- 本文参考《python数据分析与挖掘实战》
- 数据集链接,密码1234
- 《python数据分析与挖掘实战》pdf链接,密码1234
引言
数据挖掘的基本任务包括利用分类与预测、聚类分析、关联规则、时序模式、偏差检测、智能推荐等方法,帮助企业提取数据中蕴含的商业价值,提高企业的竞争力。
对于餐饮企业来说,数据挖掘的基本任务就是从餐饮企业采集各类菜品销量、成本单价、会员消费、促销活动等内部数据,以及天气、节假日、竞争对手及周边商业氛围等外部数据,利用数据挖掘手段,实现菜品只能推荐、促销效果分析、客户价值分析、新店选点优化、热销/滞销菜品分析和销量趋势预测,最后将这些结果推送给企业管理人员,实现精准营销。本文主要是以餐饮行业数据为例,展示数据探索(EDA)的一般流程。
一、前期准备
这一部分主要包括:
- 目标定义
- 任务理解
- 指标确定
指标的确定是建立在目标定义与任务理解上的
1.目标定义与任务理解
针对数据挖掘应用需求,你首先就得要先明确挖掘的目标是什么(你想干什么),即系统完成后能达到什么效果。针对餐饮行业的数据挖掘,可定下如下挖掘目标:
- 实现动态菜品智能推荐,不仅推荐给顾客感兴趣的菜,同时这些菜品也符合餐饮行业最大收益。
- 对餐饮客户进行细分,对不同价值的客户采取不同的营销策略,实现精准化营销。
- 基于菜品销售情况及其他因素,对菜品的销量进行预测,方便准备原材料
- 基于餐饮大数据,优化新店选址,并对新店潜在客户的口味偏好进行分析,以便及时调整菜式。
二、数据采集与抽样
在明确挖掘目标后,如果数据量巨大,需要从业务系统中抽取一个与挖掘目标相关的样本子集,而不是动用全部的企业数据。进行数据取样时,一定要严把质量关。
衡量取样数据质量的标准包括:
- 资料完整无缺,各项指标齐全
- 数据准确无误,反映的都是正常(而不是异常)状态下的水平
注意: 若从正在运行的系统中抽取时,尤其需要数据的完整性与有效性
抽样的方式有以下几种:
- 随机抽样
- 等距抽样
- 分层抽样
首先将样本总体分成若干个层次,每个层次中的观测值都有相同的概率被选中,但不同的层次可以设定不同的概率 - 按起始顺序抽样
- 分类抽样
依据某种属性的取值来选择数据子集
三、数据探索
通过检验数据集的数据质量、绘制图表、计量某些特征量等手段,对样本数据集的结构和规律进行分析的过程就是数据探索。数据探索有助于选择合适的数据预处理和建模方法。数据探索主要是想弄清一下问题:
- 样本数据集的数量与质量是否满足模型构建的要求?
- 有没有明显的规律与趋势?
- 有没有出现从未设想过的数据状态?
- 属性之间有什么相关性?
- 它可以分成什么样的类别?
接下来将从数据质量分析与数据特征分析两方面来对数据进行探索
1.数据质量分析
数据质量分析的主要任务是检查原始数据中是否存在脏数据。脏数据包括缺失值、异常值、不一致的值、重复数据以及含有特殊符号(如#、¥、*)的数据。本节对数据的缺失值、异常值和一致性进行分析。
1.1缺失值分析
数据的缺失主要包括记录的缺失和记录中某个字段信息的缺失。对缺失值的分析,可以使用简单的统计分析,得到含有缺失值的属性的个数以及每个属性的未缺失数、缺失数与缺失率。
缺失值产生的原因:
- 有些信息暂时无法获取或者获取代价太大
- 有些信息被遗漏
- 属性不存在,在某些情况下,缺失值并不意味着数据有错误,对一些对象来说,属性是不存在的,即缺失本身就是一种状态。
1.1.1缺失值可视化
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as mg
cat_sale = pd.read_csv('data/catering_sale.csv',header=0,index_col=0,encoding='gbk') # 餐饮数据
# 缺失可视化
mg.matrix(cat_sale)
1.1.2描述性统计
# 描述性统计
cat_sale.describe()
len(cat_sale)
# 201
其中count是非空值的个数,与len
相比少1,则缺失数目为1。
# 给出样本数据的相关信息概览 :行数,列数,列索引,列非空值个数,列类型,内存占用
cat_sale.info()
201行200个非空值,则有1个空值。
1.1.3统计缺失数与缺失率
# 一个函数,统计每一列的缺失个数及缺失比例
def missing_percentage(df):
total = df.isnull().sum().sort_values(ascending=False)[df.isnull().sum().sort_values(ascending=False) != 0]
percent = round(total * 100 / len(df),2)
return pd.concat([total,percent],axis=1,keys=['Total','Percentage'])
missing_percentage(cat_sale)
缺失率为0.5%
1.2异常值分析
异常值(离群点)是指样本中的个别值,其数值明显偏离其他观测值。重视异常值的出现,要分析其产生的可能原因,在建模时要正确处理异常值。异常值分析有以下三种方式:
- 简单的统计分析
简单的对数据做一个描述性统计describe()
,可以查看是否存在异常值数据。最常用的统计量是最大值
与最小值
,用来判断这个变量的取值是否超出了合理范围。 - 3σ原则
如果数据服从正态分布,在3σ
原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值。
如果数据不服从正态分布,也可以用远离平均值的标准差倍数来描述 - 箱型图提供了识别异常值的一个标准:异常值被定义为小于 Q L − 1.5 I Q R Q_L-1.5IQR QL−1.5IQR或大于 Q U + 1.5 I Q R Q_U+1.5IQR QU+1.5IQR的值。其中 Q L Q_L QL是下四分位数, Q U Q_U QU是上四分位数, I Q R = Q U − Q L IQR=Q_U-Q_L IQR=QU−QL包含了全部观测值的一半。
1.2.1 3σ原则
据图发现,数据不服从正态分布,不建议使用3σ
原则
1.2.2箱型图分析
# 箱型图分析
# 解决中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号问题
plt.rcParams['axes.unicode_minus'] = False
p = cat_sale.boxplot(return_type='dict')
# 获得异常点的x,y
x = p['fliers'][0].get_xdata()
y = p['fliers'][0].get_ydata()
y.sort() # 处理异常点接近的情况
print(x)
# 对异常点进行注释-annotate,某些相近的点注释会出现重叠,需要来控制位置
for i in range(len(x)):
# 发现有异常点接近的情况,分情况讨论
if i > 0:
plt.annotate(y[i],xy=(x[i],y[i]),xytext=(x[i] +0.05 - 0.8 /(y[i]-y[i-1]),y[i]))
else:
plt.annotate(y[i],xy=(x[i],y[i]),xytext=(x[i] +0.08,y[i]))
通过异常值分析,可以确定过滤规则,在数据预处理当中,编写过滤程序。
1.3一致性分析
在数据挖掘过程中,不一致数据的产生主要发生在数据集成的过程中,可能是由于被挖掘数据来自于不同的数据源,对于重复存放的数据未能进行一致性更新造成的。
1.4重复数据处理
获取的数据中可能存在重复数据,一般是进行删除,pandas中对应drop_duplicates
方法,其中duplicated
方法可以检查数据是否有重复。
具体可见删除重复值
发现有两个重复值,但是这里只是销量相同,索引是日期,日期是不同的,根据常理,不应该删除。
2.数据特征分析
通过绘制图表,计算某些特征量等进行数据特征分析
2.1分布分析
分布分析能揭示数据的分布特征和分布类型。对于定量数据,可以做出频率分布表,绘制频率分布直方图、绘制茎叶图进行直观分析;对于定性数据,可以用饼图和条形图直观的显示分布情况。
2.1.1定量数据的分布分析
对于定量数据而言,绘制频率分布直方图选择“组数”和“组宽”是最主要的问题。一般按照以下步骤进行:
- 第一步: 求极差
- 第二步:决定组距与组数
- 第三步:决定分点
- 第四步:列出频率分布表
- 第五步:绘制频率分布直方图
以“捞起生鱼片”在2014年第二个季度的销售数据为例,
cat_fish_sale = pd.read_excel('data/catering_fish_congee.xls',index_col=0,header=None,names=['date','sale'],encoding='gbk')
- 求极差与确定组距与组数
- 列出频率分布表与绘制频率分布直方图
# 对数据进行分箱
bins = [0,500,1000,1500,2000,2500,3000,3500,4000] # 分位点
labels = ['[0,500)','[500,1000)','[1000,1500)','[1500,2000)','[2000,2500)','[2500,3000)','[3000,3500)','[3500,4000)'] # 箱名
cat_fish_sale['sale分箱']=pd.cut(cat_fish_sale.sale,bins,labels=labels)
# 聚合统计每一个箱的数量
aggResult = cat_fish_sale.groupby(by='sale分箱')['sale'].size()
# aggResult = cat_fish_sale.groupby(by='sale分箱')['sale'].agg(np.size) # agg函数常与groupby一起使用,传入自己的聚合函数
paggResult = round(aggResult / aggResult.sum(),2) * 100
plt.figure(figsize=(10,8))
paggResult.plot(label='sale',color='k',alpha=0.5,kind='bar',grid=True)
plt.title('季度销售频率直方图',fontsize=20)
plt.legend(loc='upper right')
2.1.1定性数据的分布分析
对于定性变量,常根据变量的分类类型来分组,可以采用饼图和条形图来描述定性变量的分布。
以不同菜品在某段时间内的销售量分布为例,
- 饼图
饼图的每一部分代表每一个类型的所占百分比或频数,根据定性变量的类型数目将饼图分成几部分,每一部分的大小与每一类型的频数成正比
cat_dish_profit = pd.read_excel('data/catering_dish_profit.xls',header=0,index_col=0)
cat_dish_profit
# 饼图
x = cat_dish_profit['盈利']
labels = cat_dish_profit['菜品名']
plt.figure(figsize=(8,6))
plt.pie(x, # 数据
labels=labels, # 标签
startangle=90 # 旋转角度
)
plt.title('菜品销量分布饼图',fontsize=20)
plt.axis('equal') # 通过改变轴的限制来设置相等的缩放(例如,让圆变成圆)
# https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html?highlight=axis#matplotlib.pyplot.axis
- 条形图
条形图的高度代表每一类型的百分比或频数,宽度没有意义
# 条形图
x = cat_dish_profit['菜品名']
y = cat_dish_profit['盈利']
plt.figure(figsize=(8,8))
plt.bar(x,y)
plt.xlabel('菜品',fontsize=20)
plt.ylabel('销售量',fontsize=20)
plt.title('菜品的销量分布(条形图)',fontsize=20)
2.2 对比分析
对比分析是将两个相互联系的指标进行比较,从数量上展示和说明。常用于指标间的横纵向比较、时间序列的比较分析。在对比分析中,选择合适的对比标准才能得到正确的结论。
2.2.1 绝对数比较
利用绝对数进行对比,从而寻找差异
如上图,它们之间的大小关系就是通过绝对数来表现的。
2.2.2 相对数比较
它是由两个有联系的指标对比计算的,是用以反映客观现象之间数量联系程度的综合指标。由于研究目的和对比基础不同,相对数可以分为以下几种:
- 结构相对数
将同一总体内的部分数值与全部数值进行对比求得比重,用以说明事物结构,如产品合格率 - 比例相对数
将同一总体内不同部分的数值进行对比,表明总体内各部分的比例关系,比如人口性别比例 - 比较相对数
将同一时期两个性质相同的指标数值进行对比,说明同类现象在不同空间条件下的数量对比关系。比如:不同地区的商品价格对比 - 强度相对数
将同一时期两个性质不同但有一定联系的总量指标进行对比,用以说明现象的强度、密度和普遍程度。比如:人均国内生产总值 - 计划完成程度相对数
将某一时期实际完成数与计划数进行对比,用以说明计划完成程度 - 动态相对数
将同一现象在不同时期的指标数值进行对比,用以说明发展方向和变化速度。比如:发展速度
以各部门的销售数据为例,利用比较相对数与动态相对数来比较,可以发现在此期间哪个部门的销售金额较高以及趋势变化
cat_dish_sale = pd.read_excel('data/dish_sale.xls',index_col=0) # 各部门的销售数据
# 比较相对数与动态相对数
plt.figure(figsize=(8,8))
plt.plot(cat_dish_sale.index,cat_dish_sale['A部门'],'ko-',label='A部门')
plt.plot(cat_dish_sale.index,cat_dish_sale['B部门'],'r*--',label='B部门')
plt.plot(cat_dish_sale.index,cat_dish_sale['C部门'],'bx-.',label='C部门')
plt.legend(loc='best')
plt.ylabel('销售额(万元)',fontsize=15)
plt.title('各部门销售额对比分析',fontsize=20)
以B部门各年份的销售数据为例,
plt.figure(figsize=(8,8))
plt.plot(cat_dish_b_sale.index,cat_dish_b_sale['2014年'],'ko-',label='2014年')
plt.plot(cat_dish_b_sale.index,cat_dish_b_sale['2013年'],'r*-',label='2013年')
plt.plot(cat_dish_b_sale.index,cat_dish_b_sale['2012年'],'bx-',label='2012年')
plt.legend(loc='best')
plt.xlabel('月份',fontsize=15)
plt.ylabel('销售额(万元)',fontsize=15)
plt.title('B部门不同年份销售额变化',fontsize=20)
通过分析发现:三个部门的销售额趋势都在递减;A部门与C部门递减趋势比较平稳,B部门销售额下降趋势比较明显。
2.3统计量分析
用统计指标对定量数据进行统计描述,常从集中趋势与离中趋势两个方面进行分析
2.3.1 集中趋势
平均水平指标是对个体集中趋势的度量,使用最广泛的是均值、中位数
- 为了反映在均值中不同成分的重要程度,可以使用加权均值
- 均值对极端值非常敏感,为了消除极端值对均值的影响,可以只用中位数或者截断均值来度量数据的集中趋势。截断均值是去掉高、低极端值之后的平均数。
2.3.2 离中趋势
离中趋势是对个体离开平均水平的度量,使用较广泛的是标准差(方差)、四分位间距。
- 极差对数据集的极端值非常敏感,并且忽略了数据分布
- 标准差度量数据偏离均值的程度
- 变异系数度量标准差相对于均值的离中趋势,变异系数主要用来比较两个或者多个具有不同单位或者不同波动幅度的数据集的离中趋势
- 四分位数间距即 I Q R = Q U − Q L IQR=Q_U-Q_L IQR=QU−QL包含了全部观测值的一半, Q L Q_L QL是下四分位数, Q U Q_U QU是上四分位数。该值越大,说明数据的变异程度越大
以餐饮销量统计量为例,
cat_sale = cat_sale[(cat_sale > 400) & (cat_sale < 5000)] # 过滤异常数据
statistics = cat_sale.describe()
statistics.loc['range'] = statistics.loc['max'] - statistics.loc['min'] # 极差
statistics.loc['var'] = statistics.loc['std'] / statistics.loc['mean'] # 变异系数
statistics.loc['dis'] = statistics.loc['75%'] - statistics.loc['25%'] # 四分位距
2.4 周期性分析
周期性分析是探索某个变量是否随时间的变化而呈现出的某种周期变化趋势。时间尺度长的周期性趋势有年度周期性趋势、季节性周期性趋势;时间尺度短的周期性趋势有月度周期性趋势、周度周期性趋势,甚至是天、小时周期性趋势
以某单位日用电量为例,
正常用户
df_normal = pd.read_csv('data/user.csv',index_col=0) # 日用电量
df_normal.head()
plt.figure(figsize=(8,8))
plt.plot(df_normal.index,df_normal['Eletricity'])
plt.xlabel("日期",fontsize=15)
# 设置x轴刻度间隔
x_major_locator = plt.MultipleLocator(7) # 每隔7个数设置
ax = plt.gca() # 获得当前轴
ax.xaxis.set_major_locator(x_major_locator)
plt.ylabel('每日电量',fontsize=15)
plt.title('正常用户电量趋势',fontsize=20)
窃电用户
df_steal = pd.read_csv('data/Steal user.csv',index_col=0)
plt.figure(figsize=(8,8))
plt.plot(df_steal.index,df_steal['Eletricity'])
plt.ylabel('电量',fontsize=15)
# 设置x轴间隔
x_major_locator = plt.MultipleLocator(7)
ax = plt.gca()
ax.xaxis.set_major_locator(x_major_locator)
plt.xlabel('月份',fontsize=15)
plt.title('窃电用户的电量趋势',fontsize=20)
正常用户与窃电用户用电量呈现周期性,以周为周期。窃电用户的日用电量呈现递减趋势。
2.5 贡献度分析
贡献度分析又称为帕累托分析,它的原理是帕累托法则,又称为2/8定律。同样的投入放在不同的地方会产生不同的效益。
以菜品盈利数据为例,
cat_dish_profit['盈利占比'] = round(cat_dish_profit['盈利'] / cat_dish_profit['盈利'].sum(),2)
cat_dish_profit['累计占比'] = cat_dish_profit['盈利占比'].cumsum()
plt.figure(figsize=(8,8))
cat_dish_profit['盈利'].plot(kind='bar')
plt.xlabel('菜品名',fontsize=15)
plt.ylabel('盈利(元)',fontsize=15)
cat_dish_profit['累计占比'].plot(style='ro-.',secondary_y=True,linewidth=2) # secondary_y=True设置双索引
plt.ylabel('盈利(比例)',fontsize=15)
# 添加注释
plt.annotate(format(cat_dish_profit['累计占比'][6],'.2%'), # 注释字符
xy=(6,cat_dish_profit['累计占比'][6]), # 要注释的位置
xytext=(6,cat_dish_profit['累计占比'][6] * 0.9), # 注释的位置
arrowprops =dict(arrowstyle="->", connectionstyle="arc3,rad=.2") # 指定箭头样式
)
2.6 相关性分析
分析连续变量之间线性相关程度的强弱,并用适当的统计指标表示出来的过程称为相关性分析。
2.6.1 绘制散点图
判断两个变量是否具有线性相关关系的最直观方法是绘制散点图。
seaborn中绘制散点图
2.6.2 绘制散点图矩阵
需要同时考察多个变量的相关关系时,可以利用散点图矩阵scatter_matrix
来同时绘制各变量间的散点图,从而快速发现多个变量间的相关性。
以鸢尾花数据集为例,
# 导入模块,注意第二个和第三个都需要
import pandas as pd
from pandas.plotting import scatter_matrix
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
iris_df = pd.DataFrame(X, columns=load_iris().feature_names)
# 下面这句是关键,scatter_matrix()方法
scatter_matrix(iris_df, c=y, figsize=(15, 15),
marker='o', hist_kwds={
'bins': 20},
s=60, alpha=.8)
plt.show()
这里只展示了散点图矩阵的画法,在回归问题中容易发现相关关系。
2.6.3 计算相关系数
可以使用相关系数来准确的描述变量之间的线性相关程度,比较常用的系数有Pearson
相关系数、Spearman
相关系数和判定系数
Pearson
线性相关系数要求连续变量的取值服从正态分布
,Pearson
线性相关系数只有在两个变量具有线性关系时才是完全相关的- 对于不服从正态分布的变量、分类或等级变量之间可采用
Spearman
相关系数,只要两个变量具有严格单调的函数关系就是完全Spearman
相关 - 判定系数是相关系数的平方,用 r 2 r^2 r2表示
r 2 r^2 r2越接近于1,表明 x x x和 y y y之间的相关性越强; r 2 r^2 r2越接近于0,表明两个变量之间几乎没有直线相关关系。
以不同菜品的日销售量为例,通过分析菜品日销售量之间的相关性得到不同菜品之间的相关关系,如替补菜品、互补菜品、没有关系
cat_sale_all = pd.read_excel('data/catering_sale_all.xls',index_col=0) # 不同菜品的日销售量数据
cat_sale_all.head()
cat_sale_all.corr() # 相关系数矩阵
# 显示百合酱蒸凤爪与其他菜品的相关关系
cat_sale_all.corr()['百合酱蒸凤爪']
从相关系数可以看出:有些菜品之间是互补菜品,有些菜品之间是完全没有关系的。
如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论留言!