朝陽(yáng)醫(yī)院2018年銷售數(shù)據(jù)分析

朝陽(yáng)醫(yī)院2018年銷售數(shù)據(jù)分析

一、提出問(wèn)題

一般來(lái)說(shuō),數(shù)據(jù)分析師拿到這個(gè)需求之后不能馬上就開始導(dǎo)入然后分析,必須在分析之前要明確自己的分析目的。數(shù)據(jù)分析只是手段,只是工具而已,能不能解決所要分析的問(wèn)題,能不能從數(shù)據(jù)中發(fā)現(xiàn)問(wèn)題,發(fā)現(xiàn)商機(jī),才是重點(diǎn)。

重要的話重復(fù)三遍:

分析之前一定要明確自己這次分析是為了什么

分析之前一定要明確自己這次分析是為了什么

分析之前一定要明確自己這次分析是為了什么

現(xiàn)在有一份朝陽(yáng)醫(yī)院2018年的銷售數(shù)據(jù),不能隨便分析,分析到什么結(jié)果算什么結(jié)果。分析之前我們要有針對(duì)性的分析目標(biāo)。

那么此次分析的目標(biāo)是:

  • 月均消費(fèi)次數(shù)
  • 月均消費(fèi)金額
  • 客單價(jià)
  • 消費(fèi)趨勢(shì)

當(dāng)我們清楚的了解自己的分析目標(biāo)之后,就可以開始分析了。

二、理解數(shù)據(jù)

理解數(shù)據(jù)是為了清洗數(shù)據(jù)做準(zhǔn)備的,如果你都不了解你手里的數(shù)據(jù)有多少,分別是什么類型,有多少缺失等,那就無(wú)法進(jìn)行清洗數(shù)據(jù)的工作,從而無(wú)法開始真正的數(shù)據(jù)分析。

# 首先加載數(shù)據(jù)分析常用庫(kù)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline
#然后導(dǎo)入數(shù)據(jù)
sales = pd.read_excel('D:/辦公/數(shù)據(jù)分析/chaoyangyiyuan9062/朝陽(yáng)醫(yī)院2018年銷售數(shù)據(jù).xlsx')
#先看一下總體數(shù)據(jù)的描述統(tǒng)計(jì)分析
sales.describe()
image.png

這里我們可以發(fā)現(xiàn)銷售數(shù)量、應(yīng)收金額、實(shí)收金額出現(xiàn)負(fù)值,這些肯定是屬于需要清洗篩選的數(shù)據(jù)了。

#再看一下數(shù)據(jù)的真實(shí)情況
sales.head()
image.png
#再看一下數(shù)據(jù)信息
sales.info()
image.png

通過(guò)以上的理解數(shù)據(jù),我們可以著手開始清洗數(shù)據(jù)了。

三、清洗數(shù)據(jù)

1、選擇子集

在我們獲取到的數(shù)據(jù)中,數(shù)據(jù)量十分龐大,但是不是每一列都是我們所需要分析的呢,不一定,那么這個(gè)時(shí)候就要選擇整個(gè)數(shù)據(jù)中合適的子集去進(jìn)行分析,這樣可以使后續(xù)的分析變得更加方便,在本次案例中,不需要選擇子集,所以可以先跳過(guò)這一步。

2、列重命名

有些數(shù)據(jù)的原始列命名對(duì)于數(shù)據(jù)分析來(lái)說(shuō)容易誤解,或者容易產(chǎn)生歧義,一不小心就理解錯(cuò)了,很不利于分析,在這個(gè)時(shí)候,就需要給列名重命名。

#把購(gòu)藥時(shí)間改成銷售時(shí)間,直接在原數(shù)據(jù)框進(jìn)行修改。
sales.rename(columns= {'購(gòu)藥時(shí)間':'銷售時(shí)間'},inplace=True)
#看一下修改后的數(shù)據(jù)
sales.head()
image.png

