利用pandas进行简单数据分析:医院销售数据分析案例

本篇文章中,假设以朝阳医院2018年销售数据为例,目的是了解朝阳医院在2018年里的销售情况。

利用pandas进行简单数据分析:医院销售数据分析案例

1、数据分析的目的

数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。

本篇文章中,假设以朝阳医院2018年销售数据为例,目的是了解朝阳医院在2018年里的销售情况,这就需要知道几个业务指标,例如:月均消费次数,月均消费金额、客单价以及消费趋势。

2、数据分析基本过程

数据分析基本过程包括:获取数据、数据清洗、构建模型、数据可视化以及消费趋势。

2.1 获取数据

Excel中的数据部分截图:

利用pandas进行简单数据分析:医院销售数据分析案例
  • 先导入包,然后读取文件,读取的时候用object读取,防止有些数据读不了:
In [1]: import pandas as pd

In [2]: # 读取数据(最好使用 object 类型读取) ...: data = pd.read_excel("朝阳医院2018年销售数据.xlsx", dtype="object")

In [3]: # 修改为 DataFrame 格式 ...: dataDF = pd.DataFrame(data)

In [4]: dataDF.head()Out[4]: 购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 星期五 001616528 236701 强力VC银翘片 6 82.8 691 2018-01-02 星期六 001616528 236701 清热解毒口服液 1 28 24.642 2018-01-06 星期三 0012602828 236701 感康 2 16.8 153 2018-01-11 星期一 0010070343428 236701 三九感冒灵 1 28 284 2018-01-15 星期五 00101554328 236701 三九感冒灵 8 224 208
  • 查看这些基本信息
In [5]: # 查看数据的形状,即几行几列   ...: dataDF.shapeOut[5]: (6578, 7)

In [6]: # 查看索引 ...: dataDF.indexOut[6]: RangeIndex(start=0, stop=6578, step=1)

In [7]: # 查看每一列的列表头内容 ...: dataDF.columnsOut[7]: Index(['购药时间', '社保卡号', '商品编码', '商品名称', '销售数量', '应收金额', '实收金额'], dtype='object')

In [8]: # 查看每一列数据统计数目 ...: dataDF.count()Out[8]: 购药时间 6576社保卡号 6576商品编码 6577商品名称 6577销售数量 6577应收金额 6577实收金额 6577dtype: int64

总共有6578行7列数据,但是“购药时间”和“社保卡号”这两列只有6576个数据,而“商品编码”到“实收金额”这些列都是只有6577个数据,这就意味着数据中存在缺失值,可以推断出数据中存在一行缺失值,此外“购药时间”和“社保卡号”这两列都各自存在一个缺失数据,这些缺失数据在后面步骤中需要进一步处理。

2.2 数据清洗

数据清洗过程包括:选择子集、列名重命名、缺失数据处理、数据类型转换、数据排序及异常值处理

2.2.1 选择子集

在我们获取到的数据中,可能数据量非常庞大,并不是每一列都有价值都需要分析,这时候就需要从整个数据中选取合适的子集进行分析,这样能从数据中获取最大价值。在本次案例中不需要选取子集,暂时可以忽略这一步。

2.2.2 列名重命名

在数据分析过程中,有些列名和数据容易混淆或产生歧义,不利于数据分析,这时候需要把列名换成容易理解的名称,可以采用rename函数实现:

In [9]: # 使用 rename 函数,把"购药时间" 改为 "销售时间"   ...: dataDF.rename(columns={"购药时间": "销售时间"}, inplace=True)   ...: dataDF.columnsOut[9]: Index(['销售时间', '社保卡号', '商品编码', '商品名称', '销售数量', '应收金额', '实收金额'], dtype='object')

2.2.3 缺失数据处理

获取的数据中很有可能存在缺失值,通过查看基本信息可以推测“购药时间”和“社保卡号”这两列存在缺失值,如果不处理这些缺失值会干扰后面的数据分析结果。缺失数据常用的处理方式为删除含有缺失数据的记录或者利用算法去补全缺失数据。在本次案例中为求方便,直接使用dropna函数删除缺失数据,具体如下:

