通过前面学习的pandas基础,下面开始实践~每天进步一点点
数据分析的基本过程一般分为以下几个部分:
①提出问题
②理解数据
③数据清洗
④构建模型
⑤数据可视化
本项目根据以上过程详细分析朝阳医院药品销售数据!
数据获取
链接:https://pan.baidu.com/s/1IsU5jEgPxTmLGq3z3ja_pA
提取码:h51q
1.提出问题
在数据分析之前,我们先要明确分析目标是什么,这样可以避免我们像无头苍蝇一样拿着数据无从下手,也可以帮助我们更高效的选取数据,进行分析研究。
本次的分析目标是从销售数据中分析出以下业务指标:
1)月均消费次数
2)月均消费金额
3)客单价
4)消费趋势
有了分析目标,我们再来关注一下数据情况。
2.理解数据
1)导入数据包,提取数据文件
# coding:utf-8
import pandas as pd
salesDf = pd.read_excel(r'.\朝阳医院2018年销售数据.xlsx')
2)查看导入数据的基本状况
#查看导入数据的类型
print(type(salesDf))
# 查看列数据类型
print(salesDf.dtypes())
# 行数 列数
print(salesDf.shape)
#查看列名
print(salesDf.columns)
#查看每列数据的统计数目
print(salesDf.count())
#查看前五列
print(salesDf.head())
打印结果:
image.png3.数据清洗
取得了数据,并不能马上就开始进行数据分析。我们得到的数据通常并不是完全符合我们分析要求的,而且可能存在缺失值、异常值,这些数据都会使我们的分析结果产生偏差。所以在分析之前,需要进行子集选择、缺失数据补充、异常值处理、数据类型转换等多个步骤。这些都属于数据清理的范畴。 在数据分析中,通常有多达60%的时间是花在数据清洗中的。通常的清洗步骤有以下几步:
• 选择子集
• 列名重命名
• 缺失数据处理
• 数据类型转换
• 数据排序
• 异常值处理
这些步骤有些不是一步就能完成的,可能需要重复操作。
现在开始对药店销售数据进行数据清洗。
1)选择子集
药店销售数据中,项目较少,选择子集可以忽略,我们从列名重命名开始。
2)列名重命名
销售数据集,购药时间显示为销售时间更为合理,我们先把这个项目名称做一下变更。
#购药时间->销售时间
nameChangeDict = {'购药时间':'销售时间'}
#参数inplace=True表示覆盖元数据集
salesDf.rename(columns = nameChangeDict,inplace=True)
3)缺失数据处理
对于缺失数据,我们可以有几种处理方法:
▪ 删除
当缺失数据占总数据量的比例很小的时候,我们通常采用删除的处理方法。
▪ 合理值填充
在某些不适合删除的场合,我们有时候也会对缺失数据进行合理值填充,如平均值,中位数,相邻数据等等。
#首先查看一下哪些项目存在缺失值
print(salesDf.isnull().any())
image.png
好吧,每个项目都存在缺失值。在这个销售数据中,销售时间和社保卡号是必须项目,不可或缺。所以我们在这里只把销售时间和社保卡号有缺失的数据做删除处理。我们来查看一下销售时间和社保卡缺失的数据大小,然后做删除处理。
#查看一下缺失值的数量
#通常可以用isnull函数来查找缺失值
salesDf[salesDf[['销售时间','社保卡号']].isnull().values == True]
image.png
#序号6574因为销售时间和社保卡号都缺失,所以会出现两次。所以我们要去掉一下重复数据。
naDf = salesDf[salesDf[['销售时间','社保卡号']].isnull().values == True].drop_duplicates()
print(naDf)
image.png
从上面可以清楚看出销售时间和社保卡号缺失的数据一共有三条,当数据量大的时候我们可以只显示条数,不显示数据内容
#缺失数据行数
print(naDf.shape[0])
#现在把这些缺失数据进行删除
#含有销售时间和社保卡号的缺失数据删除
salesDf = salesDf.dropna(subset=['销售时间','社保卡号'],how = 'any')
#删除后数据集规模显示
print(salesDf.shape)
在数据删除后要及时更新一下最新的序号,不然可能会产生问题。
#重命名行名(index):排序后的列索引值是之前的行号,需要修改成从0到N按顺序的索引值
salesDf=salesDf.reset_index(drop=True)
4)数据类型转换
▪ 数量、金额项目:从字符串类型转换为数值(浮点型)类型
salesDf['销售数量'] = salesDf['销售数量'].astype('float')
salesDf['应收金额'] = salesDf['应收金额'].astype('float')
salesDf['实收金额'] = salesDf['实收金额'].astype('float')
print('转换后的数据类型:\n',salesDf.dtypes)
▪ 日期项目:从字符串类型转换为日期类型 销售日期中包含了日期和星期,我们只要保留日期内容即可。这里用一个自定义的函数dateChange来实现这个功能。
# 日期转换
def dateChange(dateSer):
dateList = [i.split(' ')[0] for i in dateSer]
dateChangeSer = pd.Series(dateList)
return dateChangeSer
dateChangeSer = dateChange(salesDf['销售时间'])
print(dateChangeSer)
salesDf['销售时间'] = dateChangeSer
print(salesDf.head())
image.png
在做完转化后再观察一下有没有产生新的缺失值
print(salesDf['销售时间'].isnull().any())
print(salesDf.dtypes)
数据没有产生新的缺失,我们继续向下,把销售时间的数据类型转为日期型。
dateSer=pd.to_datetime(salesDf['销售时间'], format = '%Y-%m-%d', errors='coerce')
print(dateSer)
print(dateSer.isnull().any())
compareDf = pd.DataFrame(dateSer[dateSer.isnull()],salesDf[dateSer.isnull()]['销售时间'])
print(compareDf)
image.png
查看了下数据,产生空值的原因是因为数据中出现了'2018-02-29'这样实际不存在的日期。在实际应用中,最好能向业务部门询问一下产生的原因,看下是不是因为日期推算不正确导致了这样原因的产生,需不需要将这样的数据进行一下必要的修正。这里就简单的把数据进行删除。
salesDf['销售时间'] = dateSer
print(salesDf.dtypes)
salesDf = salesDf.dropna(subset=['销售时间', '社保卡号'], how='any')
print(salesDf.shape)
salesDf = salesDf.reset_index(drop=True)
5)数据排序 销售记录一般是以销售时间为顺序排列的,所以我们对数据进行一下排序
# 按销售时间排序
salesDf = salesDf.sort_values(by='销售时间')
# 再次更新一下序号
salesDf = salesDf.reset_index(drop=True)
print(salesDf)
6)异常值处理
在下面数据集的描述指标中可以看出,存在销售数量为负的数据,这明显是不合理的,我们把这部分数据也进行删除
print(salesDf.describe())
image.png
# 删除异常值:通过条件判断筛选出数据#查询条件
querySer = salesDf.loc[:, '销售数量'] > 0
# 应用查询条件
print('删除异常值前:', salesDf.shape)
salesDf = salesDf.loc[querySer, :]
print('删除异常值后:', salesDf.shape)
删除异常值前: (6552, 7)
删除异常值后: (6509, 7)
4.构建模型
1)业务指标1:月均消费次数=总消费次数 / 月份数
总消费次数:同一天内,同一个人发生的所有消费算作一次消费。这里我们根据列名(销售时间,社区卡号)结合,如果这两个列值同时相同,只保留1条,将重复的数据删除
月份数:数据已经按照销售时间进行排序,只需将最后的数据与第一条数据相减就可换算出月份数
# 总消费次数计算
kpDf = salesDf.drop_duplicates(subset=['销售时间', '社保卡号'])
total = kpDf.shape[0]
print('总消费次数为:', total)
# 月份数计算
startDay = salesDf.loc[0, '销售时间']
print('开始日期:', startDay)
endDay = salesDf.loc[salesDf.shape[0] - 1, '销售时间']
print('结束日期:', endDay)
monthCount = (endDay - startDay).days // 30
print('月份数:', monthCount)
# # 业务指标1:月均消费次数=总消费次数 / 月份数
kpi1 = total / monthCount
print('业务指标1:月均消费次数=', kpi1)
image.png
业务指标1:月均消费次数= 890.8333333333334
2)指标2:月均消费金额 = 总消费金额 / 月份数
totalMoney = salesDf['实收金额'].sum()
kpi2 = totalMoney / monthCount
print('业务指标2:月平均消费金额=', kpi2)
业务指标2:月平均消费金额= 50672.494999999995
3)指标3:客单价=总消费金额 / 总消费次数
kpi3 = kpi2 / kpi1
print('业务指标3:客单价=', kpi3)
业务指标3:客单价= 56.88212722170252
4)指标4:消费趋势,画图:折线图
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
# 在进行操作之前,先把数据复制到另一个数据框中,防止对之前清洗后的数据框造成影响
groupDf = salesDf
# 第1步:重命名行名(index)为销售时间所在列的值
groupDf.index = groupDf['销售时间']
print(groupDf.head())
image.png
# 第2步:分组
gb = groupDf.groupby(groupDf.index.month)
# 第3步:应用函数,计算每个月的消费总额
mounthDf = gb.sum()
print(mounthDf)
image.png
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['font.serif'] = ['SimHei']
sns.set_style("darkgrid", {"font.sans-serif": ['simhei', 'Arial']})
# 绘制销售数量图
plt.plot(mounthDf['销售数量'], color='b')
plt.show()
image.png
参考链接:https://mp.weixin.qq.com/s?__biz=MzIyNTg3ODM0Ng==&mid=2247483699&idx=1&sn=67826b5afdfb7cc7d924601edf6a6acb&chksm=e8784916df0fc000769969be83de5f4268f9e49657495b93f417d9b714393c08aeb38eb61925&token=498825246&lang=zh_CN&scene=21#wechat_redirect
网友评论