3、缺失數(shù)據(jù)處理

任何一個(gè)得到的數(shù)據(jù)都很有可能會(huì)有缺失值,那么對(duì)于這些缺失值一定需要處理一下,不然會(huì)干擾后來(lái)的分析結(jié)果。刪除缺失值用dropna函數(shù),代碼如下

#沒(méi)有時(shí)間和社??ㄌ?hào)的消費(fèi)數(shù)據(jù)對(duì)于本次分析是無(wú)效的,
#所以清理一下缺失值
sales = sales.dropna(subset=['銷售時(shí)間','社??ㄌ?hào)'],how='any')

4、數(shù)據(jù)類型處理

在導(dǎo)入的時(shí)候?yàn)榱朔乐褂行?shù)據(jù)導(dǎo)入不進(jìn)來(lái),所以強(qiáng)制所有數(shù)據(jù)都是object類型,但在實(shí)際分析上這樣是不可能的,所以要把需要改變類型的數(shù)據(jù)類型改變了,通過(guò)觀察,我們發(fā)現(xiàn),銷售數(shù)量,應(yīng)收金額,實(shí)收金額應(yīng)該改成float類型,銷售時(shí)間應(yīng)該清理后改成時(shí)間類型,對(duì)于改變成float類型的幾列,使用astype函數(shù),代碼如下。

這里因?yàn)榭瀑惥W(wǎng)導(dǎo)入的時(shí)候無(wú)法選擇object,所以跳過(guò)。

sales['銷售數(shù)量'] = sales['銷售數(shù)量'].astype('float64')
sales['應(yīng)收金額'] = sales['應(yīng)收金額'].astype('float64')
sales['實(shí)收金額'] = sales['實(shí)收金額'].astype('float64')

而銷售時(shí)間那一列,則需要進(jìn)行處理后才能轉(zhuǎn)換為時(shí)間類型,把銷售時(shí)間的日期和星期分開。

sales['銷售時(shí)間'], sales['銷售星期'] = sales['銷售時(shí)間'].str.split(' ', 1).str
#切分好之后,把銷售時(shí)間變?yōu)闀r(shí)間類型
sales['銷售時(shí)間'] = pd.to_datetime(sales['銷售時(shí)間'],format='%Y-%m-%d',errors='coerce')
#先看一下清洗到這個(gè)階段的數(shù)據(jù)
sales.head()
image.png

現(xiàn)在數(shù)據(jù)看起來(lái)已經(jīng)有點(diǎn)那么回事了,接下來(lái)把數(shù)據(jù)按照時(shí)間排序一下。排序之后索引會(huì)被打亂,所以也需要重置一下索引。代碼如下

#將數(shù)據(jù)按照銷售時(shí)間排序
sales = sales.sort_values('銷售時(shí)間',ascending=True)
#重置索引
sales = sales.reset_index(drop=True)
#再看一下數(shù)據(jù)
sales.head()
image.png

6、異常值處理

這里就要清洗前面理解數(shù)據(jù)時(shí)提到的負(fù)值的數(shù)據(jù)了,這些數(shù)據(jù)必須是要大于0才屬于正常數(shù)據(jù)。

從數(shù)據(jù)基本情況可以看出,銷售數(shù)量和應(yīng)收金額,實(shí)收金額,都有負(fù)的異常值,需要把這些值舍去,即選取銷售數(shù)量和應(yīng)收金額大于0的列,代碼如下

#選取銷售數(shù)量和應(yīng)收金額大于0的列
sales = sales[(sales['銷售數(shù)量'] > 0) & (sales['應(yīng)收金額'] > 0)]
#看一下目前的數(shù)據(jù)
sales.head()
image.png

做完以上幾個(gè)清洗的工作,接下來(lái)就可以開始正式的數(shù)據(jù)分析了。

四、數(shù)據(jù)分析