In [10]: # 删除缺失值之前    ...: dataDF.shapeOut[10]: (6578, 7)

In [11]: # 使用dropna函数删除缺失值 ...: dataDF = dataDF.dropna()

In [12]: # 删除缺失值之后 ...: dataDF.shapeOut[12]: (6575, 7)

2.2.4 数据类型转换

在导入数据时为了防止导入不进来,会强制所有数据都是object类型,但实际数据分析过程中“销售数量”,“应收金额”,“实收金额”,这些列需要浮点型(float)数据,“销售时间”需要改成时间格式,因此需要对数据类型进行转换。

可以使用astype()函数转为浮点型数据:

In [13]: # 将字符串转为浮点型数据    ...: dataDF["销售数量"] = dataDF["销售数量"].astype("f8")    ...: dataDF["应收金额"] = dataDF["应收金额"].astype("f8")    ...: dataDF["实收金额"] = dataDF["实收金额"].astype("f8")    ...: dataDF.dtypesOut[13]: 销售时间     object社保卡号     object商品编码     object商品名称     object销售数量    float64应收金额    float64实收金额    float64dtype: object

在“销售时间”这一列数据中存在星期这样的数据,但在数据分析过程中不需要用到,因此要把销售时间列中日期和星期使用split函数进行分割,分割后的时间,返回的是Series数据类型:

In [15]: # 定义函数将星期去除    ...: def splitsaletime(timeColser):    ...:     timelist = []    ...:     for t in timeColser:    ...:         timelist.append(t.split(" ")[0])  # [0]表示选取的分片,这里表示切割完后选取第一个分片    ...:     timeser = pd.Series(timelist)  # 将列表转行为一维数据Series类型    ...:     return timeser    ...: 

In [16]: # 获取"销售时间"这一列数据 ...: t = dataDF.loc[:, "销售时间"] ...: # 调用函数去除星期,获取日期 ...: timeser = splitsaletime(t) ...: # 修改"销售时间"这一列日期 ...: dataDF.loc[:, "销售时间"] = timeser ...: dataDF.head()Out[16]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.001 2018-01-02 001616528 236701 清热解毒口服液 1.0 28.0 24.642 2018-01-06 0012602828 236701 感康 2.0 16.8 15.003 2018-01-11 0010070343428 236701 三九感冒灵 1.0 28.0 28.004  2018-01-15    00101554328  236701    三九感冒灵   8.0  224.0  208.00

接着把切割后的日期转为时间格式,方便后面的数据统计:

In [17]: # 字符串转日期    ...: # errors='coerce'如果原始数据不符合日期的格式,转换后的值为NaT    ...: dataDF.loc[:, "销售时间"] = pd.to_datetime(dataDF.loc[:, "销售时间"], errors='coerce')    ...: dataDF.dtypesOut[17]: 销售时间    datetime64[ns]社保卡号            object商品编码            object商品名称            object销售数量           float64应收金额           float64实收金额           float64dtype: object
In [18]: # 转换日期过程中不符合日期格式的数值会被转换为空值None,
...: # 这里删除为空的行 ...: dataDF = dataDF.dropna() ...: dataDF.shapeOut[18]: (6549, 7)

2.2.5 数据排序

此时时间是没有按顺序排列的,所以还是需要排序一下,排序之后索引会被打乱,所以也需要重置一下索引。其中by:表示按哪一列进行排序,ascending=True表示升序排列,ascending=False表示降序排列:

In [19]: # 按销售时间进行升序排序    ...: dataDF = dataDF.sort_values(by='销售时间', ascending=True)    ...: dataDF.head()Out[19]:            销售时间           社保卡号    商品编码          商品名称  销售数量   应收金额   实收金额0    2018-01-01      001616528  236701       强力VC银翘片   6.0   82.8   69.03436 2018-01-01     0010616728  865099    硝苯地平片(心痛定)   2.0    3.4    3.01190 2018-01-01  0010073966328  861409  非洛地平缓释片(波依定)   5.0  162.5  145.03859 2018-01-01  0010073966328  866634   硝苯地平控释片(欣然)   6.0  111.0   92.53888 2018-01-01  0010014289328  866851   缬沙坦分散片(易达乐)   1.0   26.0   23.0

