北京朝阳医院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)
运行结果:
![1]()
# 按月采样
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)
![]()
分析结论
#根据以上图表和分析,我们可以发现周五和周六的销售总额要显著高于其他日期 即周五周六前来买药的客户人数更多,销售的药品数量更多
#根据每周的销售趋势是周日到周四销售总额会有波动,但是幅度不大,周五周六的销售总额相对较高,按月份比较的话,四月份的销售总额显著的高,而二月份的销售总额显著的低,猜测销售总额非常低是因为春节的缘故