数据分析:某地医院药品销售业务数据分析
数据分析:某地医院药品销售业务数据分析
本篇⽂章以朝阳医院2018年销售数据为例,⽬的是了解朝阳医院在2018年⾥的销售情况⼏个业务指标
⽉均消费次数
⽉均消费⾦额
客单价
消费趋势
数据分析的步骤:提出问题→理解数据→数据清洗→构建模型→数据可视化
⼀.确定业务问题
我们知道,数据分析是指⽤适当的统计分析⽅法对收集来的⼤量数据进⾏分析,提取有⽤信息和形成结论⽽对数据加以详细研究和概括总结的过程。
那么,与之对应的数据分析基本过程包括:获取数据、数据清洗、构建模型、数据可视化以及消费趋势等
⼆:数据概览
# 2018年朝阳医院数据消费⾦额趋势图
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
import pandas as pd
import numpy as np
fileNameStr='F:\\Downloads\朝阳医院2018年销售数据.xlsx'
xls=pd.ExcelFile(fileNameStr,dtype='object')
salesDf = xls.parse('Sheet1',dtype='object')
salesDf.info()
打印结果
<class 'frame.DataFrame'>
RangeIndex: 6578 entries, 0 to 6577
Data columns (total 7 columns):
购药时间    6576 non-null object
社保卡号    6576 non-null float64
商品编码    6577 non-null float64
商品名称    6577 non-null object
销售数量    6577 non-null float64
应收⾦额    6577 non-null float64
实收⾦额    6577 non-null float64
dtypes: float64(5), object(2)
memory usage: 359.8+ KB
数据概览
salesDf.head()
打印结果
购药时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 星期五 001616528 236701 强⼒VC银翘⽚ 6 82.8 69
1 2018-01-0
2 星期六 001616528 236701 清热解毒⼝服液 1 28 24.64
2 2018-01-06 星期三 0012602828 236701 感康 2 16.8 15
3 2018-01-11 星期⼀ 0010070343428 236701 三九感冒灵 1 28 28
4 2018-01-1
5 星期五 00101554328 236701 三九感冒灵 8 224 208
# ⾏、列数
salesDf.shape
(6578, 7)
salesDf.index
RangeIndex(start=0, stop=6578, step=1)
s
Index(['购药时间', '社保卡号', '商品编码', '商品名称', '销售数量', '应收⾦额', '实收⾦额'], dtype='object')
购药时间    6576
社保卡号    6576
商品名称    6577
销售数量    6577
应收⾦额    6577
实收⾦额    6577
dtype: int64
数据缺失:总共有6578⾏7列数据,但是“购药时间”和“社保卡号”这两列只有6576个数据,⽽“商品编码”⼀直到“实收⾦额”这些列都是只有6577个数据,数据中存在缺失值,可以推断出数据中存在⼀⾏缺失值,此外“购药时间”和“社保卡号”这两列都各⾃存在⼀个缺失数据。
在任何数据分析的操作步骤中,为保证数据分析准确性,数据清洗步骤就显得尤为重要。
三.数据清洗
数据清洗过程,或称数据预处理,主要包括以下⼏个步骤
选择⼦集
列名重命名
删除缺失数据
数据类型转换
数据排序
异常值处理
1选择⼦集
在我们获取到的数据中,可能数据量⾮常庞⼤,并不是每⼀列都有价值都需要分析,这时候就需要从整个数据中选取合适的⼦集进⾏分析,这样能从数据中获取最⼤价值。
2列名重命名
在数据分析过程中,有些列名和数据容易混淆或产⽣歧义,不利于数据分析,这时候需要把列名换成容易理解的名称,可以采⽤rename函数实现:
salesDf.head()
打印结果
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 星期五 1.616528e+06 236701.0 强⼒VC银翘⽚ 6.0 82.8 69.00
1 2018-01-0
2 星期六 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-1
5 星期五 1.015543e+08 236701.0 三九感冒灵 8.0 224.0 208.00
3 缺失数据处理
任何⼀个得到的数据都很有可能会有缺失值,删除列(销售时间,社保卡号)中为空的⾏,使⽤dropna删除缺失数据
print('删除缺失值前⼤⼩',salesDf.shape)
# how='any' 给定的任何⼀列中有缺失值就删除
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失后⼤⼩',salesDf.shape)
打印结果
删除缺失值前⼤⼩ (6578, 7)
删除缺失后⼤⼩ (6575, 7)
4 数据类型处理
在导⼊的时候为了防⽌有些数据导⼊不进来,所以强制所有数据都是object类型,但在实际分析上这样是不可能的。
通过观察,销售数量,应收⾦额,实收⾦额,应该改成float类型,销售时间应该清理后改成时间类型,对于改变成float类型的⼏列,使⽤astype函数,代码如下。
salesDf['销售数量']=salesDf['销售数量'].astype('float')
salesDf['应收⾦额']=salesDf['应收⾦额'].astype('float')
salesDf['实收⾦额']=salesDf['实收⾦额'].astype('float')
print('转换后的数据类型:\n',salesDf.dtypes)
打印结果
销售时间    object
社保卡号    object
商品编码    object
商品名称    object
销售数量    float64
应收⾦额    float64
实收⾦额    float64
dtype: object
⽽销售时间那⼀列,则需要进⾏处理后才能转换为时间类型,把销售时间的⽇期和星期分开
分割时间列,定义函数:分割销售⽇期,获取销售⽇期
def splitSaletime(timeColSer):
timeList=[]
for value in timeColSer:
#例如2018-01-01 星期五,分割后为:2018-01-01
dateStr=value.split(' ')[0]
timeList.append(dateStr)
timeSer=pd.Series(timeList)
return timeSer
获取“销售时间”这⼀列,对字符串进⾏分割,获取销售⽇期
timeSer=salesDf.loc[:,'销售时间']
dateSer=splitSaletime(timeSer)
修改销售时间这⼀列的值
打印结果
dateSer[0:3]
0    2018-01-01
1    2018-01-02
2    2018-01-06
dtype: object
获取分割之后的销售⽇期,少了星期时间字符
salesDf.loc[:,'销售时间']=dateSer
salesDf.head()
打印结果
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 001616528 236701 强⼒VC银翘⽚ 6.0 82.8 69.00
1 2018-01-0
2 001616528 236701 清热解毒⼝服液 1.0 28.0 24.64
2 2018-01-06 0012602828 236701 感康 2.0 16.8 15.00
3 2018-01-11 0010070343428 236701 三九感冒灵 1.0 28.0 28.00
4 2018-01-1
5 00101554328 236701 三九感冒灵 8.0 224.0 208.00
5 数据排序
使⽤sort_values进⾏排序,by:按哪⼏列排序,ascending=True 表⽰升序排列,ascending=False表⽰降序排列#按销售时间进⾏升序排列
salesDf=salesDf.sort_values(by='销售时间',ascending=True)
#查看排序后的前10⾏
salesDf.head(10)
打印结果
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 001616528 236701 强⼒VC银翘⽚ 6.0 82.8 69.0
3436 2018-01-01 0010616728 865099 硝苯地平⽚(⼼痛定) 2.0 3.4 3.0
1190 2018-01-01 0010073966328 861409 ⾮洛地平缓释⽚(波依定) 5.0 162.5 145.0
3859 2018-01-01 0010073966328 866634 硝苯地平控释⽚(欣然) 6.0 111.0 92.5
3888 2018-01-01 0010014289328 866851 缬沙坦分散⽚(易达乐) 1.0 26.0 23.0
交易时间字符串是什么894 2018-01-01 0013331728 861405 苯磺酸氨氯地平⽚(络活喜) 2.0 69.0 62.0
893 2018-01-01 0011743428 861405 苯磺酸氨氯地平⽚(络活喜) 1.0 34.5 31.0
4368 2018-01-01 00103283128 870921 卡托普利⽚ 1.0 2.4 2.2
4562 2018-01-01 0010074599128 874684 厄贝沙坦氢氯噻嗪⽚(依伦平) 5.0 118.0 118.0
5039 2018-01-01 0010017493928 868042 马来酸左旋氨氯地平⽚(⽞宁) 1.0 46.0 46.0
重命名⾏名(index),使⽤reset_index修改成从0到N按顺序排序的索引值index
set_index(drop=True)
查看数据 salesDf.head(6)
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 001616528 236701 强⼒VC银翘⽚ 6.0 82.8 69.0
1 2018-01-01 0010616728 865099 硝苯地平⽚(⼼痛定) 2.0 3.4 3.0
2 2018-01-01 0010073966328 861409 ⾮洛地平缓释⽚(波依定) 5.0 162.5 145.0
3 2018-01-01 0010073966328 86663
4 硝苯地平控释⽚(欣然) 6.0 111.0 92.5
4 2018-01-01 0010014289328 866851 缬沙坦分散⽚(易达乐) 1.0 26.0 23.0
5 2018-01-01 0013331728 861405 苯磺酸氨氯地平⽚(络活喜) 2.0 69.0 62.0
6 异常值处理
查看汇总数据描述,其中销售数量值不能⼩于0
salesDf.describe()
打印结果
销售数量应收⾦额实收⾦额
count 6549.000000 6549.000000 6549.000000
mean 2.384486 50.449076 46.284370
std 2.375227 87.696401 81.058426
min -10.000000 -374.000000 -374.000000
25% 1.000000 14.000000 12.320000
50% 2.000000 28.000000 26.500000
75% 2.000000 59.600000 53.000000
max 50.000000 2950.000000 2650.000000
通过条件判断来删除异常值
querySer=salesDf.loc[:,'销售数量']>0
print('删除异常值前:',salesDf.shape)
salesDf=salesDf.loc[querySer,:]
print('删除异常值后:',salesDf.shape)
# 打印结果
删除异常值前: (6549, 7)
删除异常值后: (6506, 7)
数据的预处理⼯作完成,接下来分析业务的各个指标
四构建数据模型
1.⽉份数
业务指标1:⽉均消费次数=总消费次数 / ⽉份数
在计算总的消费次数当中将每个⼈每天的不同消费记录作为消费⼀次,⽤drop_duplicates去掉同⼀天同⼀个⼈的重复消费记录根据列名(销售时间,社区卡号),如果这两个列值同时相同,只保留1条,将重复的数据删除
kpi1_Df=salesDf.drop_duplicates(subset=['销售时间', '社保卡号'])
#总消费次数
totalI=kpi1_Df.shape[0]
print('总消费次数=',totalI)
# 打印结果:总消费次数= 5342
# 计算⽉份数
#按销售时间升序排序
kpi1_Df=kpi1_Df.sort_values(by='销售时间',ascending=True)
#重命名⾏名,索引排序
kpi1_Df=set_index(drop=True)
kpi1_Df.head()
打印结果
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
0 2018-01-01 001616528 236701 强⼒VC银翘⽚ 6.0 82.8 69.0
1 2018-01-01 0012697828 861464 复⽅利⾎平⽚(复⽅降压⽚) 4.0 10.0 9.4
2 2018-01-01 0010060654328 861458 复⽅利⾎平氨苯蝶啶⽚(北京降压0号) 1.0 10.
3 9.2
3 2018-01-01 0011811728 861456 酒⽯酸美托洛尔⽚(倍他乐克) 1.0 7.0 6.3
4 2018-01-01 0013448228 861507 苯磺酸氨氯地平⽚(安内真) 1.0 9.
5 8.5
计算总⽉份数,第⼀⾏时间与结尾时间之差除以30取整
startTime=kpi1_Df.loc[0,'销售时间']
#最⼤时间值
endTime=kpi1_Df.loc[totalI-1,'销售时间']
#天数
daysI=(endTime-startTime).days
#⽉份数: 运算符“//”表⽰取整除
#返回商的整数部分,例如9//2 输出结果是4
monthsI=daysI//30
print('⽉份数:',monthsI)
⽉份数: 6
2.⽉均消费次数
业务指标2:⽉均消费次数=总消费次数 / ⽉份数
计算⽉均消费次数
kpi1_I=totalI // monthsI
print('业务指标2:⽉均消费次数=',kpi1_I)
# 打印结果
业务指标2:⽉均消费次数= 890
3.⽉均消费⾦额
指标3:⽉均消费⾦额 = 总消费⾦额 / ⽉份数
#总消费⾦额
totalMoneyF=salesDf.loc[:,'实收⾦额'].sum()
#⽉均消费⾦额
monthMoneyF=totalMoneyF / monthsI
print('业务指标3:⽉均消费⾦额=',monthMoneyF)
业务指标3:⽉均消费⾦额= 50668.35166666666
4.客单价
指标4:客单价=总消费⾦额 / 总消费次数
客单价(per customer transaction)是指商场(超市)每⼀个顾客平均购买商品的⾦额,客单价也即是平均交易⾦额。'''
totalMoneyF:总消费⾦额
totalI:总消费次数
'''
pct=totalMoneyF / totalI
print('客单价:',pct)
客单价: 56.909417821040805
5.消费趋势图
#在进⾏操作之前,先把数据复制到另⼀个数据框中,防⽌对之前清洗后的数据框造成影响
groupDf=salesDf
#第1步:重命名⾏名(index)为销售时间所在列的值
groupDf.index=groupDf['销售时间']
groupDf.head()
打印结果
销售时间社保卡号商品编码商品名称销售数量应收⾦额实收⾦额
销售时间
2018-01-01 2018-01-01 001616528 236701 强⼒VC银翘⽚ 6.0 82.8 69.0
2018-01-01 2018-01-01 0010616728 865099 硝苯地平⽚(⼼痛定) 2.0 3.4 3.0
2018-01-01 2018-01-01 0010073966328 861409 ⾮洛地平缓释⽚(波依定) 5.0 162.5 145.0
2018-01-01 2018-01-01 0010073966328 866634 硝苯地平控释⽚(欣然) 6.0 111.0 92.5

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。