In [20]: # 重置索引(index) ...: dataDF = dataDF.reset_index(drop=True) ...: dataDF.head()Out[20]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.01 2018-01-01 0010616728 865099 硝苯地平片(心痛定) 2.0 3.4 3.02 2018-01-01 0010073966328 861409 非洛地平缓释片(波依定) 5.0 162.5 145.03 2018-01-01 0010073966328 866634 硝苯地平控释片(欣然) 6.0 111.0 92.54 2018-01-01 0010014289328 866851 缬沙坦分散片(易达乐) 1.0 26.0 23.0

2.2.6 异常值处理

先查看数据的描述统计信息:

In [21]: # 查看描述统计信息    ...: dataDF.describe()Out[21]:               销售数量         应收金额         实收金额count  6549.000000  6549.000000  6549.000000mean      2.384486    50.449076    46.284370std       2.375227    87.696401    81.058426min     -10.000000  -374.000000  -374.00000025%       1.000000    14.000000    12.32000050%       2.000000    28.000000    26.50000075%       2.000000    59.600000    53.000000max      50.000000  2950.000000  2650.000000

通过描述统计信息可以看到,“销售数量”、“应收金额”、“实收金额”这三列数据的最小值出现了负数,这明显不符合常理,数据中存在异常值的干扰,因此要对数据进一步处理,以排除异常值的影响:

In [22]: # 将"销售数量"这一列中小于0的数排除掉    ...: pop = dataDF.loc[:, "销售数量"] > 0    ...: dataDF = dataDF.loc[pop, :]

In [23]: # 排除异常值后再次查看描述统计信息 ...: dataDF.describe()Out[23]: 销售数量 应收金额 实收金额count 6506.000000 6506.000000 6506.000000mean 2.405626 50.927897 46.727653std 2.364565 87.650282 80.997726min 1.000000 1.200000 0.03000025% 1.000000 14.000000 12.60000050% 2.000000 28.000000 27.00000075% 2.000000 59.600000 53.000000max 50.000000 2950.000000 2650.000000

2.3 构建模型及数据可视化

数据清洗完成后,需要利用数据构建模型(就是计算相应的业务指标),并用可视化的方式呈现结果。

2.3.1 业务指标1:月均消费次数

月均消费次数 = 总消费次数 / 月份数

利用pandas进行简单数据分析:医院销售数据分析案例

①计算总消费次数:

In [24]: # 删除重复数据    ...: kpi1_Df = dataDF.drop_duplicates(subset=['销售时间', '社保卡号'])

In [25]: # 删除重复数据 ...: kpi1_Df = dataDF.drop_duplicates(subset=['销售时间', '社保卡号'])

In [26]: # 有多少行 ...: totall = kpi1_Df.shape[0] ...: print('总消费次数:', totall)总消费次数:5342

②计算月份数:

In [27]: # 按销售时间升序排序    ...: kpi1_Df = kpi1_Df.sort_values(by='销售时间', ascending=True)

In [28]: # 重命名行名(index) ...: kpi1_Df = kpi1_Df.reset_index(drop=True)

In [29]: # 获取时间范围 ...: # 最小时间值 ...: startTime = kpi1_Df.loc[0, '销售时间'] ...: # 最大时间值 ...: endTime = kpi1_Df.loc[totall - 1, '销售时间']

In [30]: # 计算天数 ...: daysI = (endTime - startTime).days

In [31]: # 月份数:运算符"//"表示取整除,返回商的整数部分 ...: monthsI = daysI // 30 ...: print('月份数:', monthsI)月份数:6

③计算月均消费次数:

In [32]: # 计算月均消费次数    ...: kpi1_I = totall // monthsI    ...: print('业务指标1:月均消费次数=', kpi1_I)业务指标1:月均消费次数= 890

