对数据进行质量分析以后,接下来可通过绘制图表、计算某些特征量等手段进行数据的特征分析。
分布分析能揭示数据的分布特征和分布类型。对于定量数据,要想了解其分布形式是对称的还是非对称的、发现某些特大或特小的可疑值,可做出频率分布表、绘制频率分布直方图、绘制茎叶图进行直观分析;对于定性数据,可用饼图和条形图直观地显示其分布情况。
对于定量变量而言,选择“组数”和“组宽”是做频率分布分析时最主要的问题,一般按照以下步骤进行:
第一步:求极差。
第二步:决定组距与组数。
第三步:决定分点。
第四步:列出频率分布表。
第五步:绘制频率分布直方图。
遵循的主要原则如下:
1)各组之间必须是相互排斥的。
2)各组必须将所有的数据包含在内。
3)各组的组宽最好相等。
下面结合具体实例来运用分布分析对定量数据进行特征分析。
表3-2是菜品“捞起生鱼片”在2014年第二个季度的销售数据,绘制销售量的频率分布表、频率分布图,对该定量数据做出相应的分析。
表3-2 “捞起生鱼片”的销售情况
*数据详见:demo/data/catering_fish_congee.xls。
(1)求极差
(2)分组
这里根据业务数据的含义,可取组距为500,则组数如式(3-2)所示。
(3)决定分点
分布区间如表3-3所示。
表3-3 分布区间
(4)绘制频率分布直方表
根据分组区间得到如表3-4所示的频率分布表。其中,第1列将数据所在的范围分成若干组段,其中第1个组段要包括最小值,最后一个组段要包括最大值。习惯上将各组段设为左闭右开的半开区间,如第一个组段为[0,500)。第2列组中值是各组段的代表值,由本组段的上限值和下限值相加除以2得到。第3列和第4列分别为频数和频率。第5列是累计频率,是否需要计算该列数值视情况而定。
表3-4 频率分布
(5)绘制频率分布直方图
若以2014年第二季度“捞起生鱼片”这道菜每天的销售额组段为横轴,以各组段的频率密度(频率与组距之比)为纵轴,表3-4中的数据可绘制成频率分布直方图,如代码清单3-3所示。
代码清单3-3 “捞起生鱼片”的季度销售情况
import pandas as pd import numpy as np catering_sale = '../data/catering_fish_congee.xls' # 餐饮数据 data = pd.read_excel(catering_sale,names=['date','sale']) # 读取数据,指定“日期” 列为索引 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)'] data['sale分层'] = pd.cut(data.sale, bins, labels=labels) aggResult = data.groupby(by=['sale分层'])['sale'].agg({'sale': np.size}) pAggResult = round(aggResult/aggResult.sum(), 2, ) * 100 import matplotlib.pyplot as plt plt.figure(figsize=(10,6)) # 设置图框大小尺寸 pAggResult['sale'].plot(kind='bar',width=0.8,fontsize=10) # 绘制频率直方图 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.title('季度销售额频率分布直方图',fontsize=20) plt.show()
*代码详见:demo/code/feature_check.py。
运行代码清单3-3可得季度销售额频率分布直方图,如图3-3所示。
图3-3 季度销售额频率分布直方图
对于定性变量,常常根据变量的分类类型来分组,可以采用饼图和条形图来描述定性变量的分布,如代码清单3-4所示。
代码清单3-4 不同菜品在某段时间的销售量分布情况
import pandas as pd import matplotlib.pyplot as plt catering_dish_profit = '../data/catering_dish_profit.xls' # 餐饮数据 data = pd.read_excel(catering_dish_profit) # 读取数据,指定“日期”列 为索引 # 绘制饼图 x = data['盈利'] labels = data['菜品名'] plt.figure(figsize=(8, 6)) # 设置画布大小 plt.pie(x,labels=labels) # 绘制饼图 plt.rcParams['font.sans-serif'] = 'SimHei' plt.title('菜品销售量分布(饼图)') # 设置标题 plt.axis('equal') plt.show() # 绘制条形图 x = data['菜品名'] y = data['盈利'] plt.figure(figsize=(8, 4)) # 设置画布大小 plt.bar(x,y) plt.rcParams['font.sans-serif'] = 'SimHei' plt.xlabel('菜品') # 设置x轴标题 plt.ylabel('销量') # 设置y轴标题 plt.title('菜品销售量分布(条形图)') # 设置标题 plt.show() # 展示图片
*代码详见:demo/code/feature_check.py。
图3-4 菜品销售量分布(饼图)
饼图的每一个扇形部分代表每一类型的所占百分比或频数,根据定性变量的类型数目将饼图分成几个部分,每一部分的大小与每一类型的频数成正比;条形图的高度代表每一类型的百分比或频数,条形图的宽度没有意义。
运行代码清单3-4可得不同菜品在某段时间的销售量分布图,如图3-4和图3-5所示。
对比分析是指把两个相互联系的指标进行比较,从数量上展示和说明研究对象规模的大小、水平的高低、速度的快慢以及各种关系是否协调。特别适用于指标间的横纵向比较、时间序列的比较分析。在对比分析中,选择合适的对比标准是十分关键的,选得合适,才能做出客观评价,选得不合适,评价后可能得出错误的结论。
对比分析主要有以下两种形式:
它是利用绝对数进行对比,从而寻找差异的一种方法。
图3-5 菜品的销售量分布(条形图)
它是由两个有联系的指标对比计算的,是用以反映客观现象之间数量联系程度的综合指标,其数值表现为相对数。由于研究目的和对比基础不同,相对数可以分为以下几种:
1)结构相对数:将同一总体内的部分数值与全部数值进行对比求得比重,用以说明事物的性质、结构或质量,如居民食品支出额占消费支出总额的比重、产品合格率等。
2)比例相对数:将同一总体内不同部分的数值进行对比,表明总体内各部分的比例关系,如人口性别比例、投资与消费比例等。
3)比较相对数:将同一时期两个性质相同的指标数值进行对比,说明同类现象在不同空间条件下的数量对比关系,如不同地区的商品价格对比,不同行业、不同企业间的某项指标对比等。
4)强度相对数:将两个性质不同但有一定联系的总量指标进行对比,用以说明现象的强度、密度和普遍程度,如人均国内生产总值用“元/人”表示,人口密度用“人/平方公里”表示,也有用百分数或千分数表示的,如人口出生率用“‰”表示。
5)计划完成程度相对数:将某一时期实际完成数与计划数进行对比,用以说明计划完成程度。
6)动态相对数:将同一现象在不同时期的指标数值进行对比,用以说明发展方向和变化速度,如发展速度、增长速度等。
以各菜品的销售数据为例,从时间维度上分析,可以看到A部门、B部门、C部门3个部门的销售金额随时间的变化趋势,可以了解在此期间哪个部门的销售金额较高、趋势比较平稳,也可以从单一部门(B部门)做分析,了解各年份的销售对比情况,如代码清单3-5所示。
代码清单3-5 不同部门各月份的销售对比情况
# 部门之间销售金额比较 import pandas as pd import matplotlib.pyplot as plt data=pd.read_excel("../data/dish_sale.xls") plt.figure(figsize=(8, 4)) plt.plot(data['月份'], data['A部门'], color='green', label='A部门',marker='o') plt.plot(data['月份'], data['B部门'], color='red', label='B部门',marker='s') plt.plot(data['月份'], data['C部门'], color='skyblue', label='C部门',marker='x') plt.legend() # 显示图例 plt.ylabel('销售额(万元)') plt.show() # B部门各年份之间销售金额的比较 data=pd.read_excel("../data/dish_sale_b.xls") plt.figure(figsize=(8, 4)) plt.plot(data['月份'], data['2012年'], color='green', label='2012年',marker='o') plt.plot(data['月份'], data['2013年'], color='red', label='2013年',marker='s') plt.plot(data['月份'], data['2014年'], color='skyblue', label='2014年', marker='x') plt.legend() # 显示图例 plt.ylabel('销售额(万元)') plt.show()
*代码详见:demo/code/feature_check.py。
运行代码清单3-5可得3个部门的销售金额随时间的变化趋势,以及B部门在不同年份的销售额随时间的变化趋势,如图3-6与图3-7所示。
图3-6 3部门之间销售额的比较
图3-7 B部门各年份销售额的比较
总体来看,3个部门的销售额呈递减趋势;A部门和C部门的递减趋势比较平稳;B部门的销售额下降趋势比较明显,进一步分析造成这种现象的原因,可能是原材料不足。
用统计指标对定量数据进行统计描述,常从集中趋势和离中趋势两个方面进行分析。
平均水平指标是对个体集中趋势的度量,使用最广泛的是均值和中位数;反映变异程度的指标则是对个体离开平均水平的度量,使用较广泛的是标准差(方差)、四分位间距。
(1)均值
均值是所有数据的平均值。
如果求n个原始观察数据的平均数,计算公式如式(3-3)所示。
有时,为了反映在均值中不同成分的重要程度,为数据集中的每一个x i 赋予w i ,这就得到了式(3-4)所示的加权均值的计算公式。
类似地,频率分布表(见表3-4)的平均数可以使用式(3-5)计算。
式中,x 1 ,x 2 ,…,x k 分别为k个组段的组中值,f 1 ,f 2 ,…,f k 分别为k个组段的频率。这里的f i 起权重作用。
作为一个统计量,均值对极端值很敏感。如果数据中存在极端值或者数据是偏态分布的,那么均值就不能很好地度量数据的集中趋势。为了消除少数极端值的影响,可以使用截断均值或者中位数来度量数据的集中趋势。截断均值是去掉高、低极端值之后的平均数。
(2)中位数
中位数是将一组观察值从小到大按顺序排列,位于中间的那个数据。即在全部数据中,小于和大于中位数的数据个数相等。
将某一数据集x:{x 1 ,x 2 ,…,x n }按从小到大的排序{x 1 ,x 2 ,…,x n },当n为奇数时,中位数的计算公式如式(3-6)所示;当n为偶数时,中位数的计算公式如式(3-7)所示。
(3)众数
众数是指数据集中出现最频繁的值。众数并不经常用来度量定性变量的中心位置,更适用于定性变量。众数不具有唯一性。当然,众数一般用于离散型变量而非连续型变量。
(1)极差
极差对数据集的极端值非常敏感,并且忽略了位于最大值与最小值之间的数据是如何分布的。
(2)标准差
标准差度量数据偏离均值的程度,计算公式如式(3-9)所示。
(3)变异系数
变异系数度量标准差相对于均值的离中趋势,计算公式如式(3-10)所示。
变异系数主要用来比较两个或多个具有不同单位或不同波动幅度的数据集的离中趋势。
(4)四分位数间距
四分位数包括上四分位数和下四分位数。将所有数值由小到大排列并分成4等份,处于第一个分割点位置的数值是下四分位数,处于第二个分割点位置(中间位置)的数值是中位数,处于第三个分割点位置的数值是上四分位数。
四分位数间距是指上四分位数Q U 与下四分位数Q L 之差,其间包含了全部观察值的一半。其值越大,说明数据的变异程度越大;反之,说明变异程度越小。
前面已经提过,DataFrame对象的describe()方法已经可以给出一些基本的统计量,根据给出的统计量,可以衍生出我们所需要的统计量。针对餐饮销量数据进行统计量分析,如代码清单3-6所示。
代码清单3-6 餐饮销量数据统计量分析
# 餐饮销量数据统计量分析 import pandas as pd catering_sale = '../data/catering_sale.xls' # 餐饮数据 data = pd.read_excel(catering_sale, index_col='日期') # 读取数据,指定“日期”列 为索引列 data = data[(data['销量'] > 400)&(data['销量'] < 5000)] # 过滤异常数据 statistics = data.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%'] # 四分位数间距 print(statistics)
*代码详见:demo/code/feature_check.py。
运行代码清单3-6可以得到下面的结果,即为餐饮销量数据统计量情况。
销量 count 195.000000 mean 2744.595385 std 424.739407 min 865.000000 25% 2460.600000 50% 2655.900000 75% 3023.200000 max 4065.200000 range 3200.200000 var 0.154755 dis 562.600000
周期性分析是探索某个变量是否随着时间的变化而呈现出某种周期变化趋势。时间尺度相对较长的周期性趋势有年度周期性趋势、季节性周期性趋势;时间尺度相对较短的有月度周期性趋势、周度周期性趋势,甚至更短的天、小时周期性趋势。
例如,要对正常用户和窃电用户在2012年2月份与3月份日用电量进行预测,可以分别分析正常用户和窃电用户的日用电量的时序图,来直观地估计其用电量变化趋势,如代码清单3-7所示。
代码清单3-7 某单位日用电量预测分析
import pandas as pd import matplotlib.pyplot as plt df_normal = pd.read_csv("../data/user.csv") plt.figure(figsize=(8,4)) plt.plot(df_normal["Date"],df_normal["Eletricity"]) plt.xlabel("日期") # 设置x轴刻度间隔 x_major_locator = plt.MultipleLocator(7) ax = plt.gca() ax.xaxis.set_major_locator(x_major_locator) plt.ylabel("每日电量") plt.title("正常用户电量趋势") plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 # plt.axis('equal') plt.show() # 展示图片 # 窃电用户用电趋势分析 df_steal = pd.read_csv("../data/Steal user.csv") plt.figure(figsize=(10, 9)) plt.plot(df_steal["Date"],df_steal["Eletricity"]) plt.xlabel("日期") plt.ylabel("日期") # 设置x轴刻度间隔 x_major_locator = plt.MultipleLocator(7) ax = plt.gca() ax.xaxis.set_major_locator(x_major_locator) plt.title("窃电用户电量趋势") plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.show() # 展示图片
*代码详见:demo/code/feature_check.py。
运行代码清单3-7可得正常用户和窃电用户在2012年2月份与3月份日用电量的时序图,如图3-8和图3-9所示。
图3-8 正常用户在2012年2月份与3月份日用电量时序图
总体来看,正常用户和窃电用户在2012年2月份与3月份日用电量呈现出周期性,以周为周期,因为周末不上班,所以周末用电量较低。工作日和非工作日的用电量比较平稳,没有太大的波动。而窃电用户在2012年2月份与3月份日用电量呈现出递减趋势,同样周末的用电量是最低的。
贡献度分析又称帕累托分析,它的原理是帕累托法则,又称20/80定律。同样的投入放在不同的地方会产生不同的效益。例如,对一个公司来讲,80%的利润常常来自于20%最畅销的产品,而其他80%的产品只产生了20%的利润。
图3-9 窃电用户在2012年2月份与3月份日用电量时序图
就餐饮企业来讲,应用贡献度分析可以重点改善某菜系盈利最高的前80%的菜品,或者重点发展综合影响最高的80%的部门。这种结果可以通过帕累托图直观地呈现出来。图3-10是某个月中海鲜系列的10个菜品A1~A10的盈利额(已按照从大到小的顺序排序)。
由图3-10可知,菜品A1~A7共7个菜品,占菜品种类数的70%,总盈利额占该月盈利额的85.0033%。根据帕累托法则,应该增加对菜品A1~A7的成本投入,减少对菜品A8~A10的成本投入,以获得更高的盈利额。
表3-5是餐饮系统对应的菜品盈利数据,绘制菜品盈利帕累托图,如代码清单3-8所示。
图3-10 菜品盈利数据帕累托图
表3-5 餐饮系统菜品盈利数据
*数据详见:demo/data/catering_dish_profit.xls。
代码清单3-8 绘制菜品盈利数据帕累托图
# 菜品盈利数据帕累托图 import pandas as pd # 初始化参数 dish_profit = '../data/catering_dish_profit.xls' # 餐饮菜品盈利数据 data = pd.read_excel(dish_profit, index_col='菜品名') data = data['盈利'].copy() data.sort_values(ascending=False) import matplotlib.pyplot as plt # 导入图像库 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.figure() data.plot(kind='bar') plt.ylabel('盈利(元)') p = 1.0*data.cumsum()/data.sum() p.plot(color='r', secondary_y=True, style='-o',linewidth=2) plt.annotate(format(p[6], '.4%'), xy=(6, p[6]), xytext=(6*0.9, p[6]*0.9), arrow-props=dict(arrowstyle="->", connectionstyle="arc3,rad=.2")) # 添加注释,即85%处的标记。这里包括了指定箭头样式。 plt.ylabel('盈利(比例)') plt.show()
*代码详见:demo/code/feature_check.py。
分析连续变量之间线性相关程度的强弱,并用适当的统计指标表示出来的过程称为相关分析。
判断两个变量是否具有线性相关关系最直观的方法是直接绘制散点图,如图3-11所示。
图3-11 相关关系的散点图示例
需要同时考察多个变量间的相关关系时,一一绘制它们之间的简单散点图十分麻烦。此时可利用散点图矩阵来同时绘制各变量间的散点图,从而快速发现多个变量间的主要相关性,这在进行多元线性回归时显得尤为重要。
散点图矩阵示例如图3-12所示。
图3-12 散点图矩阵
为了更加准确地描述变量之间的线性相关程度,可以通过相关系数的计算来进行相关分析。在二元变量的相关分析过程中,比较常用的有Pearson相关系数、Spearman秩相关系数和判定系数。
(1)Pearson相关系数
Pearson相关系数一般用于分析两个连续性变量之间的关系,其计算公式如式(3-11)所示。
相关系数r的取值范围:-1≤r≤1。
0<|r|<1表示存在不同程度的线性相关。
(2)Spearman秩相关系数
Pearson线性相关系数要求连续变量的取值服从正态分布。不服从正态分布的变量、分类或等级变量之间的关联性可采用Spearman秩相关系数(也称等级相关系数)来描述。
其计算公式如式(3-12)所示。
对两个变量成对的取值分别按照从小到大(或者从大到小)的顺序编秩,R i 代表x i 的秩次,Q i 代表y i 的秩次,R i -Q i 为x i 、y i 的秩次之差。
表3-6给出一个变量x(x 1 ,x 2 ,…,x i ,…,x n )秩次的计算过程。
表3-6 秩次的计算过程
因为一个变量相同的取值必须有相同的秩次,所以在计算中采用的秩次是排序后所在位置的平均值。
只要两个变量具有严格单调的函数关系,那么它们就是完全Spearman相关的,这与Pearson相关不同,Pearson相关只有在变量具有线性关系时才是完全相关的。
上述两种相关系数在实际应用计算中都要对其进行假设检验,使用t检验方法检验其显著性水平以确定其相关程度。研究表明,在正态分布假定下,Spearman秩相关系数与Pearson相关系数在效率上是等价的,而对于连续测量数据,更适合用Pearson相关系数来进行分析。
(3)判定系数
判定系数是相关系数的平方,用r 2 表示,用来衡量回归方程对y的解释程度。判定系数的取值范围为0≤r 2 ≤1。r 2 越接近于1,表明x与y之间的相关性越强;r 2 越接近于0,越表明两个变量之间几乎没有直线相关关系。
利用餐饮管理系统可以统计得到不同菜品的日销量数据,数据示例如表3-7所示。
表3-7 菜品日销量数据
*数据详见:demo/data/catering_sale_all.xls。
分析这些菜品日销售量之间的相关性可以得到不同菜品之间的相关关系,如是替补菜品、互补菜品或者没有关系,为原材料采购提供参考。其Python代码如代码清单3-9所示。
代码清单3-9 餐饮销量数据相关性分析
# 餐饮销量数据相关性分析 import pandas as pd catering_sale = '../data/catering_sale_all.xls' # 餐饮数据,含有其他属性 data = pd.read_excel(catering_sale, index_col='日期') # 读取数据,指定“日期”列 为索引列 print(data.corr()) # 相关系数矩阵,即给出了任 意两款菜式之间的相关系数 print(data.corr()['百合酱蒸凤爪']) # 只显示“百合酱蒸凤爪”与 其他菜式的相关系数 # 计算“百合酱蒸凤爪”与“翡翠蒸香茜饺”的相关系数 print(data['百合酱蒸凤爪'].corr(data['翡翠蒸香茜饺']))
*代码详见:demo/code/feature_check.py。
代码清单3-9给出了3种不同形式的求相关系数的运算。运行代码清单3-9,可以得到任意两款菜式之间的相关系数,如运行“data.corr()['百合酱蒸凤爪']”可以得到下面的结果:
百合酱蒸凤爪 1.000000 翡翠蒸香茜饺 0.009206 金银蒜汁蒸排骨 0.016799 乐膳真味鸡 0.455638 蜜汁焗餐包 0.098085 生炒菜心 0.308496 铁板酸菜豆腐 0.204898 香煎韭菜饺 0.127448 香煎萝卜糕 -0.090276 原汁原味菜心 0.428316 Name:百合酱蒸凤爪, dtype: float64
从这个结果可以看出,如果顾客点了“百合酱蒸凤爪”,和点“翡翠蒸香茜饺”“金银蒜汁蒸排骨”“香煎萝卜糕”“铁板酸菜豆腐”“香煎韭菜饺”等主食类菜品的相关性比较低,反而和点“乐膳真味鸡”“生炒菜心”“原汁原味菜心”的相关性比较高。