1 月均消費(fèi)次數(shù)

這里的月均消費(fèi)次數(shù)定義為總次數(shù)除以月份,其中假如一個(gè)人一天買了兩次藥,但只算做消費(fèi)了一次,即計(jì)算次數(shù)的時(shí)候需要進(jìn)行去重處理。

#首先對(duì)數(shù)據(jù)進(jìn)行一個(gè)去重,使用drop_duplicates函數(shù)
sales = sales.drop_duplicates(subset=['銷售時(shí)間','社保卡號(hào)'])
#去重后看一下一共有多少條數(shù)據(jù)
total = sales.shape[0]

這里可以看到去重后的數(shù)據(jù)一共5363條,相比較原始數(shù)據(jù)的6578條,已經(jīng)去除了1200多條重復(fù)數(shù)據(jù)。

#再計(jì)算月份
#用銷售時(shí)間的最大值減去最小值即可得到天數(shù),再除以(地板除)三十就可以得到月份了
month = (sales['銷售時(shí)間'].max() - sales['銷售時(shí)間'].min()).days // 30

KPI1 = total / month
print('月均消費(fèi)次數(shù)為:',KPI1)
image.png

2 月均消費(fèi)金額

同樣,月均消費(fèi)金額為總實(shí)收金額除以總月份,在計(jì)算總金額的時(shí)候不能去重,需要都計(jì)算上金額。

#計(jì)算總金額
sum_sale = sales['實(shí)收金額'].sum()

KPI2 = sum_sale / month
print('月均消費(fèi)金額為:',KPI2)
image.png

3 客單價(jià)

客單價(jià)就是總實(shí)收金額除以總消費(fèi)次數(shù)

kdj = sum_sale / total
print('客單價(jià)為:',kdj)
image.png

4 消費(fèi)趨勢(shì)

關(guān)于消費(fèi)趨勢(shì),首先我們先來(lái)看一下每天的消費(fèi)總金額的變化,把數(shù)據(jù)按天聚合,繪圖,代碼如下。

##對(duì)去重后的數(shù)據(jù)按照天進(jìn)行重新采樣
#首先要把索引變成時(shí)間
sales.index = pd.DatetimeIndex(sales['銷售時(shí)間'])
#將索引按天聚合
b = sales.resample('D').sum()
b.head()
image.png
#畫圖
plt.plot(b.index,b['實(shí)收金額'])
plt.xlabel = 'Time'
plt.ylabel = 'Money'
plt.title = '總金額消費(fèi)趨勢(shì)圖'
plt.show()
image.png

根據(jù)上圖可以看出每日消費(fèi)金額主要在1000-4000波動(dòng),波動(dòng)幅度較大,并且有幾個(gè)峰值特別高的日子。

#按月采樣
salesm = sales.resample('M').sum()
#畫圖
plt.plot(salesm.index, salesm['實(shí)收金額'])
plt.show()
image.png

這里看出該藥店的銷售總額和客流量基本成正比。二月份的客流量最少,同樣銷售業(yè)績(jī)也最差,同樣的四月份客流量最高,銷售總額也最多。

但是六月份客流量變少了,而消費(fèi)總額卻變多了,可能是因?yàn)槿司I的藥更貴了,具體原因尚且不得而知,七月份的數(shù)據(jù)如此小的原因是因?yàn)槠咴路葜唤y(tǒng)計(jì)了半個(gè)月的數(shù)據(jù),數(shù)據(jù)不全,不能拿來(lái)做比較。


image.png

通過(guò)這里,我們可以發(fā)現(xiàn),周五周六的銷售總額要顯著的的高于其他日期,即周五周六應(yīng)該前來(lái)買藥的人更多,銷售的藥品更多。

即每周的銷售趨勢(shì)是周日到周四銷售總額會(huì)有波動(dòng),但是幅度不大,周五周六的銷售總額相對(duì)較高,按月份比較的話,四月份的銷售總額顯著的高,而二月份的銷售總額顯著的低,猜測(cè)銷售總額非常低是因?yàn)榇汗?jié)的緣故。