2.3.2 业务指标2:月均消费金额

月均消费金额 = 总消费金额 / 月份数

In [33]: # 总消费金额    ...: totalMoneyF = dataDF.loc[:, '实收金额'].sum()

In [34]: # 月均消费金额 ...: monthMoneyF = totalMoneyF / monthsI ...: print('业务指标2:月均消费金额=', monthMoneyF)业务指标2:月均消费金额= 50668.35166666666

2.3.3 业务指标3:客单价

客单价 = 总消费金额 / 总消费次数

In [35]: # 客单价 = 总消费金额 / 总消费次数    ...: pct = totalMoneyF / totall    ...: print('业务指标3:客单价=', pct)业务指标3:客单价= 56.909417821040805

2.3.4 业务指标4:消费趋势

先导入相关的包:

In [36]: import matplotlib.pyplot as plt    ...:     ...: # 画图时用于显示中文字符    ...: from pylab import mpl    ...: mpl.rcParams['font.sans-serif'] = ['SimHei']   # SimHei是黑体的意思

In [37]: # 在操作之前先复制一份数据,防止影响清洗后的数据 ...: groupDf = dataDF

①分析每天的消费金额

In [38]: # 重命名行(index)为销售时间所在列的值    ...: groupDf.index = groupDf['销售时间']    ...: groupDf.head()Out[38]:                  销售时间           社保卡号    商品编码          商品名称  销售数量   应收金额   实收金额销售时间2018-01-01 2018-01-01      001616528  236701       强力VC银翘片   6.0   82.8   69.02018-01-01 2018-01-01     0010616728  865099    硝苯地平片(心痛定)   2.0    3.4    3.02018-01-01 2018-01-01  0010073966328  861409  非洛地平缓释片(波依定)   5.0  162.5  145.02018-01-01 2018-01-01  0010073966328  866634   硝苯地平控释片(欣然)   6.0  111.0   92.52018-01-01 2018-01-01  0010014289328  866851   缬沙坦分散片(易达乐)   1.0   26.0   23.0
In [39]: # 画图
...: plt.plot(groupDf['实收金额']) ...: plt.title('按天消费金额图') ...: plt.xlabel('时间') ...: plt.ylabel('实收金额')Out[39]: <matplotlib.text.Text at 0xe16a278>

In [40]: # 保存图片 ...: plt.savefig('./day.png') ...: # 显示图片 ...: plt.show()
利用pandas进行简单数据分析:医院销售数据分析案例

从结果可以看出,每天消费总额差异较大,除了个别天出现比较大笔的消费,大部分人消费情况维持在500元以内。

②分析每月的消费金额

接下来,我销售时间先聚合再按月分组进行分析:

In [41]: # 将销售时间聚合按月分组    ...: gb = groupDf.groupby(groupDf.index.month)    ...: gbOut[41]: <pandas.core.groupby.DataFrameGroupBy object at 0x000000000E184B38>

In [42]: # 应用函数,计算每个月的消费总额 ...: monthDf = gb.sum() ...: monthDfOut[42]: 销售数量 应收金额 实收金额销售时间1 2527.0 53561.6 49461.192 1858.0 42028.8 38790.383 2225.0 45318.0 41597.514 3005.0 54296.3 48787.845 2225.0 51263.4 46925.276 2328.0 52300.8 48327.707 1483.0 32568.0 30120.22

In [43]: # 描绘按月消费金额图 ...: plt.plot(monthDf['实收金额']) ...: plt.title('按月消费金额图') ...: plt.xlabel('月份') ...: plt.ylabel('实收金额')Out[43]: <matplotlib.text.Text at 0xe81d400>

In [44]: # 保存图片 ...: plt.savefig('./month.png') ...: # 显示图片 ...: plt.show()
利用pandas进行简单数据分析:医院销售数据分析案例

结果显示,7月消费金额最少,这是因为7月份的数据不完整,所以不具参考价值。

