数据分析项目补充:医院药品销售数据分析
北京朝阳医院2018年销售数据分析项目
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime
import calendar
# 在matplotlib模块绘图时如果是中文标题的话可能会出现显示不正常的情况,这种问题可以通过添加下面两行代码来解决这种问题
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
#利用pandas库的read_excel读取xlsx文件
data = pd.read_excel(r'C:\Users\Administrator\Documents\Tencent Files\3189374495\FileRecv\朝阳医院2018年销售数据.xlsx')
data.head()#查看开头的数据,括号中可以输入显示几行也可以不写
运行结果:
购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额
0 2018-01-01 星期五 1.616528e+06 236701.0 强力VC银翘片 6.0 82.8 69.00
1 2018-01-02 星期六 1.616528e+06 236701.0 清热解毒口服液 1.0 28.0 24.64
2 2018-01-06 星期三 1.260283e+07 236701.0 感康 2.0 16.8 15.00
3 2018-01-11 星期一 1.007034e+10 236701.0 三九感冒灵 1.0 28.0 28.00
4 2018-01-15 星期五 1.015543e+08 236701.0 三九感冒灵 8.0 224.0 208.00
data.info()#info查看数据类型
运行结果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6578 entries, 0 to 6577
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 购药时间 6576 non-null object
1 社保卡号 6576 non-null float64
2 商品编码 6577 non-null float64
3 商品名称 6577 non-null object
4 销售数量 6577 non-null float64
5 应收金额 6577 non-null float64
6 实收金额 6577 non-null float64
dtypes: float64(5), object(2)
memory usage: 359.9+ KB
data.shape#shape查看有多少行多少列,前面是行数,后者是列数
运行结果:
(6578,7)
data.isnull().sum()#isnull()查看是否有空值,加sum()求空值数量
运行结果:
购药时间 2
社保卡号 2
商品编码 1
商品名称 1
销售数量 1
应收金额 1
实收金额 1
dtype: int64
data = data.dropna(subset=['社保卡号'],how='any')#dropna用于删除空值操作,一般不会这么使用除非数据量很大不在乎这么一点,一般用填充解决
data.info()
运行结果:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 6576 entries, 0 to 6577
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 购药时间 6575 non-null object
1 社保卡号 6576 non-null float64
2 商品编码 6576 non-null float64
3 商品名称 6576 non-null object
4 销售数量 6576 non-null float64
5 应收金额 6576 non-null float64
6 实收金额 6576 non-null float64
dtypes: float64(5), object(2)
memory usage: 411.0+ KB
data=data.drop(data[data['购药时间'].str[:10]=='2018-02-29'].index)#这里有2018-02-29号的数据,要知道18年是没有29日的,属于异常数据删除
data[data['购药时间'].isnull()]#查看2018年2月29日对应的数据
运行结果:
购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额
6570 NaN 11778628.0 2367011.0 高特灵 10.0 56.0 56.0
data=data.loc[data['购药时间'].dropna().index]#删除该行异常数据
data['Date']=pd.to_datetime(data['购药时间'].str[:10],format='%Y-%m-%d')#利用datetime转换购药时间列为datetime数据类型
data.Date#查看
运行结果:
0 2018-01-01
1 2018-01-02
2 2018-01-06
3 2018-01-11
4 2018-01-15
...
6572 2018-04-27
6573 2018-04-27
6575 2018-04-27
6576 2018-04-27
6577 2018-04-28
Name: Date, Length: 6552, dtype: datetime64[ns]
data.rename(columns={'购药时间':'销售时间'},inplace=True)#命名列名购药时间为销售时间,inplace参数如果为true就是修改原数据,如果为false就是不修改原数据
data=data.sort_values('Date')#按照日期排序
data=data.reset_index(drop=True)
data.describe()#describe快速统计数据
运行结果:
社保卡号 商品编码 销售数量 应收金额 实收金额
count 6.552000e+03 6.552000e+03 6552.000000 6552.00000 6552.000000
mean 6.095150e+09 1.015031e+06 2.384158 50.43025 46.266972
std 4.888430e+09 5.119572e+05 2.374754 87.68075 81.043956
min 1.616528e+06 2.367010e+05 -10.000000 -374.00000 -374.000000
25% 1.014290e+08 8.614560e+05 1.000000 14.00000 12.320000
50% 1.001650e+10 8.615070e+05 2.000000 28.00000 26.500000
75% 1.004898e+10 8.687840e+05 2.000000 59.60000 53.000000
max 1.283612e+10 2.367012e+06 50.000000 2950.00000 2650.000000
data=data.drop(data[(data['销售数量']<=0) | (data['应收金额']<=0)].index)#根据上表的数据我们发现销售数量和应收金额的min出现了负数,我们要知道金额和数量不可能是负数,所以这是异常值需要我们删除
data.duplicated().sum() #查找重复的数据
数据分析环节
# 月均消费次数
data_month_count=data.drop_duplicates(subset=['销售时间','社保卡号'])
day_number=(max(data_month_count.Date)-min(data_month_count.Date)).days
print('月均消费次数:%.2f' %(len(data_month_count)/(day_number//30)))
运行结果:
月均消费次数:890.83
# 月均消费金额
money_sum=data['实收金额'].sum()
print('月均实收金额: %.2f' %(money_sum/(day_number//30)))
运行结果:
月均实收金额: 50672.49
# 客单价
print('客单价: %.2f' %(money_sum/data_month_count.shape[0]))
运行结果:
客单价: 56.88
# 消费趋势
dd=data.set_index('Date',drop=True)# 将索引index编成日期,方便之后进行重采样
# 按天采样 #fontsize是字体大小
dd_day=dd.resample('D').sum()
plt.figure(figsize=(30,10),dpi=50)
plt.plot(dd_day.index,dd_day['实收金额'])
plt.title('平均每天销售金额',fontsize=20)
plt.legend(['money'],fontsize=20)
plt.xlabel('time',fontsize=20)
plt.ylabel('money_sum',fontsize=20)
运行结果:
# 按月采样
dd_month=dd.resample('M').sum()
plt.figure(figsize=(30,10),dpi=50)
plt.plot(dd_month.index,dd_month['实收金额'])
plt.title('平均每月销售金额',fontsize=20)
plt.legend(['money'],fontsize=20)
plt.xlabel('time',fontsize=20)
plt.ylabel('money_sum',fontsize=20)
#按星期采样
#对星期进行自定义排序
data['销售星期']=data['销售时间'].str[11:]
week=['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
data['销售星期']=data['销售星期'].astype('category').cat.set_categories(week)
data=data.sort_values(by=['销售星期'])
#销售星期分析
data= data.sort_values('销售星期')
money_week=data.groupby(['销售星期'])['实收金额'].sum()
#绘图
plt.figure(figsize=(30,10),dpi=50)
plt.plot(money_week.index,money_week)
plt.xticks(money_week.index,fontsize=20)
plt.title('按星期划分的销售情况',fontsize=20)
plt.legend(['money'],fontsize=20)
分析结论
#根据以上图表和分析,我们可以发现周五和周六的销售总额要显著高于其他日期 即周五周六前来买药的客户人数更多,销售的药品数量更多
#根据每周的销售趋势是周日到周四销售总额会有波动,但是幅度不大,周五周六的销售总额相对较高,按月份比较的话,四月份的销售总额显著的高,而二月份的销售总额显著的低,猜测销售总额非常低是因为春节的缘故
为了舒适的结果,眼前的坎坷路程即使再长都是值得的。