五、反思與總結(jié)

本次數(shù)據(jù)分析過(guò)程中遇到一個(gè)問(wèn)題,耗費(fèi)了許多時(shí)間。
問(wèn)題便是在最后的兩個(gè)趨勢(shì)圖上,由于數(shù)據(jù)和題目都是科賽網(wǎng)拿到的,所以一開始在做每月消費(fèi)金額趨勢(shì)圖的時(shí)候代碼如下:

#畫圖之前的代碼全部一致
b.plot(x = b.index,y = '實(shí)收金額')
plt.xlabel = 'Time'
plt.ylabel = 'Money'
plt.title = '總金額消費(fèi)趨勢(shì)圖'
plt.show()

就是這樣的代碼,與科賽網(wǎng)的代碼一致,但是卻無(wú)法正常運(yùn)行,報(bào)錯(cuò)如下:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-90-25f586ca3e93> in <module>()
      1 #畫圖
      2 #plt.plot(b.index,b['實(shí)收金額'])
----> 3 b.plot(x = b.index,y = '實(shí)收金額',style='-')
      4 plt.xlabel = 'Time'
      5 plt.ylabel = 'Money'

D:\IT\Anaconda5\lib\site-packages\pandas\plotting\_core.py in __call__(self, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)
   2939                           fontsize=fontsize, colormap=colormap, table=table,
   2940                           yerr=yerr, xerr=xerr, secondary_y=secondary_y,
-> 2941                           sort_columns=sort_columns, **kwds)
   2942     __call__.__doc__ = plot_frame.__doc__
   2943 

D:\IT\Anaconda5\lib\site-packages\pandas\plotting\_core.py in plot_frame(data, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)
   1975                  yerr=yerr, xerr=xerr,
   1976                  secondary_y=secondary_y, sort_columns=sort_columns,
-> 1977                  **kwds)
   1978 
   1979 

D:\IT\Anaconda5\lib\site-packages\pandas\plotting\_core.py in _plot(data, x, y, subplots, ax, kind, **kwds)
   1764                 if is_integer(x) and not data.columns.holds_integer():
   1765                     x = data_cols[x]
-> 1766                 elif not isinstance(data[x], ABCSeries):
   1767                     raise ValueError("x must be a label or position")
   1768                 data = data.set_index(x)

D:\IT\Anaconda5\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
   2680         if isinstance(key, (Series, np.ndarray, Index, list)):
   2681             # either boolean or fancy integer index
-> 2682             return self._getitem_array(key)
   2683         elif isinstance(key, DataFrame):
   2684             return self._getitem_frame(key)

D:\IT\Anaconda5\lib\site-packages\pandas\core\frame.py in _getitem_array(self, key)
   2724             return self._take(indexer, axis=0)
   2725         else:
-> 2726             indexer = self.loc._convert_to_indexer(key, axis=1)
   2727             return self._take(indexer, axis=1)
   2728 

D:\IT\Anaconda5\lib\site-packages\pandas\core\indexing.py in _convert_to_indexer(self, obj, axis, is_setter)
   1325                 if mask.any():
   1326                     raise KeyError('{mask} not in index'
-> 1327                                    .format(mask=objarr[mask]))
   1328 
   1329                 return com._values_from_object(indexer)

KeyError: "DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',\n               '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08',\n               '2018-01-09', '2018-01-10',\n               ...\n               '2018-07-10', '2018-07-11', '2018-07-12', '2018-07-13',\n               '2018-07-14', '2018-07-15', '2018-07-16', '2018-07-17',\n               '2018-07-18', '2018-07-19'],\n              dtype='datetime64[ns]', name='銷售時(shí)間', length=200, freq=None) not in index"