1月、4月、5月和6月的月消费金额差异不大,2月和3月的消费金额迅速降低,这可能是2月和3月处于春节期间,大部分人都回家过年的原因。

③分析药品销售情况

对“商品名称”和“销售数量”这两列数据进行聚合为Series形式,方便后面统计,并按降序排序:

In [45]: # 聚合统计各种药品的销售数量    ...: medicine = groupDf[['商品名称','销售数量']]    ...: bk = medicine.groupby('商品名称')[['销售数量']]    ...: re_medicine = bk.sum()

In [46]: # 对药品销售数量按降序排序 ...: re_medicine = re_medicine.sort_values(by='销售数量',ascending=False) ...: re_medicine.head()Out[46]: 销售数量商品名称苯磺酸氨氯地平片(安内真) 1781.0开博通 1440.0酒石酸美托洛尔片(倍他乐克) 1140.0硝苯地平片(心痛定) 825.0苯磺酸氨氯地平片(络活喜) 796.0

截取销售数量最多的前十种药品,并用条形图展示结果:

In [47]: # 截取销售数量最多的十种药品    ...: top_medicine = re_medicine.iloc[:10,:]    ...: top_medicineOut[47]:                      销售数量商品名称苯磺酸氨氯地平片(安内真)      1781.0开博通                1440.0酒石酸美托洛尔片(倍他乐克)     1140.0硝苯地平片(心痛定)          825.0苯磺酸氨氯地平片(络活喜)       796.0复方利血平片(复方降压片)       515.0G琥珀酸美托洛尔缓释片(倍他乐克)   509.0缬沙坦胶囊(代文)           445.0非洛地平缓释片(波依定)        375.0高特灵                 366.0

In [48]: # 用条形图展示销售数量前十的药品 ...: top_medicine.plot(kind='bar') ...: plt.title('药品销售前十情况') ...: plt.xlabel('药品种类') ...: plt.ylabel('销售数量') ...: plt.legend(loc=0)Out[48]: <matplotlib.legend.Legend at 0xe456cf8>

In [49]: # 保存图片 ...: plt.savefig('./medicine.png') ...: # 显示图片 ...: plt.show()
利用pandas进行简单数据分析:医院销售数据分析案例

得到销售数量最多的前十种药品信息,这些信息将会有助于加强医院对药房的管理。
3、代码汇总

In [1]: import pandas as pd

In [2]: # 读取数据(最好使用 object 类型读取) ...: data = pd.read_excel("朝阳医院2018年销售数据.xlsx", dtype="object")

In [3]: # 修改为 DataFrame 格式 ...: dataDF = pd.DataFrame(data)

In [4]: dataDF.head()Out[4]: 购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 星期五 001616528 236701 强力VC银翘片 6 82.8 691 2018-01-02 星期六 001616528 236701 清热解毒口服液 1 28 24.642 2018-01-06 星期三 0012602828 236701 感康 2 16.8 153 2018-01-11 星期一 0010070343428 236701 三九感冒灵 1 28 284 2018-01-15 星期五 00101554328 236701 三九感冒灵 8 224 208

In [5]: # 查看数据的形状,即几行几列 ...: dataDF.shapeOut[5]: (6578, 7)

In [6]: # 查看索引 ...: dataDF.indexOut[6]: RangeIndex(start=0, stop=6578, step=1)

In [7]: # 查看每一列的列表头内容 ...: dataDF.columnsOut[7]: Index(['购药时间', '社保卡号', '商品编码', '商品名称', '销售数量', '应收金额', '实收金额'], dtype='object')

In [8]: # 查看每一列数据统计数目 ...: dataDF.count()Out[8]: 购药时间 6576社保卡号 6576商品编码 6577商品名称 6577销售数量 6577应收金额 6577实收金额 6577dtype: int64

In [9]: # 使用 rename 函数,把"购药时间" 改为 "销售时间" ...: dataDF.rename(columns={"购药时间": "销售时间"}, inplace=True) ...: dataDF.columnsOut[9]: Index(['销售时间', '社保卡号', '商品编码', '商品名称', '销售数量', '应收金额', '实收金额'], dtype='object')

