前两天翻了翻数据分析的招聘简历,看到好多公司在招聘数据分析师的时候,不管前面要求什么,都会在最后加一句:能够会Python是加分项。那Python是有多好用?今儿一篇文章教会你用Python来分析数据的常用语法。让你在面试的时候,也能有底气的来一句,了解一点儿。
首先呢,先讲讲Python分析常常用的3个包:NuPmy和Pandas以及绘制图形的matplotlib,本篇是Python分析数据的第一篇,所以在清洗数据的时候用的是前两个包,绘图包我会在后面的文章里详细讲解,敬请期待哈~
这三个包的功能不同,用法也不同,NumPy是用于数学计算,像各种复杂的运算方法都可以用Numpy实现,Pandas是数据分析工具,纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。
获取数据、观察数据
以朝阳医院一年的销售数据为例:
清洗为可供我们分析提取的规整型数据
源数据链接:
下好了数据之后,我们可以在C盘建立一个专门放置数据的文件夹,我将它命名为mymy
在Python中获取所需的分析包
#导入分析所需Pandas包
import pandas as pd
获取Excel中的数据,并且为了格式规范,我们将所有数据类型以字符串形式导入
#读取Ecxcel数据,统一先按照字符串读入,之后转换
#文件名字符串=‘文件位置’
fileNameStr='C:\mymy\朝阳医院2016年销售数据.xlsx'
xls = pd.ExcelFile(fileNameStr, dtype='object')
salesDf = xls.parse('Sheet1',dtype='object')
这里提一下,我们要养成经常看数据的习惯,来保证我们每一步的运行都是没有问题的
看下数据集前面几行,确保我们的操作没问题
#打印出前5行,以确保数据运行
salesDf.head()
打印后的数据展示
#有多少行,多少列
salesDf.shape
输出行与列的数
#查看每一列的数据类型
salesDf.dtypes
每一列都是我们设置的字符串类型
接着我们把销售时间改为购药时间
#字典:旧列名和新列名对应关系
colNameDict = {'购药时间':'销售时间'}
salesDf.rename(columns = colNameDict,inplace=True)
salesDf.head()
在代码里inplace=True的意思是我们的更改是在原来的数据框上面更改的。
(Python默认为Flase,也就是重新创建一个改动之后的数据框)
看,源数据上的购药时间已经改为了销售时间
接下来是对于空值我们的删除方式
print('删除缺失值前大小',salesDf.shape)
#删除列(销售时间,社保卡号)中为空的行
#how='any' 在给定的任何一列中有缺失值就删除
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失后大小',salesDf.shape)
还记得之前导入的时候,为了方便管理,我们全都导入为字符串格式了么,现在让我们把所有字符串格式的列转换为我们需要数据类型的列
我们观察一下源数据
可以看到后三行应该为数字的格式
所以:
1.把后三行转变为数字类型中浮点格式
#字符串转换为数值(浮点型)
salesDf['销售数量'] = salesDf['销售数量'].astype('float')
salesDf['应收金额'] = salesDf['应收金额'].astype('float')
salesDf['实收金额'] = salesDf['实收金额'].astype('float')
print('转换后的数据类型:\n',salesDf.dtypes)
2.销售时间这一列有两个重复的日期,2016-01-01和星期五,我们在后续的数据统计时只需要前面的日期就可以了,所以要想办法将2016-01-01留下,删除星期五
思路是:我们要将每一行的日期分隔开,在取第一列,就是这样的:
#测试:字符串分割
testList='2018-06-03 星期五'.split(' ')
testList[0]
成功分割第一行,但是一个严峻的问题出现了,我们要做的是把销售时间的这一列分割,像上面这么做只是分割了一行,难道要全部手动么?
如果出现这种反复机械的动作,我们可以直接考虑编写一个函数,让计算机来处理问题。
按照上面的字符串分割,取第一个的思路,我们可以写个如下的函数。
#定义函数:分割销售日期,获取销售日期
#输入: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]
OK,现在我们可以看到,函数发挥了它的作用,在几秒钟将一整列进行分割完毕。
接下来是替换:
#修改销售时间这一列的值
salesDf.loc[:,'销售时间']=dateSer
salesDf.head()
源数据已经按照我们的计划进行更改与清洗
分割好之后,继续我们刚刚的任务:为每一列改为我们需要的数据类型
我们将销售时间改为日期型:即将字符串改为日期型
#数据类型转换:字符串转换为日期
#errors='coerce' 如果原始数据不符合日期的格式,转换后的值为空值NaT
#format 是你原始数据中日期的格式
salesDf.loc[:,'销售时间']=pd.to_datetime(salesDf.loc[:,'销售时间'],
format='%Y-%m-%d',
errors='coerce')
salesDf.dtypes
我们会发现一个问题:如果转换的时候,有不符合我们转换规则的值,那就会直接转换为空值,而空值对于数据的影响很大,我们必须在清洗的时候即时清洗掉。
#删除销售时间与社保卡号中所有的空值
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
清洗掉空值之后,我们对于数据集开始排序,排序遵循:先打印排序前数据集–排序中即时打印看效果–排序后打印看结果
先打印排序前数据集:
print('排序前的数据集')
salesDf.head()
好,看到数据集头部基本确定数据集格式等没有问题,可以继续下一步排序
我们决定按常规排序方法,每一天的销售,按时间大小排序。
#按销售日期进行升序排列
salesDf=salesDf.sort_values(by='销售时间',
ascending=True)
#排序中段效果
salesDf.head(3)
我们打印出前三行,看看排序的效果如何:
可以的,数据按照我们的想法排好了,不过接着出现一个新问题,前面的序号被打乱了?
重新排列序号
#重新排列序号:重命名行名(index)
salesDf=salesDf.reset_index(drop=True)
salesDf.head()
最终结果
接着最后一步是使用出我们的绝招:描述!
描述是什么?是可以让你对于数据有一个迅速的了解,发现问题的超好用函数
#描述指标:查看出“销售数量”值不能小于0
salesDf.describe()
问题出现了,销售数量不可能为负,所以我们要对所有销售数量为负的数据进行处理。
这种在常理情况下不会出现的我们乘其为异常值
对于异常值我们最好的处理方法是删掉
#删除异常值:通过条件判断筛选出数据
#查询条件
querySer=salesDf.loc[:,'销售数量']>0
#应用查询条件
print('删除异常值前:',salesDf.shape)
salesDf=salesDf.loc[querySer,:]
print('删除异常值后:',salesDf.shape)
到这里基本清洗就告一段落了,数据已经变得整齐并且清晰,可以供我们接下来分析与绘图。下面讲一点分析的小技巧:
对于处理后的数据我们要先与业务人员来讨论,对于朝阳医院的数据,我们最关心的是问题是什么?这些问题对他们有什么帮助?
这里我列出几个业务指标
月均消费次数、月均消费金额、客单价
一、月均消费次数
月均消费次数=总消费次数/月份数
月均消费次数是业务人员很重视用来衡量每天我们医院客流量的指标,一个客人算一个客流量,那么就是说,一个人即使一天消费多次也只能算一次消费。
这样我们就可以用代码实现为:
逻辑为:每一天一个社保卡只能算一次消费:所以相同时间相同社保卡消费人数仅留一条,剩下删除。得到总消费次数
kpi1_Df=salesDf.drop_duplicates(subset=['销售时间', '社保卡号'])
#总消费次数:有多少行
totalI=kpi1_Df.shape[0]
print('总消费次数=',totalI)
接下来:将销售时间按照升序排序,重新对列进行排序,得到规整的时间序列表
用最大天数减去最小天数得到总天数,然后用总天数除以30,取整数部分以计算月份。得到月份数
用代码表示如下:
'''
计算月份数:时间范围
'''
#第1步:按销售时间升序排序
kpi1_Df=kpi1_Df.sort_values(by='销售时间',
ascending=True)
#重命名行名(index)
kpi1_Df=kpi1_Df.reset_index(drop=True)
#第2步:获取时间范围
#最小时间值
startTime=kpi1_Df.loc[0,'销售时间']
#最大时间值
endTime=kpi1_Df.loc[totalI-1,'销售时间']
#第3步:计算月份数
#天数
daysI=(endTime-startTime).days
#月份数: 运算符“//”表示取整除
#返回商的整数部分,例如9//2 输出结果是4
monthsI=daysI//30
print('月份数:',monthsI)
套用之前我们最开始定义业务指标的公式得到月均消费次数:
#业务指标1:月均消费次数=总消费次数 / 月份数
kpi1_I=totalI // monthsI
print('业务指标1:月均消费次数=',kpi1_I)
二、月均消费金额
月均消费金额是业务人员来预估每个月营收情况的一个基础指标
公式定义为:月均消费金额=总消费金额/月份数
逻辑为:用求和函数获得全年消费总金额,除以之前求出的月份数
#总消费金额
totalMoneyF=salesDf.loc[:,'实收金额'].sum()
#月均消费金额
monthMoneyF=totalMoneyF / monthsI
print('业务指标2:月均消费金额=',monthMoneyF)
三、客单价
客单价则是业务人员用来衡量人均购买力的硬性指标。
公式则是:客单价=总消费金额/总消费次数
'''
totalMoneyF:总消费金额
totalI:总消费次数
'''
pct=totalMoneyF / totalI
print('客单价:',pct)
数据清洗其实最需要的是练习,就多多练习,多找一些源数据来分析当脑中想到一个指标,就可以马上在Python中实现时,我们就完成了一个质的飞跃啦。
这篇现讲这么多,期待下一篇哈哈。