手上有一份练习使用虚拟的朝阳医院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,七月份是因为统计日期不到二十天,出现总金额、次数不足。