In [10]: # 删除缺失值之前 ...: dataDF.shapeOut[10]: (6578, 7)

In [11]: # 使用dropna函数删除缺失值 ...: dataDF = dataDF.dropna()

In [12]: # 删除缺失值之后 ...: dataDF.shapeOut[12]: (6575, 7)

In [13]: # 将字符串转为浮点型数据 ...: dataDF["销售数量"] = dataDF["销售数量"].astype("f8") ...: dataDF["应收金额"] = dataDF["应收金额"].astype("f8") ...: dataDF["实收金额"] = dataDF["实收金额"].astype("f8") ...: dataDF.dtypesOut[13]: 销售时间 object社保卡号 object商品编码 object商品名称 object销售数量 float64应收金额 float64实收金额 float64dtype: object

...: def splitsaletime(timeColser): ...: timelist = [] ...: for t in timeColser: ...: # [0]表示选取的分片,这里表示切割完后选取第一个分片 ...: timelist.append(t.split(" ")[0]) ...: # 将列表转行为一维数据Series类型 ...: timeser = pd.Series(timelist) ...: return timeser ...:

In [15]: # 定义函数将星期去除 ...: def splitsaletime(timeColser): ...: timelist = [] ...: for t in timeColser: ...: timelist.append(t.split(" ")[0]) # [0]表示选取的分片,这里表示切割完后选取第一个分片 ...: timeser = pd.Series(timelist) # 将列表转行为一维数据Series类型 ...: return timeser ...:

In [16]: # 获取"销售时间"这一列数据 ...: t = dataDF.loc[:, "销售时间"] ...: # 调用函数去除星期,获取日期 ...: timeser = splitsaletime(t) ...: # 修改"销售时间"这一列日期 ...: dataDF.loc[:, "销售时间"] = timeser ...: dataDF.head()Out[16]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.001 2018-01-02 001616528 236701 清热解毒口服液 1.0 28.0 24.642 2018-01-06 0012602828 236701 感康 2.0 16.8 15.003 2018-01-11 0010070343428 236701 三九感冒灵 1.0 28.0 28.004 2018-01-15 00101554328 236701 三九感冒灵 8.0 224.0 208.00

In [17]: # 字符串转日期 ...: # errors='coerce'如果原始数据不符合日期的格式,转换后的值为NaT ...: dataDF.loc[:, "销售时间"] = pd.to_datetime(dataDF.loc[:, "销售时间"], errors='coerce') ...: dataDF.dtypesOut[17]: 销售时间 datetime64[ns]社保卡号 object商品编码 object商品名称 object销售数量 float64应收金额 float64实收金额 float64dtype: object

In [18]: # 转换日期过程中不符合日期格式的数值会被转换为空值None, ...: # 这里删除为空的行 ...: dataDF = dataDF.dropna() ...: dataDF.shapeOut[18]: (6549, 7)

In [19]: # 按销售时间进行升序排序 ...: dataDF = dataDF.sort_values(by='销售时间', ascending=True) ...: dataDF.head()Out[19]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.03436 2018-01-01 0010616728 865099 硝苯地平片(心痛定) 2.0 3.4 3.01190 2018-01-01 0010073966328 861409 非洛地平缓释片(波依定) 5.0 162.5 145.03859 2018-01-01 0010073966328 866634 硝苯地平控释片(欣然) 6.0 111.0 92.53888 2018-01-01 0010014289328 866851 缬沙坦分散片(易达乐) 1.0 26.0 23.0

In [20]: # 重置索引(index) ...: dataDF = dataDF.reset_index(drop=True) ...: dataDF.head()Out[20]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额0 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.01 2018-01-01 0010616728 865099 硝苯地平片(心痛定) 2.0 3.4 3.02 2018-01-01 0010073966328 861409 非洛地平缓释片(波依定) 5.0 162.5 145.03 2018-01-01 0010073966328 866634 硝苯地平控释片(欣然) 6.0 111.0 92.54 2018-01-01 0010014289328 866851 缬沙坦分散片(易达乐) 1.0 26.0 23.0

