注:本文主要是利用python进行简单的医疗数据分析的练习文章,仅限新手练习用。
程序狗的前世与今生
最近的学习让我最大的感触就是终于知道什么叫做‘人生苦短’,需要太多太多的时间要去学习和摸索了,最终我患上了‘突发性迷茫综合征’,大概就是这样的过程:‘看到好多牛逼的包和模块突然觉得哇自己那个都想学都要用,好多书视频都是关于python二话不说mark and download’→→→‘咦!网盘硬盘满了,好吧,我要去看书看视频敲代码’→→→‘且慢!这么多怎么看啊!?从哪个开始看啊?看完得啥时候了!!?’→→→‘抽根烟压压惊去!’→→→‘压完惊了没?’→→→‘再抽根’
经过迷茫并痛苦的洗礼后,我下定决心既然决定上这条船,那就让自己多些冷静,多去静下心来做好自己的规划,按照计划一步一步来吧。终于我到了数据分析这个坎儿了,so try my best(同时非常感谢鼓励我的人)。如题这次我稍微深入去练习数据分析,数据分析的基本步骤分为:提出问题—理解数据—数据清洗—构建模型—数据可视化—数据反馈(那是工作了之后的事了)。
(一)提出问题:
一切的数据分析工作目的都是要解决我们生活和工作中的实际问题,只有提出问题才能够进行下一步,比如:药店每个月的销售金额是多少?微信公众号中阅读量最多的十篇文章是哪些?明确的问题能够为我们后面数据分析提供了大的方向和目标。
因为这里给的是医院的部分药品销售数据(https://pan.baidu.com/s/1kXf4VIn),所以直接进入练习。目的是要获取月均消费次数、月均消费额、客单价、消费趋势
(二)理解数据:
1、根据我们提出的问题去获得相关的数据。2、导入我们获得的数据。3、查看数据集的信息。
1)读取Excel数据
#导入numpy包
import numpy as np
#导入pandas包
import pandas as pd
#读取Excel数据,统一先按照str读入,之后在转换
fileNameStr='C:/Users/Administrator/Desktop/朝阳医院2018年销售数据.xlsx'
xls = pd.ExcelFile(fileNameStr, dtype='object')
salesDf = xls.parse('Sheet1',dtype='object')
#打印前五行观察
salesDf.head()
#输入.shape看看有多少行多少列
salesDf.shape
#查看列的数据类型
salesDf.dtypes
(三)数据清洗:
数据清洗也叫数据预处理,因为大多时候获取的数据并不符合我们的数据分析的标准这时候我们就需要对数据进行预处理,使之数据更加规整有序方便我们下一步的分析。
数据清洗通常需要数据分析大部分时间,但是我觉得也是有一定的步骤的,我将它大致分为六部曲:选择子集→列名重命名→缺失数据处理→数据类型转换→数据排序→异常值处理
1)选择子集
当原始数据信息太大,里面有很多我们不需要的信息的时候我们需要选择子集,也就是原始数据中的一部分作为数据分析的对象,因为这里本身文件的数据够用加之数据量也不多不需要选择子集,所以只是简单练习了一下选择了从0到第4列的数据,这里通过切片访问原始数据并用loc属性确定选择子集的范围。
#选择子集
subSalesDf=salesDf.loc[0:4,'购药时间':'销售数量']
subSalesDf
2)对 列 进行重命名
这里我们对数据旧列名“购药时间”改为新列名“销售时间”。
#字典:旧列名和新列名对应关系
colNameDict = {'购药时间':'销售时间'}
'''
inplace=False,数据框本身不会变,而会创建一个改动后的新数据框,默认inplace是False
inplace=True,数据框本身会改动
'''
salesDf.rename(columns=colNameDict,inplace=True)
#再次打印前五行看看新列名有没有改上去
salesDf.head()
3)缺失数据的处理
原始数据经常会由于记录缺失错误,这时候会导致有些数据是缺失的,处理的两种办法:1、直接删除这个缺失数据:2、如果缺失数据太多德华就需要建立模型利用差值补充这些数据。这里我用的是直接删除数据的办法
但是这里的数据中的销售时间和社保卡号是不能有缺失值的,因为我们要区别出那个社保卡号在那段时间消费了,这里我用的是dropna来删除这个缺失数据
print('删除缺失值前大小',salesDf.shape)
删除缺失值前大小 (6578, 7)
#删除列(销售时间,社保卡号)中为空的行
#how=‘any’ 在给定的任何一列中有缺失值就删除
salesDf = salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失值后大小',salesDf.shape)
删除缺失值后大小 (6575, 7),subset是用于存放或删除指定列的列表
从这里可以看出删除后比删除前少了3数值,可能这3个数值是对不上号的
4)类型转换
因为在导入数据时候将所有的列导入的是字符串类型,但是后三列销售数量、应收金额、实收金额中的数值会出现小数点,所以这里把str字符串类型改为float浮点型
salesDf['销售数量'] = salesDf['销售数量'].astype('float')
salesDf['应收金额'] = salesDf['应收金额'].astype('float')
salesDf['实收金额'] = salesDf['实收金额'].astype('float')
print('转换后的数据类型: \n',salesDf.dtypes)
astype进行基本数据的类型转化,这里看到后三列已转换为浮点型
这里我发现时间这一列前面是日期中间是空格后面是星期几。如果业务不需要统计或者针对星期几的销售额的话我觉得完全可以把它去掉,这里需要字符串分割split
'''
定义函数:分割销售日期,获取销售日期
输入:timeColSer 销售时间这一列,是个Series数据类型
输出:分割后的时间,返回也是个Series数据类型
'''
def splitSaletime(timeColSer):
#建立一个空的时间列表
timeList=[]
for value in timeColSer:
#例如2018-01-01 星期五,分割后为:2018-01-01,星期五
dateStr=value.split(' ')[0]
timeList.append(dateStr)
#将列表转换为一维数据Series类型
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
dateSer.head()
还需要注意的是这里要把字符串转换为日期格式,也就是对应的销售时间和社保卡号这两列,因为后面需要计算总天数所以这里要提前转换一下
#字符串转换日期,转换后的值为NaT
#format 是原始数据中日期的格式
salesDf.loc[:,'销售时间']=pd.to_datetime(salesDf.loc[:,'销售时间'],format='%Y-%m-%d',errors='coerce')
'''
转换日期过程中不符合日期格式的数值会被转换为空值None
这里需要删除列(销售时间,社保卡号)中为空的行
'''
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
5)对销售时间进行排序
排序前:
排序后:
'''
by:按哪几列排序
ascending=True 表示降序排列
ascending=False 表示升序排列
'''
#按销售日期进行升序排列
salesDf=salesDf.sort_values(by='销售时间',ascending=True)
salesDf.head()
突然发现第一列第一行的数值为0但是第二列的第二行就是1903了
这里我需要把行重命名
#用index重命名行名
salesDf=salesDf.reset_index(drop=True)
salesDf.head()
这样就有顺序多了
6)异常值处理
为了从整体上了解这些数据,我用describe查看描述统计信息有没有异常值
#获取每一列数据的描述统计信息
salesDf.describe()
从图中发现销售数量最小值是负数,从而引起了应收金额和实收金额也是负数,销售数量肯定是大于零,我需要去处理异常值
#删除异常值:通过条件判断筛选出数据
#查询条件
querySer=salesDf.loc[:,'销售数量']>0
#应用查询条件
print('删除异常值前:',salesDf.shape)
salesDf=salesDf.loc[querySer,:]
print('删除异常值后:',salesDf.shape)
(四)构建模型:
通过对与处理后的数据进行简单或者复杂的分析,简单地说就是我们要输出的结果或指标
这里我需要获取月均消费次数:月均消费次数=总消费次数/总月份数,(这里总消费次数定义同一天内同一个人发生的所有消费算作一次消费),我需要判断销售时间和社保卡号这两列里面有哪些数据是重复的。
#删除重复数据
kpil_Df=salesDf.drop_duplicates(subset=['销售时间','社保卡号'])
#查看删除后有多少行
totalI=kpil_Df.shape[0]
print('总消费次数=',totalI)
获取总行数=总消费次数,然后再去获取总月份数:
1)获取总月份数需要把销售时间进行排序
#按销售时间升序排序
kpil_Df=kpil_Df.sort_values(by='销售时间',ascending=True)
#重命名行名(index)
kpil_Df=kpil_Df.reset_index(drop=True)
2)获取时间范围
#最小时间值
startTime=kpil_Df.loc[0,'销售时间']
#最大时间值
endTime=kpil_Df.loc[totalI-1,'销售时间']
3)计算月份数
#获取天数
daysI=(endTime-startTime).days
#月份数:天数除以月份数,月份数取30天为一个月,用运算符“//”取整除
#返回商的整数部分
monthsI=daysI//30
print('月份数:',monthsI)
接下来就可以计算月平均消费次数了
kpil_I=totalI // monthsI
print('目标1:月平均消费次数=',kpil_I)
计算月均消费金额
#总消费金额,sum()求和
totalMoneyF=salesDf.loc[:,'实收金额'].sum()
#月均消费金额
monthsMoneyF=totalMoneyF / monthsI
print('目标2:月均消费金额=',monthsMoneyF)
计算客单价
客单价=总消费金额/总消费次数
'''
totalMoneyF:总消费金额
totalI:总消费次数
'''
pct=totalMoneyF / totalI
print('客单价:',pct)
(五)数据可视化:
数据可视化说白了就是展示图表,数据用图表的方式展示出来方便别人去分析。这里用图表的方式去分析消费趋势。(数据可视化后面分享)