可以說(shuō)我為了解決這個(gè)問(wèn)題耗費(fèi)了小半天的時(shí)間,因?yàn)榭瀑惥W(wǎng)的源代碼我復(fù)制了一遍運(yùn)行也是出錯(cuò)的,所以個(gè)人估計(jì)是matplotlib庫(kù)的版本問(wèn)題?具體原因我也不是很確定。

在百度搜了很久沒(méi)有相關(guān)結(jié)果,后來(lái)還是在stackoverflow找到了嘗試的代碼。


image.png

這才有了第四部分的正確代碼和趨勢(shì)圖。

另外還有一點(diǎn)就是科賽網(wǎng)的最后兩個(gè)趨勢(shì)圖個(gè)人覺得選取的數(shù)據(jù)不對(duì),因?yàn)樵创a對(duì)日期重采樣之后不是以sum計(jì)算的而是以count計(jì)算的。代碼如下:

##對(duì)去重后的數(shù)據(jù)按照天進(jìn)行重新采樣
#首先要把索引變成時(shí)間
sales.index = pd.DatetimeIndex(sales['銷售時(shí)間'])
#然后對(duì)其按照每天從新采樣
salesd = sales.resample('D').count()

#畫圖
salesd.plot(x = salesd.index, y = '實(shí)收金額')
plt.xlabel('Time')
plt.ylabel('Money')
plt.title('xiao shou shu ju')
plt.show()

對(duì)此我特意將代碼改成count然后把數(shù)據(jù)展開查看


image.png

所以按照代碼來(lái)看,源代碼畫圖的數(shù)據(jù)是X為索引-銷售時(shí)間,y為實(shí)收金額,但是怎么看這樣的實(shí)收金額都不會(huì)是一天的實(shí)收金額。因?yàn)閷?shí)際上數(shù)字21是2018年1月1日銷售了21單,而實(shí)際的實(shí)收金額則需要重采樣之后按照sum來(lái)計(jì)算。

后面兩個(gè)趨勢(shì)圖都是這樣的情況,就趨勢(shì)圖來(lái)說(shuō)我相信自己這種做法才是正確的。

但是對(duì)于畫圖的plot()的代碼我還是只知其然不知其所以然,希望有大佬能夠指點(diǎn)迷津。

以上。
謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 項(xiàng)目名稱:CD用戶消費(fèi)行為分析 數(shù)據(jù)來(lái)源:網(wǎng)上下載數(shù)據(jù)CDNow網(wǎng)站的用戶購(gòu)買明細(xì)CDNOW_master.txt...
    e10be475c3fa閱讀 414評(píng)論 0 0
  • 這是一本通俗易懂,但是很經(jīng)典的書。 一:財(cái)務(wù)分析總體方法 老唐說(shuō)企業(yè)財(cái)務(wù)分析四步走:首先,瀏覽資產(chǎn)負(fù)債表和利潤(rùn)表各...
    ForeverXiaofeng閱讀 1,714評(píng)論 0 2
  • 一、“人是沒(méi)辦法管理時(shí)間的,時(shí)間也不聽從任何人的安排”? 當(dāng)我看到“人是沒(méi)辦法管理時(shí)間的,時(shí)間也不聽從任何人的管理...
    采蘑菇的小Timor閱讀 395評(píng)論 0 0
  • 今天練習(xí)可以殺人的兩根弦,我好喜歡 這個(gè)了不起看到12歲的孩子的堅(jiān)持我練琴何嘗不是
    每個(gè)人的孟母堂閱讀 390評(píng)論 0 2
  • 晚宴是在別墅的背面進(jìn)行,草坪很大,修剪的也很整齊,太陽(yáng)已經(jīng)快看不到了,不過(guò),餐桌上的燭光,樹上纏繞著的燈光,卻又有...
    玉折蘭摧閱讀 740評(píng)論 0 48

友情鏈接更多精彩內(nèi)容