In [21]: # 查看描述统计信息 ...: dataDF.describe()Out[21]: 销售数量 应收金额 实收金额count 6549.000000 6549.000000 6549.000000mean 2.384486 50.449076 46.284370std 2.375227 87.696401 81.058426min -10.000000 -374.000000 -374.00000025% 1.000000 14.000000 12.32000050% 2.000000 28.000000 26.50000075% 2.000000 59.600000 53.000000max 50.000000 2950.000000 2650.000000

In [22]: # 将"销售数量"这一列中小于0的数排除掉 ...: pop = dataDF.loc[:, "销售数量"] > 0 ...: dataDF = dataDF.loc[pop, :]

In [23]: # 排除异常值后再次查看描述统计信息 ...: dataDF.describe()Out[23]: 销售数量 应收金额 实收金额count 6506.000000 6506.000000 6506.000000mean 2.405626 50.927897 46.727653std 2.364565 87.650282 80.997726min 1.000000 1.200000 0.03000025% 1.000000 14.000000 12.60000050% 2.000000 28.000000 27.00000075% 2.000000 59.600000 53.000000max 50.000000 2950.000000 2650.000000

In [24]: # 计算总消费次数 ...: # 删除重复数据 ...: kpi1_Df = dataDF.drop_duplicates(subset=['销售时间', '社保卡号'])

In [25]: # 删除重复数据 ...: kpi1_Df = dataDF.drop_duplicates(subset=['销售时间', '社保卡号'])

In [26]: # 有多少行 ...: totall = kpi1_Df.shape[0] ...: print('总消费次数:', totall)总消费次数:5342

In [27]: # 按销售时间升序排序 ...: kpi1_Df = kpi1_Df.sort_values(by='销售时间', ascending=True)

In [28]: # 重命名行名(index) ...: kpi1_Df = kpi1_Df.reset_index(drop=True)

In [29]: # 获取时间范围 ...: # 最小时间值 ...: startTime = kpi1_Df.loc[0, '销售时间'] ...: # 最大时间值 ...: endTime = kpi1_Df.loc[totall - 1, '销售时间']

In [30]: # 计算天数 ...: daysI = (endTime - startTime).days

In [31]: # 月份数:运算符"//"表示取整除,返回商的整数部分 ...: monthsI = daysI // 30 ...: print('月份数:', monthsI)月份数:6

In [32]: # 计算月均消费次数 ...: kpi1_I = totall // monthsI ...: print('业务指标1:月均消费次数=', kpi1_I)业务指标1:月均消费次数= 890

In [33]: # 总消费金额 ...: totalMoneyF = dataDF.loc[:, '实收金额'].sum()

In [34]: # 月均消费金额 ...: monthMoneyF = totalMoneyF / monthsI ...: print('业务指标2:月均消费金额=', monthMoneyF)业务指标2:月均消费金额= 50668.35166666666

In [35]: # 客单价 = 总消费金额 / 总消费次数 ...: pct = totalMoneyF / totall ...: print('业务指标3:客单价=', pct)业务指标3:客单价= 56.909417821040805

In [36]: import matplotlib.pyplot as plt ...: ...: # 画图时用于显示中文字符 ...: from pylab import mpl ...: mpl.rcParams['font.sans-serif'] = ['SimHei'] # SimHei是黑体的意思

In [37]: # 在操作之前先复制一份数据,防止影响清洗后的数据 ...: groupDf = dataDF

In [38]: # 重命名行(index)为销售时间所在列的值 ...: groupDf.index = groupDf['销售时间'] ...: groupDf.head()Out[38]: 销售时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额销售时间2018-01-01 2018-01-01 001616528 236701 强力VC银翘片 6.0 82.8 69.02018-01-01 2018-01-01 0010616728 865099 硝苯地平片(心痛定) 2.0 3.4 3.02018-01-01 2018-01-01 0010073966328 861409 非洛地平缓释片(波依定) 5.0 162.5 145.02018-01-01 2018-01-01 0010073966328 866634 硝苯地平控释片(欣然) 6.0 111.0 92.52018-01-01 2018-01-01 0010014289328 866851 缬沙坦分散片(易达乐) 1.0 26.0 23.0

