数据分析的步骤:提出问题→理解数据→数据清洗→构建模型→数据可视化
目标数据:2018年朝阳医院销售数据.xlsx
业务部门下发了一项业务分析目标,把数据发给我的时候就在思考该怎么分析,接下来一起探讨怎么进行简单的数据分析
一、提出业务指标问题
从销售数据中分析下面的业务指标问题:
(1)月均消费次数
(2)月均消费金额
(3)客单价
(4)消费趋势
导入所需要的包
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
import pandas as pd
import numpy as np
将销售Ecxcel数据导入到python中
fileNameStr='E:\\2018python\朝阳医院2018年销售数据.xlsx'
xls=pd.ExcelFile(fileNameStr,dtype='object')
salesDf = xls.parse('Sheet1',dtype='object')
查看前五行数据
salesDf.head()
查看表格数据的行数和列数
salesDf.shape
(6578, 7)
可以查看到数据有6578行,7列。
查看列的数据类型
salesDf.dtypes
购药时间 object
社保卡号 object
商品编码 object
商品名称 object
销售数量 object
应收金额 object
实收金额 object
dtype: object
二、数据清洗(数据预处理)
数据预处理主要有以下步骤:
(1)选择子集
(2)列名重命名
(3)删除缺失数据
(4)数据类型转换
(5)数据排序
(6)异常值处理
1.选择子集
本案例子集不用选择子集,需要的子集已经存在
2.列名重命名
salesDf.rename(columns ={'购药时间':'销售时间'},inplace=True) #inplace=True,数据框本身会改动
salesDf.head()
3. 删除缺失数据
删除列(销售时间,社保卡号)中为空的行,使用dropna删除缺失数据
print('删除缺失值前大小',salesDf.shape)
#how='any' 给定的任何一列中有缺失值就删除
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失后大小',salesDf.shape)
删除缺失值前大小 (6578, 7)
删除缺失后大小 (6575, 7)
在删除缺失数据之前有6578行,删除缺失的数据之后是6575行
4. 数据类型转换
将字符串转换为浮点型数值
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
日期列字符串转换为日期数据类型
#测试:字符串分割
testList='2018-06-03 星期五'.split(' ')
testList
['2018-06-03', '星期五']
testList[0]
'2018-06-03'
分割时间列,定义函数:分割销售日期,获取销售日期
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()
数据类型转换:字符串转换为日期
salesDf.loc[:,'销售时间']=pd.to_datetime(salesDf.loc[:,'销售时间'],
format='%Y-%m-%d', errors='coerce')
salesDf.dtypes
销售时间 datetime64[ns]
社保卡号 object
商品编码 object
商品名称 object
销售数量 float64
应收金额 float64
实收金额 float64
dtype: object
转换日期过程中不符合日期格式的数值会被转换为空值,
这里删除列(销售时间,社保卡号)中为空的行
salesDf=salesDf.dropna(subset=['销售时间','社保卡号'],how='any')
5. 数据排序
使用sort_values进行排序,by:按哪几列排序,ascending=True 表示升序排列,ascending=False表示降序排列
#按销售时间进行升序排列
salesDf=salesDf.sort_values(by='销售时间',ascending=True)
#查看排序后的前10行
salesDf.head(10)
重命名行名(index),使用reset_index修改成从0到N按顺序排序的索引值index
salesDf=salesDf.reset_index(drop=True)
salesDf.head(6)
6. 异常值处理
查看汇总数据描述,其中销售数量值不能小于0
salesDf.describe()
通过条件判断来删除异常值
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=kpi1_Df.reset_index(drop=True)
kpi1_Df.head()
计算总月份数,第一行时间与结尾时间之差除以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.消费趋势图
指标5:消费趋势画图
#在进行操作之前,先把数据复制到另一个数据框中,防止对之前清洗后的数据框造成影响
groupDf=salesDf
#第1步:重命名行名(index)为销售时间所在列的值
groupDf.index=groupDf['销售时间']
groupDf.head()
分组
gb=groupDf.groupby(groupDf.index.month)
gb
<pandas.core.groupby.DataFrameGroupBy object at 0x000000000ED4CC18>
#第3步:应用函数,计算每个月的消费总额
mounthDf=gb.sum()
mounthDf
选取每个月的应收金额和实收金额的消费总额
mounthDf=DataFrame(mounthDf,columns=['应收金额','实收金额'])
mounthDf
6.数据可视化
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei'] #防止中文乱码
mounthDf.plot(title='2018年朝阳医院数据消费金额趋势图',figsize=(15,8),fontsize=20)
以上可以看出第1月和第七月消费总金额是最高的,在第七月消费金额最低。
医药销售量和天气变化有一定的影响,尤其在冬季天气寒冷和初春季节,容易受到天气影响,气温变化大,市民容易感冒,从而在医药行业销售更多了医药,销售量上升,在气温平稳时期销售量下降。
总之,医药销售金额会受到当地天气和环境等因素的影响。
dropna函数详细使用地址:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html
本次练习学习基本知识,了解到简单的数据分析过程。