在数据分析时,用Python进行数据处理主要使用的两个包:Numpy、Pandas。Numpy包是数值编程工具:N维数组对象:ndarray,对数组结构数据进行运算(不用遍历循环),有随机数、线性代数、傅里叶变换等功能。Pandas包是基于Numpy构建,为数据分析而存在,有一维数组Series 和二维数组 Dataframe,可直接读取数据并做处理(高效简单),兼容各种数据库并支持各种分析算法。数据处理主要有一维的行或列,还有二维的行和列(类似EXCEL),Numpy和Pandas也有一维、二维数据,并且在Numpy的基础上的Pandas的一维数组Series 和二维数组 Dataframe可以更高效处理数据。主要将从一维数据开始,然后再到二维数据,再以一个数据分析的案例来学习数据分析的基本过程。
1、一维数据分析
1.1、一维数据分析:Numpy
1)、一维数组array的定义,可以使用到numpy.array()函数去设置。
#定义:一维数组array,参数传入的是一个列表[2,3,4,5,6,8,9]ar = np.array([2,3,4,5,6,8,9])print('输出数组ar:',ar) #输出数组arprint('数组ar的数据类型:',type(ar)) #数组ar的数据类型
生成结果:
2、查询使用使用索引位置下标。
生成结果:
查询的原理如下图:
3、切片访问:获取指定序号范围的元素。
#切片访问:获取指定序号范围的元素ar[1:3] #a[1:3]获取到的是序号从1到2的元素,他是一个左闭右开的区间print('ar[1:3]输出结果:',ar[1:3])
生成结果:
切片访问的原理如下图:
4、查看数据类型dtype。
生成结果:
5、统计计算。
print('ar内数据的平均值:',ar.mean()) #计算平均值print('ar内数据的标准差:',ar.std ()) #计算标准差print('ar内数据的方差:',ar.var()) #计算方差print('ar内数据的最大值:',ar.max()) #计算最大值print('ar内数据的最小值:',ar.min()) #计算最小值
生成结果:
6、向量化运行:乘以标量
生成结果:
1.2、一维数据分析:Pandas
1)、定义:Pandas一维数据结构:Series。
stockS=pd.Series([54.74,190.9,173.14,1050.3,181.86,1139.49], index=['腾讯', '阿里巴巴', '苹果', '谷歌', 'Facebook', '亚马逊']) #创建Seriesprint(stockS)
生成结果:
2)、获取描述统计信息。
3)、iloc属性用于根据索引获取值。
st0 = stockS.iloc[0] #按照整数的行位置进行索引print('输出stockS行号为0的数据:',st0)
生成结果:
4)、loc属性用于根据索引获取值。
生成结果:
5)、向量化运算:向量相加(根据标签自动对齐,)。
s1=pd.Series([1,2,3,4],index=['a','b','c','d'])s2=pd.Series([10,20,30,40],index=['a','b','e','f'])s3=s1 s2 #根据标签自动对齐,空值和任何值计算结果扔为空值print('输出s3的结果:\n',s3)
生成结果:
6)、处理缺失值:NaN
生成结果:
方法2:将缺失值进行填充
s3=s1.add(s2,fill_value=0)print('s1与s2进行向量相加时,出现缺失值直接补0,得到s3为:\n',s3)
生成结果:
2、二维数据分析
2.1、二维数据分析:Numpy
1)、二维数组array的定义,可以使用到numpy.array()函数去设置。
生成结果:
2)、索引与切片
#获取行号是0,列号是2的元素a[0,2]ar[0,2]#获取第1行ar[:,0]#获取第1列ar[0,:]print('输出ar[0,2]:',ar[0,2])print('获取第1行:',ar[:,0])print('获取第1列:',ar[0,:])
生成结果:
3)、Numpy数轴参数:axis,axis=0是列方向,axis=1是行方向。
生成结果:
2.2、Pandas二维数组:数据框(DataFrame)
1)、二维数组DataFrame的定义。
#第1步:定义一个有序的元组salesDict=( ('购药时间',['2018-01-01 星期五','2018-01-02 星期六','2018-01-06 星期三']), ('社保卡号',['001616528','001616528','0012602828']), ('商品编码',[236701,236701,236701]), ('商品名称',['强力VC银翘片','清热解毒口服液','感康']), ('销售数量',[6,1,2]), ('应收金额',[82.8,28,16.8]), ('实收金额',[69,24.64,15]))#导入有序字典from collections import OrderedDict#定义一个有序字典salesOrderDict=OrderedDict(salesDict)#定义数据框:传入字典,列名salesDf=pd.DataFrame(salesOrderDict)salesDf
生成结果:
2)、按每列或行来求值。
生成结果:
3)、 查询数据:iloc属性用于根据位置获取值
#查询第1行第2列的元素salesDf.iloc[0,1]#获取第1行,:代表所有列salesDf.iloc[0,:] #生成一个Series#获取第1列,:代表所有行salesDf.iloc[:,0] #生成一个Seriesprint('查询第1行第2列的元素:',salesDf.iloc[0,1])print('---------')print('获取第1行:\n',salesDf.iloc[0,:])print('---------')print('获取第1列:\n',salesDf.iloc[:,0])
生成结果:
4)、 查询数据:loc属性用于根据索引获取值。
生成结果:
#通过列表来选择某几列的数据salesDf[['商品名称','销售数量']]#通过切片功能,获取指定范围的列salesDf.loc[:,'购药时间':'销售数量']print('查看商品名称、销售数量数据:\n',salesDf[['商品名称','销售数量']])print('------------')print('查看购药时间到销售数量各列数据:\n',salesDf.loc[:,'购药时间':'销售数量'])
生成结果:
5)、条件判断
生成结果:
6)、 查看数据集描述统计信息
#读取Ecxcel数据import osos.chdir(r'D:\data3')fileNameStr='朝阳医院2018年销售数据.xlsx'xls = pd.ExcelFile(fileNameStr)salesDf = xls.parse('Sheet1')#打印出前3行,以确保数据运行正常salesDf.head(3)
生成结果:
生成结果:
#查看某一列的数据类型salesDf.loc[:,'销售数量'].dtype
生成结果:
生成结果:
3、案例:药店销售数据分析
数据分析的基本过程:1、 提出问题→2、理解数据→3、数据清洗→4、构建模型→5、数据可视化。
3.1、提出问题
可以从销售数据中分析出业务指标:
1)、月均消费次数;
2)、月均消费金额;
3)、客单价;
3.2、理解数据
1)、读取销售数据
import pandas as pdfileNameStr='D:/data3/朝阳医院2018年销售数据.xlsx'xls = pd.ExcelFile(fileNameStr)salesDf = xls.parse('Sheet1')
2)、查看数据基本信息
生成结果:
#有多少行,多少列salesDf.shape
生成结果:
即数据有6578行,7列。
生成结果:
3.3、数据清洗
数据清洗有6个基本步骤:1、选择子集;2、列名重命名;3、缺失数据处理;4、数据类型转换;5、数据排序;6、异常值处理。这次使用的数据列数字段较少,不需要选择子集。
1)、 列名重命名
colNameDict = {'购药时间':'销售时间'} #字典:旧列名和新列名对应关系salesDf.rename(columns = colNameDict,inplace=True) #在原表上将购药时间列名改为销售时间salesDf.head()
生成结果:
2)、 缺失数据处理
python缺失值有3种:1、Python内置的None值;2、在pandas中,将缺失值表示为NA,表示不可用not available;3、对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。
生成结果:
3)、数据类型转换
从数据上看,销售时间是一个文本形式的数据,需要将数据转换为日期数据类型。销售时间一列的数据 是以空格分开一个标准日期和一个星期几的格式,需要编写一个函数,分割销售日期的前一分部,获取销售日期。
def splitSaletime(timeColSer): timeList=[] #自建一个空列表,将处理完的数据存入 for value in timeColSer: dateStr=value.split(' ')[0] #例如2018-01-01 星期五,分割后为:2018-01-01 timeList.append(dateStr) #将分割后的日期格式存入空列表 timeSer=pd.Series(timeList) #将列表转行为一维数据Series类型 return timeSer
使用定义好的splitSaletime函数处理“销售时间”这一列的数据。
生成结果:
将“销售时间”这一列的数据修改为处理好的“dateSer”数据。
salesDf.loc[:,'销售时间']=dateSer #修改销售时间这一列的值salesDf.head() #查看处理的结果
生成结果:
因为“销售时间”这一列数据类型还是属于字符类型,需要转化为时间类型。
生成结果:
因为在“销售时间”转化为时间类型时,会有空值产生。还有“社保卡号”这一列也不能这空值,所以要将“销售时间”、“社保卡号”这一列出现空值的行删除。
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any') #删除列(销售时间,社保卡号)中为空的行salesDf.shape #查看处理后的数据行数与列数
生成结果:
4)、 数据排序
从数据上看,以时间为维度可以对“销售时间”排序,并且排序后由于行名会有变化,所以重名行名(index).
生成结果:
5)、异常值处理
从数据上看,销售数量是关联到应收金额、实收金额,首先销售数量不能小于0,先简单查看数据的统计情况。
salesDf.describe() #查看每列的统计值
生成结果:
删除异常值:通过条件判断筛选出数据。
生成结果:
3.4、构建模型
1)、 月均消费次数=总消费次数 / 月份数;
其中对于消费次数的定义再细化:同一天内,同一个人发生的所有消费应该是算做一次消费。从数据的计算实现来操作,可以根据”销售时间“和”社区卡号“,两列值只取唯一值,也就是如果两值同时相同,就只保留1条,将重复的删除。
kpi1_Df=salesDf.drop_duplicates(subset=['销售时间', '社保卡号'])totalI=kpi1_Df.shape[0] #获取行数,即是总消费次数print('总消费次数=',totalI)
生成结果:
月份数的计算,通过对销售时间排序,得到最小时间与最大时间,再用最大时间减最小时间并整除30(简化计算),最终得到月份数。
生成结果:
#第2步:获取时间范围startTime=kpi1_Df.loc[0,'销售时间'] #最小时间值endTime=kpi1_Df.loc[totalI-1,'销售时间'] #最大时间值#第3步:计算月份数daysI=(endTime-startTime).days #天数monthsI=daysI//30 #月份数print('月份数:',monthsI)
生成结果:
生成结果:
2)、月均消费金额 = 总消费金额 / 月份数;
其中月份数计算出来,现在要计算的是总消费金额,只要对”实收金额“这一列相加就可以获得总消费金额。
totalMoneyF=salesDf.loc[:,'实收金额'].sum() #总消费金额monthMoneyF=totalMoneyF / monthsI #月均消费金额print('业务指标2:月均消费金额=%.2f'%(monthMoneyF))
生成结果:
3)、 客单价=总消费金额 / 总消费次数
其中总消费金额和总消费次数在前面的计算过程已有,直接调用就可以。即totalMoneyF是总消费金额,totalI是总消费次数。
生成结果:
由此得到几点:
1、数据分析有一个基本的套路:1)、提出问题;2)、理解数据;3)、数据清洗;4)、构建模型;5)、数据可视化(待续)。
2、数据清洁的基本过程:1)、选择子集;2)、列名重命名;3)、缺失数据处理;4)、数据类型转换;5)、数据排序;6)、异常值处理。
联系客服