In [39]: # 画图 ...: plt.plot(groupDf['实收金额']) ...: plt.title('按天消费金额图') ...: plt.xlabel('时间') ...: plt.ylabel('实收金额')Out[39]: <matplotlib.text.Text at 0xe16a278>

In [40]: # 保存图片 ...: plt.savefig('./day.png') ...: # 显示图片 ...: plt.show()

In [41]: # 将销售时间聚合按月分组 ...: gb = groupDf.groupby(groupDf.index.month) ...: gbOut[41]: <pandas.core.groupby.DataFrameGroupBy object at 0x000000000E184B38>

In [42]: # 应用函数,计算每个月的消费总额 ...: monthDf = gb.sum() ...: monthDfOut[42]: 销售数量 应收金额 实收金额销售时间1 2527.0 53561.6 49461.192 1858.0 42028.8 38790.383 2225.0 45318.0 41597.514 3005.0 54296.3 48787.845 2225.0 51263.4 46925.276 2328.0 52300.8 48327.707 1483.0 32568.0 30120.22

In [43]: # 描绘按月消费金额图 ...: plt.plot(monthDf['实收金额']) ...: plt.title('按月消费金额图') ...: plt.xlabel('月份') ...: plt.ylabel('实收金额')Out[43]: <matplotlib.text.Text at 0xe81d400>

In [44]: # 保存图片 ...: plt.savefig('./month.png') ...: # 显示图片 ...: plt.show()

In [45]: # 聚合统计各种药品的销售数量 ...: medicine = groupDf[['商品名称','销售数量']] ...: bk = medicine.groupby('商品名称')[['销售数量']] ...: re_medicine = bk.sum()

In [46]: # 对药品销售数量按降序排序 ...: re_medicine = re_medicine.sort_values(by='销售数量',ascending=False) ...: re_medicine.head()Out[46]: 销售数量商品名称苯磺酸氨氯地平片(安内真) 1781.0开博通 1440.0酒石酸美托洛尔片(倍他乐克) 1140.0硝苯地平片(心痛定) 825.0苯磺酸氨氯地平片(络活喜) 796.0

In [47]: # 截取销售数量最多的十种药品 ...: top_medicine = re_medicine.iloc[:10,:] ...: top_medicineOut[47]: 销售数量商品名称苯磺酸氨氯地平片(安内真) 1781.0开博通 1440.0酒石酸美托洛尔片(倍他乐克) 1140.0硝苯地平片(心痛定) 825.0苯磺酸氨氯地平片(络活喜) 796.0复方利血平片(复方降压片) 515.0G琥珀酸美托洛尔缓释片(倍他乐克) 509.0缬沙坦胶囊(代文) 445.0非洛地平缓释片(波依定) 375.0高特灵 366.0

In [48]: # 用条形图展示销售数量前十的药品 ...: top_medicine.plot(kind='bar') ...: plt.title('药品销售前十情况') ...: plt.xlabel('药品种类') ...: plt.ylabel('销售数量') ...: plt.legend(loc=0)Out[48]: <matplotlib.legend.Legend at 0xe456cf8>

In [49]: # 保存图片 ...: plt.savefig('./medicine.png') ...: # 显示图片 ...: plt.show()

来源:CSDN

作者:梦因you而美

链接:https://blog.csdn.net/apollo_miracle/article/details/88550078

本文采用「CC BY-SA 4.0 CN」协议转载自互联网、仅供学习交流,内容版权归原作者所有,如涉作品、版权和其他问题请给「我们」留言处理。

(5)
上一篇 2019-10-27 22:00
下一篇 2019-11-05 00:08

相关文章

关注我们
关注我们
分享本页
返回顶部