手上有一份练习使用虚拟的朝阳医院2018年销售数据,使用Python进行简单的分析。数据分析的流程
一,提出问题
通过数据,分析医院销售的以下问题:
1.1 该医院月均消费次数
1.2 该医院月均消费金额
1.3 客单价
1.4 消费趋势
二,理解数据
2.1导入数据
首先使用python的pandas数据分析包导入数据,并设置格式为object
#读取Excel数据,统一先按照str读入,之后转换
import pandas as pd
fileNameStr='./朝阳医院2018年销售数据.xlsx'
xls=pd.ExcelFile(fileNameStr,dtype='object')
salesDf=xls.parse('Sheet1',dtype='object')
print(salesDf.shape)
salesDf.head()
也可以用read_excel导入导入文件的大小与前五行
可以看出文件含有6578条数据,其中的信息有购药时间、社保卡号、商品编码、商品名称、销售数量、应收金额,实收金额。
三,数据清洗
3.1 选择子集
可以使用.loc[:,列名]来选择子集,本项目7列均是有效数据,无需选择子集。
subSalesDf=salesDf.loc[:,'购药时间':'销售数量']
3.2 列名重命名
将购药时间更改为销售时间
colNameDict={'购药时间':'销售时间'}
salesDf.rename(columns=colNameDict,inplace=True)
salesDf.head()
3.3 删除重复值
可以通过duplicated来判断重复值,salesDf.drop_duplicates()可以删除行完全重复的行
#查看有无重复值
dIndex = salesDf.duplicated()
dIndex
salesDf[dIndex]
#直接删除重复行
newsalesDf=salesDf.drop_duplicates()查看有无重复行
本次分析工作没有重复的行,即使有重复的行,也最好先进行查看甄别看是否是重复值。
3.4 缺省值处理
当销售时间或社保卡号有缺省值时,删除该条数据。
print('删除缺失值前大小',salesDf.shape)
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失值后大小',salesDf.shape)缺省值处理-销售时间/社保卡号
缺省值处理还有通过算法进行填充,本次缺省值不多,进行删除处理。
3.5 一致化处理
将销售数量、应收金额、实收金额的类型转为浮点数。
#字符串转换为数值(浮点数)
salesDf['销售数量']=salesDf['销售数量'].astype('float')
salesDf['应收金额']=salesDf['应收金额'].astype('float')
salesDf['实收金额']=salesDf['实收金额'].astype('float')
将日期分隔开
'''定义函数:分割销售日期,获取销售日期输入:timeColSer 销售时间这一列,是个Series数据类型输出:分割后的时间,返回也是个Series数据类型'''
def splitSaletime(timeColSer):
timeList1=[]
timeList2=[]
for value in timeColSer:
#分割日期,例如2018-01-01 星期五,分割后为:2018-01-01
dateStr1=value.split(' ')[0]
dateStr2=value.split(' ')[1]
timeList1.append(dateStr1)
timeList2.append(dateStr2)
#将列表转行为一维数据Series类型
timeSer1=pd.Series(timeList1)
timeSer2=pd.Series(timeList2)
print(timeSer1[:5],timeSer2[:5])
return timeSer1,timeSer2
#获取"销售时间"这一列
timeSer=salesDf.loc[:,'销售时间']
#对字符串进行分割,获取销售日期
dateSer1,dateSer2=splitSaletime(timeSer)
print(dateSer1[0:5],dateSer2[0:5])将日期和星期分开
#修改销售时间这一列的值
salesDf.loc[:,'销售时间']=dateSer1
salesDf.loc[:,'销售时间2']=dateSer2
salesDf.head()保留日期和星期
把星期数保留,以便后续分析周末和平时的销售差别
#把星期数排到第二个位置
salesDf_time=salesDf['销售时间2']
salesDf=salesDf.drop('销售时间2',axis=1)
salesDf.insert(1,'销售时间星期',salesDf_time)
salesDf.head()把星期数排在第二个位置
将日期时间改为时间格式
'''
数据类型转换:字符串转换为日期
'''
#errors='coerce' 如果原始数据不符合日期的格式,转换后的值为空值NaT
#format 是原始数据中日期的格式
salesDf.loc[:,'销售时间']=pd.to_datetime(salesDf.loc[:,'销售时间'],
format='%Y-%m-%d',
errors='coerce')
salesDf.dtypes
再次处理缺省值
print('Before drop na:',salesDf.shape)
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('After drop na:',salesDf.shape)
3.6排序
#按照销售时间进行升序排序
salesDf=salesDf.sort_values(by='销售时间',ascending=True)
salesDf.head()按照销售时间升序排序
#重命名行名(index)
salesDf=salesDf.reset_index(drop=True)
salesDf.head()重命名行名
3.7 异常值处理
#删除异常值,通过条件判断筛选出数据
#查询条件
querySer=salesDf.loc[:,'销售数量']>0
print('Before del:',salesDf.shape)
salesDf=salesDf.loc[querySer,:]
print('After del:',salesDf.shape)删除销售数量为负的值
四,构建模型
回到问题本质上,一开始的需求是:月均消费次数、月均消费金额、客单价、消费趋势
4.1月均消费次数=总消费次数/月份数
计算总消费次数
#同一天内,同一个人发生所有消费算作一次消费
kpi1_Df=salesDf.drop_duplicates(subset=['销售时间','社保卡号'])
#计算总消费次数
totalI=kpi1_Df.shape[0]
print('总消费次数',totalI)
#计算月份数
#按销售时间升序排序
kpi1_Df=kpi1_Df.sort_values(by='销售时间',
ascending=True)
#重命名行名(index)
kpi1_Df=kpi1_Df.reset_index(drop=True)
#获取最小最大时间值
startTime=kpi1_Df.loc[0,'销售时间']
endTime=kpi1_Df.loc[totalI-1,'销售时间']
#计算天数
daysI=(endTime-startTime).days
#月份数:运算符"//"表示取整
monthsI=daysI//30
monthsF=daysI/30
print('月份数:%d ,天数:%d'%(monthsI,daysI))
print('月份数2:',monthsF)
kpi1_I=totalI//monthsI
print('业务指标1:月均消费次数=',kpi1_I)
4.2月均消费金额=总消费金额/月份数
#月均消费金额
#总消费金额/月份数
totalMoneyF=salesDf.loc[:,'实收金额'].sum()
monthMoneyF=totalMoneyF/monthsF
print('总金额:{},业务指标2:月均消费金额={}'.format(totalMoneyF,monthMoneyF))
4.3 客单价=总金额/消费次数
#客单价 = 总金额/消费次数
pccF=totalMoneyF/totalI
print('客单价:',pccF)
salesDf.to_excel('tmp.xlsx')
4.4消费趋势
对销售数量、应收金额、实收金额进行按照月度分组
saleDfGy=salesDf[['销售数量','应收金额','实收金额']].groupby(salesDf["销售时间"].apply(lambda x:x.month)).sum()
saleDfGy月度分组
每个月的应收总金额走势
import numpy as np
import matplotlib.pyplot as plt
plt.plot(saleDfGy[['实收金额']])每月应收总额走势
plt.plot(saleDfGy[['销售数量']])
销售数量走势销售数量走势
消费次数统计
totalIpM=kpi1_Df['销售时间'].groupby(salesDf["销售时间"].apply(lambda x:x.month)).count()
print('每个月消费次数:\n',totalIpM)消费次数统计
#客单价分析
pccFpm=saleDfGy['实收金额']/totalIpM
plt.plot(pccFpm)客单价分析
五,结论
1,应收金额在二月份有大幅度下降,三月份恢复,四月份回到正常水平,原因很可能是二月份因春节原因北京返乡人数大幅增加引起的;
2,四月份销售数量和消费次数都明显上升,但消费单价下降,很可能原因是因为温度慢慢回升,细菌得到适合的环境,感冒等小疾病突发,但消费单价不高。
3,七月份是因为统计日期不到二十天,出现总金额、次数不足。