数据挖掘复习

期末复习

数据挖掘

数据挖掘基本任务

数据挖掘的基本任务包括利用分类与预测、聚类分析、关联规则、时序模式、偏差检测、智能推荐等方法,帮助企业提取数据中蕴含的商业价值,提高企业的竞争力。

数据挖掘建模过程

  1. 定义挖掘目标
  2. 数据取样
  3. 数据探索
  4. 数据预处理
  5. 挖掘建模
  6. 模型评价

1.目标定义

  1. 任务理解

  2. 指标明确

2.数据采集

  1. 建模抽样
  2. 质量把控
  3. 实时采集

3.数据整理

  1. 数据探索
  2. 数据清洗
  3. 数据变换

4.构建模型

  1. 模式发现
  2. 构建模型
  3. 验证模型

5.模型评价

  1. 设定评价标准
  2. 多模型对比
  3. 模型优化

6.模型发布

  1. 模型部署
  2. 模型重构

第三章 数据探索 P39

需要考虑的问题

  1. 样本数据集的数量和质量是否满足模型构建的要求?
  2. 有没有出现从未设想过的数据状态?
  3. 其中有没有明显的规律和趋势?
  4. 各因素之间有什么样的关联性?

1.数据质量分析

主要任务

检查原始数据中是否存在脏数据,脏数据一般指不符合要求以及不能直接进行相应分析的数据,如缺失值、异常值、不一致值、重复数据及含有特殊符号的数据

缺失值分析

产生的原因
  1. 信息暂时无法获取,或者获取信息的代价太大
  2. 信息被遗漏,包括人为因素遗漏及数据采集设备故障导致的非人为因素遗漏
  3. 属性值不存在,如一个未婚者的配偶姓名,一个儿童的固定收入
缺失值的影响
  1. 数据挖掘建模将丢失大量的有用信息
  2. 数据挖掘模型所变现出的不确定性更加显著,规律更难把握
  3. 包含空值的数据回事建模过程陷入混乱,导致不可靠的输出
缺失值的分析
  1. 使用简单的统计分析,可以得到含有缺失值的属性的个数及每个属性的未缺失数、缺失数与缺失率等
  2. 对缺失值的处理
    • 删除存在缺失值的记录
    • 对可能值进行插补
    • 不处理

异常值分析

异常值分析是检验数据是否有录入错误,是否含有不合常理的数据。

异常值是指样本中的个别值,其数值明显偏离其他的观测值。

异常值也称为离群点,异常值分析也称为离群点分析

1. 简单统计量分析

对变量进行描述性统计,进而查看哪些数据是不合理的,如统计最大值和最小值,用来判断这个变量的取值是否超出了合理范围。

2. 3σ准则

正态分布 中σ代表 标准差 ,μ代表 均值 。x=μ即为图像的对称轴
3σ原则为
数值分布在(μ-σ,μ+σ)中的概率为0.6826
数值分布在(μ-2σ,μ+2σ)中的概率为0.9544
数值分布在(μ-3σ,μ+3σ)中的概率为0.9974
可以认为,Y 的取值几乎全部集中在(μ-3σ,μ+3σ)] 区间内,超出这个范围的可能性仅占不到0.3%.

3σ准则是建立在正态分布的等精度重复测量基础上而造成奇异数据的干扰或噪声难以满足正态分布.如果一组测量数据中某个测量值的残余误差的绝对值 νi>3σ,则该测量值为坏值,应剔除.通常把等于 ±3σ的误差作为极限误差,对于正态分布的随机误差,落在 ±3σ以外的概率只有 0.27%,它在有限次测量中发生的可能性很小,故存在3σ准则.3σ准则是最常用也是最简单的粗大误差判别准则,它一般应用于测量次数充分多( n ≥30)或当 n>10做粗略判别时的情况.

3. 箱型图分析

箱形图依据实际数据绘制,不需要事先假定数据服从特定的分布形式,没有对数据作任何限制性要求,它只是真实直观地表现数据分布的本来面貌;另一方面,箱形图判断异常值的标准以四分位数和四分位距为基础,四分位数具有一定的鲁棒性:多达25%的数据可以变得任意远而不会很大地扰动四分位数,所以异常值不能对这个标准施加影响,箱形图识别异常值的结果比较客观。由此可见,箱形图在识别异常值方面有一定的优越性。

  • Q1,Q3

  • 4分位间距(Interquartile Range) IQR=(Q3-Q1)/2

  • 内限=Q1-1.5*IQR,Q3+1.5*IQR

  • 外限=Q1-3*IQR,Q3+3*IQR

  • 温和异常点和极端异常点

箱型图

一致性分析

数据不一致性是指数据的矛盾性、不相容性。直接对不一致的数据进行挖掘,可能会产生与实际相违背的挖掘结果。

在数据挖掘过程中,不一致的数据的产生主要发生在数据集成的过程中,可能是由于被挖掘数据来自于不同的数据源,对于重复存放的数据未能进行一致性更新造成的,比如两张表中都存储了用户的地址,在用户的地址发生改变时,如果只更新了一张表中的数据,那么这两张表中就有了不一致的数据。

2. 数据特征分析

1. 分布分析

1. 定量数据的分布分析
  1. 求极差
  2. 决定组距和组数
  3. 决定分点
  4. 列出频率分布表
  5. 绘制频率分布直方图

要求

  1. 各组之间必须是相互排斥的
  2. 各组必须将所有的数据包括在内
  3. 各组的组宽最好相等
2. 定性数据分析

对于定性变量,常常根据变量的分类类型来分组。

2. 对比分析

  1. 绝对数比较
  2. 相对数比较
    1. 结构相对数:将同一总体内的部分数值与全部数值进行对比求得比重,用以说明事物的性质、结构或质量
    2. 比例相对数:将同一总体内不同部分的数值进行对比,表明总体内各部分的比例关系。
    3. 比较相对数:将同一时期两个性质相同的指标数值进行对比,说明同类现象在不同空间条件下的数量对比关系。
    4. 强度相对数:将两个性质不同但有一定联系的总量指标进行对比,用以说明现象的强度、密度和普遍程度。
    5. 计划完成程度相对数:将某一时期实际完成数与计划完成数进行对比用以说明计划完成程度。
    6. 动态相对数:将同一现象在不同时期的指标数值进行对比,用以说明发展法向和变化速度,如发展速度、增长速度等。

3. 统计量分析

1. 集中趋势程度
  1. 均值
  2. 中位数
  3. 众数
2. 离中趋势度量
  1. 极差
  2. 标准差
  3. 变异系数
  4. 四分位数间距

4. 周期性分析

周期性分析是探索某个变量是否随着时间的变化而呈现出某种周期变化趋势。

5. 贡献度分析

贡献度分析又称帕累托分析,它的原理是帕累托法则,又称20/80定律。同样的投入放在不同的地方会产生不同的效益,例如,对一个公司来讲,80%的利润常常来自于20%最畅销的产品,而其他80%的产品只产生了20%的利润。

6. 相关性分析

1. 直接绘制散点图

判断两个变量是否具有线性相关关系最直观的方法 是直接绘制散点图

2. 绘制散点图矩阵
3. 计算相关系数

为了更加准确地描述变量之间的线性相关程度,可以通过相关系数的计算来进行相关分析

  1. Pearson相关系数(要求连续变量的取值服从正态分布)
  2. Spearman秩相关系数(不服从正态分布的变量或等级变量之间的关系)
  3. 判定系数,判定系数是相关系数的平方,用$r^2$表示。$r^2$越接近1,表明x与y之间的相关性越强,$r^2$越接近0,表明x与y之间几乎没有直线相关关系

Python主要数据探索函数

1. 基本统计特征函数

方法名 函数功能 所属库
sum() 计算数据样本的总和 pandas
mean() 计算数据样本的算术平均数 pandas
var() 计算数据样本的方差 pandas
std() 计算数据样本的标准差 pandas
corr() 计算数据样本的Spearman(Pearson)相关系数矩阵 pandas
cov() 计算数据样本的协方差矩阵 pandas
skew() 样本值的偏度(三阶矩) pandas
kurt() 样本值的峰度(四阶矩) pandas
describe() 给出样本的基本描述(基本统计量如均值、标准差等) pandas

2. 拓展统计特征函数

累计计算(cum)和滚动计算(pd.rolling_),如cumsum() 依次给出前1,2,… n个数的和,rolling(2).sum()依次对相邻的两项求和

3. 统计绘图函数

绘图函数名 绘图函数功能 所属工具箱
plot() 绘制线性二维图,折线图 Matplotlib/pandas
pie() 绘制饼图 Matplotlib/pandas
hist() 绘制二维条形直方图,可显示数据的分配情形 Matplotlib/pandas
boxplot() 绘制样本数据的箱型图 pandas
plot(logy = True) 绘制y轴的对数图形 pandas
plot(yerr = error) 绘制误差条形图 pandas

4. 代码实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 代码3-10 计算两个列向量的相关系数
import pandas as pd
D = pd.DataFrame([range(1, 8), range(2, 9)]) # 生成样本D,一行为1~7,一行为2~8
print(D.corr(method='spearman')) # 计算相关系数矩阵
S1 = D.loc[0] # 提取第一行
S2 = D.loc[1] # 提取第二行
print(S1.corr(S2, method='pearson')) # 计算S1、S2的相关系数


# 代码3-11 计算6×5随机矩阵的协方差矩阵

import numpy as np
D = pd.DataFrame(np.random.randn(6, 5)) # 产生6×5随机矩阵
print(D.cov()) # 计算协方差矩阵
print(D[0].cov(D[1])) # 计算第一列和第二列的协方差


# 代码3-12 计算6×5随机矩阵的偏度(三阶矩)∕峰度(四阶矩)
import numpy as np
D = pd.DataFrame(np.random.randn(6, 5)) # 产生6×5随机矩阵
print(D.skew()) # 计算偏度
print(D.kurt()) # 计算峰度


# 代码3-13 6×5随机矩阵的describe

import numpy as np
D = pd.DataFrame(np.random.randn(6, 5)) # 产生6×5随机矩阵
print(D.describe())


# 代码3-14 pandas累积统计特征函数、移动窗口统计函数示例


D=pd.Series(range(0, 20)) # 构造Series,内容为0~19共20个整数
print(D.cumsum()) # 给出前n项和
print(D.rolling(2).sum()) # 依次对相邻两项求和


# 代码3-15 绘图之前需要加载的代码
import matplotlib.pyplot as plt # 导入绘图库
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.figure(figsize = (7, 5)) # 创建图像区域,指定比例


# 代码3-16 绘制一条蓝色的正弦虚线

import numpy as np
x = np.linspace(0,2*np.pi,50) # x坐标输入
y = np.sin(x) # 计算对应x的正弦值
plt.plot(x, y, 'bp--') # 控制图形格式为蓝色带星虚线,显示正弦曲线
plt.show()


# 代码3-17 绘制饼图


import matplotlib.pyplot as plt

# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' # 定义标签
sizes = [15, 30, 45, 10] # 每一块的比例
colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral'] # 每一块的颜色
explode = (0, 0.1, 0, 0) # 突出显示,这里仅仅突出显示第二块(即'Hogs')

plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90)
plt.axis('equal') # 显示为圆(避免比例压缩为椭圆)
plt.show()


# 代码3-18 绘制二维条形直方图

import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000) # 1000个服从正态分布的随机数
plt.hist(x, 10) # 分成10组进行绘制直方图
plt.show()


# 代码3-19 绘制箱型图


import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
x = np.random.randn(1000) # 1000个服从正态分布的随机数
D = pd.DataFrame([x, x+1]).T # 构造两列的DataFrame
D.plot(kind = 'box') # 调用Series内置的绘图方法画图,用kind参数指定箱型图box
plt.show()


# 代码3-20 使用plot(logy = True)函数进行绘图


import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
import numpy as np
import pandas as pd

x = pd.Series(np.exp(np.arange(20))) # 原始数据
plt.figure(figsize = (8, 9)) # 设置画布大小
ax1 = plt.subplot(2, 1, 1)
x.plot(label = u'原始数据图', legend = True)

ax1 = plt.subplot(2, 1, 2)
x.plot(logy = True, label = u'对数数据图', legend = True)
plt.show()


# 代码3-21 绘制误差棒图


import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
import numpy as np
import pandas as pd

error = np.random.randn(10) # 定义误差列
y = pd.Series(np.sin(np.arange(10))) # 均值数据列
y.plot(yerr = error) # 绘制误差图
plt.show()

第四章 数据预处理 P75

数据预处理

1. 数据清洗

数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值等

1. 缺失值处理

处理方法可分为三类:删除记录、数据插补和不处理

插补方法 方法描述
均值、中位数、众数插补 根据属性值的类型,用该属性取值的平均数、中位数、众数进行插补
使用固定值 将缺失的属性值用一个常量替换
最近临插补 在记录中找到与缺失样本最接近的样本的该属性卡值插补
回归方法 对带有缺失值的变量,根据已有数据和与其有关的其他变量(因变量)的数据建立拟合模型来预测确实的属性值
插值法 插值法是利用已知点建立合适的插值函数$f(x)$,未知数由对应点$x_i$求出的函数值$f(x_i)$近似代替
1. 拉格朗日插值法
2. 牛顿插值法

2. 异常值处理

异常值处理方法 方法描述
删除含有异常值的记录 直接将含有异常值的记录删除
视为缺失值 将异常值视为缺失值,利用缺失值处理的方法进行处理
平均值修正 可用前后两个观测值修正该异常值
不处理 直接在具有异常值的数据集上进行挖掘建模

2. 数据集成

数据挖掘需要的数据往往分布在不同的数据源中,数据集成就是将多个数据源合并存放在一个一致的数据储存位置(如数据仓库)中的过程。

1. 实体识别

  1. 同名异义:数据源A中的属性ID和数据源B三的属性ID分别描述的是菜品编号和订单编号,即描述的是不同的实体
  2. 异名同义:数据源A中的sales_dt和数据源B中的sales_date都是描述销售日期的
  3. 单位不统一:描述同一个实体时分别用的是国际单位和中国传统的计量单位

2. 冗余属性识别

  1. 同一属性多次出现
  2. 同一属性命名不一致导致重复

3. 数据变换

主要是对数据进行规范化处理,将数据转换成“适当的”形式,以适用于挖掘任务和算法的需要。

  1. 简单函数变换,对原始数据进行某些数学函数变换,包括平方、取对数、差分运算等

  2. 规范化

    1. 最小-最大规范化,也叫离差标准化,对原始数据的线性变换,将数值映射到[0,1]之间。

      $$ x^*=\frac{(x-min)}{(max-min)} $$

    2. 0-均值规范化,也叫标准差标准化,经过处理的数据均值为0,标准差为1。

      $$ x^*= \frac{x-\overline{x}}{σ} $$

    3. 小数定标规范化,通过移动属性值的小数位数,将属性值映射到[-1,1]之间,移动的小数位数取决于属性值绝对值的最大值

      $$ x^*=\frac{x}{10^k} $$

  3. 连续属性离散化,如某些分类算法,ID3算法、Apriori算法,要求数据是分类属性形式。

    1. 离散化的过程,连续属性离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值
    2. 常用的离散化方法,等宽法和(一维)聚类。
    • 等宽法,将属性的值域分成具有相同宽度的区间,区间的个数由数据本身的特点决定或者用户指定,类似与制作频率分布表
    • 等频法,将相同数量的记录放进每个区间
      • 这两种方法简单,易于操作,但都需要认为规定划分区间的个数。同时,等宽法缺点在于它对离群点比较敏感,倾向于不均匀地把属性值分布到各个区间。有些区间包含许多数据,而另外一些区间的数据极少,这样会严重损坏建立的决策模型。等频法虽然避免了上述问题的产生,却可能将相同的数据值分布到不同的区间,以满足每个区间中固定的数据个数
    • 基于聚类分析的方法,一维聚类方法包括两个步骤:首先将连续属性的值用聚类算法(如K-Means算法)进行聚类,然后再将聚类得到的簇进行处理,合并到一个簇的连续属性值做同一标记。聚类分析的离散化方法也需要用户制定簇的个数,从而决定产生的区间数。
  4. 属性构造,利用已有的属性集构造新的属性,并加入到现有的属性集合中。

  5. 小波变换 P(88),信号分析手段

3. 数据规约

在大数据集上进行复杂的数据分析和挖掘需要很长时间。数据规约产生更小且保持原数据完整性的新数据集,在规约后的数据集上进行分析和挖掘将提高效率。

意义

  1. 降低无效、错误数据对建模的影响,提高建模的准确性
  2. 少量却具有代表性的数据将大幅缩减数据挖掘的时间
  3. 降低储存数据的成本

1. 属性规约

属性规约通过属性合并创建新属性维数,或者通过直接删除不相关的属性(维)来减少数据维数,从而提高数据挖掘的效率,降低计算成本。属性规约的目标是寻找最小的属性子集并确保新数据子集的概率分布尽可能接近原来的数据集的概率分布。

属性规约方法 方法描述 方法解析
合并属性 将一些旧属性合并为新属性 初始属性集:{$A_1,A_2,A_3,B_1,B_2,B_3,C$},{$A_1,A_2,A_3$}->$A$ {$B_1,B_2,B_3$}->$B$ 规约后属性集{$A,B,C$}
逐步向前选择 从一个空属性集开始,每次从原来属性集合中选择一个当前最优的属性添加到当前属性子集中。直到无法选出最优属性或满足一定阈值约束为止 初始属性集:{$A_1,A_2,A_3,A_4,A_5,A_6$},{}->{$A_1$}->{$A_1,A_4$} 规约后属性集{$A_1,A_4,A_6$}
逐步向后删除 从一个全属性集开始,每次从当前属性子集中选择一个当前最差的属性并将其从当前属性子集中消去。直到无法选出最差属性为止或满足一定阈值约束为止 初始属性集:{$A_1,A_2,A_3,A_4,A_5,A_6$},{$A_1,A_3,A_4,A_5,A_6$}->{$A_1,A_4,A_5,A_6$} 规约后属性集{$A_1,A_4,A_6$}
决策树归纳 利用决策树的归纳方法对初始数据进行分类归纳学习,获得一个初始决策树,所有没有出现在这个决策树上的属性均可认为是无关属性,因此将这些属性从初始集合中删除,就可以获得一个较优的属性子集
主成分分析 用较少的变量去解释原始数据中的大部分变量,即将许多线性相关性很高的变量转化成彼此互相独立或不相关的变量

逐步向前选择、逐步向后删除和决策树归纳是属于直接删除不相关属性(维)的方法。主成分分析法是一种用于连续属性的数据降维方法,它构造了原始数据的一个正交变换,新空间的基底去除了原始空间基底下数据的相关性,只需要使用少数新变量就能解释原始数据中的大部分变异。

在应用中,通常是选出比原始变量个数少,能解释大部分数据中的变量的几个新变量,即所谓主成分,来代替原始变量进行建模。

主成分分析计算步骤

主成分分析的步骤:中心化数据集-计算协方差矩阵-计算特征根-计算主成分矩阵-得到降维后的数据集

  1. 设原始变量$X_1,X_2,…,X_p$的$n$次观测数据矩阵为式
    $$
    X=\begin{Bmatrix}
    X_{11} & X_{12} & \dots & X_{13} \\
    X_{21} & X_{22} & \dots & X_{23} \\
    \dots & \dots & \dots & \dots \\
    X_{n1} & X_{n2} & \dots & X_{np} \\
    \end{Bmatrix}=(X_1,X_2,\dots,X_P)
    $$

  2. 将数据矩阵按列进行中心标准化。

  3. 求相关系数矩阵 $\mathbf{R}$ ,$ \mathbf{R} = (r_{ij})_ {p\times p} $ , $r_{ij}$定义为式,其中$r_{ij}=r_{ji},r_{ij}=1$
    $$
    r_{rj}=
    \sum\nolimits_{k=1}^n (x_{ki}-\overline{x_i})(x_{kj}-\overline{x_j})
    /
    \sqrt{
    \sum\nolimits_{k=1}^n (x_{ki}-\overline{x_i})^2
    \sum\nolimits_{k=1}^n (x_{kj}-\overline{x_j})^2
    }
    $$

  4. 求$\mathbf{R}$的特征方程 $ det(\mathbf{R}-λ\mathbf{E})=0 $ 的特征根$λ_1\geλ_2\ge…λ_p>0$

  5. 确定主成分个数,α根据实际问题确定,一般取80%
    $$
    m:
    \frac{\sum\nolimits_{i=1}^m \lambda_i}
    {\sum\nolimits_{i=1}^p \lambda_i}
    \ge
    \alpha
    $$

  6. 计算m个相应的单位特征向量,如式
    $$
    \mathbf{\beta_1}=\begin{pmatrix}
    \beta_1 \\ \beta_2 \\ …\\ \beta_{p1}
    \end{pmatrix}
    ,
    \mathbf{\beta_2}=\begin{pmatrix}
    \beta_{12} \\ \beta_{22} \\ …\\ \beta_{p2}
    \end{pmatrix}
    ,
    \mathbf{\beta_m}=\begin{pmatrix}
    \beta_{1m} \\ \beta_{2m} \\ …\\ \beta_{pm}
    \end{pmatrix}
    $$

  7. 计算主成分,如式
    $$
    Z_i=\beta_{1i}X_1+\beta_{2i}X_2+…+\beta_{pi}X_p (i=1,2,…,m)
    $$

python中主成分分析函数:

1
sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False)
参数名称 意义 类型
n_components PCA算法中索要保留的主成分个数n,就是保留下来的特征个数n int/str
copy 表示是否在运行算法时,将原始训练数据复制一份 bool
whiten 白化,使得每个特征具有相同的方差 bool

2. 数值规约

数值规约通过选择代替的、较小的数据来减少数据量,包括有参数方法和无参数方法两类。有参数方法是使用一个模型来评估数据,只需存放参数,而不需要存放实际数据,例如回归(线性回归和多元回归)和对数线性模型(近似离散属性集中的多维概率分布)。无参数方法就需要存放实际数据,如直方图、聚类、抽样(采样)。

  1. 直方图
  2. 聚类
  3. 抽样
    • 常用抽样方法
      1. s个样本无放回简单随机抽样
      2. s个样本有放回地简单随机抽样
      3. 聚类抽样
      4. 分层抽样
  4. 参数回归

4. Python主要数据预处理函数

函数名 函数功能 所属拓展库
interpolate 一维、高维数据插值 SciPy
unique 去除数据中的重复元素,得到单值元素列表,它是对象的方法名 pandas/Numpy
isnull 判断是否空值 pandas
notnull 判断是否非空值 pandas
PCA 对指标变量矩阵进行主成分分析 Scikit-learn
random 生成随机矩阵 Numpy

代码实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 代码4-8 求向量D中的单值元素,并返回相关索引
import pandas as pd
import numpy as np
D = pd.Series([1, 1, 2, 3, 5])
D.unique()
np.unique(D)


# 代码 4-9 对一个10×4维的随机矩阵进行主成分分析
from sklearn.decomposition import PCA
D = np.random.rand(10,4)
pca = PCA()
pca.fit(D)
pca.components_ # 返回模型的各个特征向量
pca.explained_variance_ratio_ # 返回各个成分各自的方差百分比

第五章 挖掘建模 P102

1. 分类与预测

1. 实现过程

  1. 分类是构造一个分类模型,输入样本的属性值,输出对应的类别,将每个样本映射到预先定义好的类别。分类模型建立在已有类标记的数据集上,模型在已有样本上的准确率可以方便的绩,所以分类属于有监督的学习。
  2. 预测,预测是建立两种或两种以上变量间相互依赖的函数模型,然后进行预测或控制
  3. 实现过程,分类为和预测的实现过程类似,以分类模型为例。

分类模型的实现步骤

2. 常用的分类与预测算法

算法名称 算法描述
回归分析 回归分析是确定预测属性(数值型)与其他变量间相互依赖的定量关系最常用的统计学方法,包括线性回归、非线性回归、Logistic回归、岭回归、主成分回归、最小二乘回归等模型
决策树 决策树采用自顶向下的递归方式,在内部节点进行属性值的比较,并根据不同的属性值从该节点向下分支,最终得到的叶节点是学习划分的类
人工神经网络 人工神经网络是一种模型大脑神经网络结构和功能而建立的信息处理系统,表示神经网络的输入与输出变量之间的关系的模型
贝叶斯网络 贝叶斯网络又称信度网络,是Bayes方法的扩展,是目前不确定知识表达和推理领域最有效的理论模型之一
支持向量机 支持向量机是一种通过某种非现行映射,把低维的非现行可分转化为高维的线性可分,在高维空间进行线性分析的算法

3. 回归分析

回归模型名称 适用条件 算法描述
线性回归 因变量与自变量是线性关系 对一个或多个自变量与因变量之间的线性关系进行建模,可用最小二乘法求解模型系数
非线性回归 因变量与自变量之间不都是线性关系 对一个或多个自变量和因变量之间的非线性关系进行建模。如果可转化为线性关系则用线性关系求解,否则用非线性最小二乘方法求解
Logistic回归 一般是因变量的有1-0(是否)两种取值 是广义线性回归模型的特例,利用Logistic函数将因变量的取值范围控制在的0和1之间,表示取值1的概率
岭回归 参与建模的自变量之间具有多重共线性 是一种改进最小二乘估计的方法
主成分回归 参与建模的自变量之间具有多重共线性 根据主成分分析思想,对最小二乘法的一种改进,它是参数估计的一种有偏估计,可消除自变量之间的多重共线性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-

# 代码5-1 Logistic回归

import pandas as pd
from sklearn.linear_model import LogisticRegression as LR
# 参数初始化
filename = '../data/bankloan.xls'
data = pd.read_excel(filename)
x = data.iloc[:,:8].as_matrix()
y = data.iloc[:,8].as_matrix()

lr = LR() # 建立逻辑回归模型
lr.fit(x, y) # 用筛选后的特征数据来训练模型
print('模型的平均准确度为:%s' % lr.score(x, y))

4. 决策树

熵(entropy)

决策树算法 算法描述
ID3算法 其核心是在决策树的各级节点上,使用信息增益方法作为属性的选择标准,来帮助确定生成每个节点时所应采用的合适属性
C4.5算法 相对于ID3算法的重要改进是使用信息增益率来选择节点属性。C4.5算法可以克服ID3算法存在的不足:ID3算法只适用于离散的描述属性,而C4.5算法既能够处理离散的描述属性,也可以处理连续的描述属性
CART算法 CART决策树是一种十分有效的非参数分类和回归方法,通过构建树、修剪树、评估树来构建一个二叉树。当中节点是连续变量时,该树为回归树,当终节点是分类变量时,该树为分类树
  • ID3算法实现步骤
    1. 对当前样本集合,计算所有属性的信息增益
    2. 选择信息增益最大的属性作为测试属性,把测试属性取值相同的样本划分为同一个样本子集
    3. 若子样本集的类别属性只含有单个属性,则分支为叶子节点,判断其属性值并标上相应的符号,然后返回调用处;否则对子样本集递归调用本算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# -*- coding: utf-8 -*-

# 代码5-2 决策树

import pandas as pd
# 参数初始化
filename = '../data/sales_data.xls'
data = pd.read_excel(filename, index_col = u'序号') # 导入数据

# 数据是类别标签,要将它转换为数据
# 用1来表示“好”“是”“高”这三个属性,用-1来表示“坏”“否”“低”
data[data == u'好'] = 1
data[data == u'是'] = 1
data[data == u'高'] = 1
data[data != 1] = -1
x = data.iloc[:,:3].astype(int)
y = data.iloc[:,3].astype(int)


from sklearn.tree import DecisionTreeClassifier as DTC
dtc = DTC(criterion='entropy') # 建立决策树模型,基于信息熵
dtc.fit(x, y) # 训练模型

# 导入相关函数,可视化决策树。
# 导出的结果是一个dot文件,需要安装Graphviz才能将它转换为pdf或png等格式。
from sklearn.tree import export_graphviz
x = pd.DataFrame(x)

"""
string1 = '''
edge [fontname="NSimSun"];
node [ fontname="NSimSun" size="15,15"];
{
'''
string2 = '}'
"""

with open("../tmp/tree.dot", 'w') as f:
export_graphviz(dtc, feature_names = x.columns, out_file = f)
f.close()



'''
from IPython.display import Image
from sklearn import tree
import pydotplus

dot_data = tree.export_graphviz(dtc, out_file=None, #regr_1 是对应分类器
feature_names=data.columns[:3], #对应特征的名字
class_names=data.columns[3], #对应类别的名字
filled=True, rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('../tmp/example.png') #保存图像
Image(graph.create_png())
'''

5. 人工神经网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pandas as pd
# 参数初始化
inputfile = '../data/sales_data.xls'
data = pd.read_excel(inputfile, index_col = u'序号') # 导入数据

# 数据是类别标签,要将它转换为数据
# 用1来表示“好”“是”“高”这三个属性,用0来表示“坏”“否”“低”
data[data == u'好'] = 1
data[data == u'是'] = 1
data[data == u'高'] = 1
data[data != 1] = 0
x = data.iloc[:,:3].astype(int)
y = data.iloc[:,3].astype(int)

from keras.models import Sequential
from keras.layers.core import Dense, Activation

model = Sequential() # 建立模型
model.add(Dense(input_dim = 3, units = 10))
model.add(Activation('relu')) # 用relu函数作为激活函数,能够大幅提供准确度
model.add(Dense(input_dim = 10, units = 1))
model.add(Activation('sigmoid')) # 由于是0-1输出,用sigmoid函数作为激活函数

model.compile(loss = 'binary_crossentropy', optimizer = 'adam')
# 编译模型。由于我们做的是二元分类,所以我们指定损失函数为binary_crossentropy,以及模式为binary
# 另外常见的损失函数还有mean_squared_error、categorical_crossentropy等,请阅读帮助文件。
# 求解方法我们指定用adam,还有sgd、rmsprop等可选

model.fit(x, y, epochs = 1000, batch_size = 10) # 训练模型,学习一千次
yp = model.predict_classes(x).reshape(len(y)) # 分类预测

from cm_plot import * # 导入自行编写的混淆矩阵可视化函数
cm_plot(y,yp).show() # 显示混淆矩阵可视化结果

2. 聚类分析

K-Means聚类分析

K-Means算法是典型的基于举例的非层次聚类算法,在最小化误差函数的基础上将数据划分为预定的磊K,采用距离作为相似性评价指标,即认为两个对象的距离越近,相似度越大

1. 算法过程
  1. 从$n$个样本数据中随机选取$k$个对象作为初始的聚类中心。
  2. 分别计算每个样本到各个聚类中心的距离,将对象分配到距离最近的聚类中。
  3. 所有对象分配完成后,重新计算$k$个聚类的中心。
  4. 与前一次计算得到的$k$个聚类中心比较,如果聚类中心发生变化,转至步骤2,否则继续步骤5
  5. 当质心不发生变化时,停止并输出聚类结果。
2. 代码实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import pandas as pd
# 参数初始化
inputfile = '../data/consumption_data.xls' # 销量及其他属性数据
outputfile = '../tmp/data_type.xls' # 保存结果的文件名
k = 3 # 聚类的类别
iteration = 500 # 聚类最大循环次数
data = pd.read_excel(inputfile, index_col = 'Id') # 读取数据
data_zs = 1.0*(data - data.mean())/data.std() # 数据标准化

from sklearn.cluster import KMeans
model = KMeans(n_clusters = k, n_jobs = 4, max_iter = iteration,random_state=1234) # 分为k类,并发数4
model.fit(data_zs) # 开始聚类

# 简单打印结果
r1 = pd.Series(model.labels_).value_counts() # 统计各个类别的数目
r2 = pd.DataFrame(model.cluster_centers_) # 找出聚类中心
r = pd.concat([r2, r1], axis = 1) # 横向连接(0是纵向),得到聚类中心对应的类别下的数目
r.columns = list(data.columns) + ['类别数目'] # 重命名表头
print(r)

# 详细输出原始数据及其类别
r = pd.concat([data, pd.Series(model.labels_, index = data.index)], axis = 1) # 详细输出每个样本对应的类别
r.columns = list(data.columns) + ['聚类类别'] # 重命名表头
r.to_excel(outputfile) # 保存结果




def density_plot(data): # 自定义作图函数
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
p = data.plot(kind='kde', linewidth = 2, subplots = True, sharex = False)
[p[i].set_ylabel(u'密度') for i in range(k)]
plt.legend()
return plt

pic_output = '../tmp/pd' # 概率密度图文件名前缀
for i in range(k):
density_plot(data[r[u'聚类类别']==i]).savefig(u'%s%s.png' %(pic_output, i))

3. 关联规则

Apriori算法

核心思想:通过连接产生候选项与其支持度,然后通过剪枝生成频繁项集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import numpy as np
import pandas as pd
def connect_string(x, ms):
x = list(map(lambda i:sorted(i.split(ms)), x))
l = len(x[0])
r = []
for i in range(len(x)):
for j in range(i,len(x)):
if x[i][:l-1] == x[j][:l-1] and x[i][l-1] != x[j][l-1]:
r.append(x[i][:l-1]+sorted([x[j][l-1],x[i][l-1]]))
return r

#寻找关联规则的函数
def find_rule(d, support, confidence, ms = u'--'):
result = pd.DataFrame(index=['support', 'confidence']) #定义输出结果

support_series = 1.0*d.sum()/len(d) #支持度序列
column = list(support_series[support_series > support].index) #初步根据支持度筛选
k = 0

while len(column) > 1:
k = k+1
print(u'\n正在进行第%s次搜索...' %k)
column = connect_string(column, ms)
print(u'数目:%s...' %len(column))
sf = lambda i: d[i].prod(axis=1, numeric_only = True) #新一批支持度的计算函数

#创建连接数据,这一步耗时、耗内存最严重。当数据集较大时,可以考虑并行运算优化。
d_2 = pd.DataFrame(list(map(sf,column)), index = [ms.join(i) for i in column]).T

support_series_2 = 1.0*d_2[[ms.join(i) for i in column]].sum()/len(d) #计算连接后的支持度
column = list(support_series_2[support_series_2 > support].index) #新一轮支持度筛选
support_series = support_series.append(support_series_2)
column2 = []

for i in column: #遍历可能的推理,如{A,B,C}究竟是A+B-->C还是B+C-->A还是C+A-->B?
i = i.split(ms)
for j in range(len(i)):
column2.append(i[:j]+i[j+1:]+i[j:j+1])

cofidence_series = pd.Series(index=[ms.join(i) for i in column2]) #定义置信度序列

for i in column2: #计算置信度序列
cofidence_series[ms.join(i)] = support_series[ms.join(sorted(i))]/support_series[ms.join(i[:len(i)-1])]

for i in cofidence_series[cofidence_series > confidence].index: #置信度筛选
result[i] = 0.0
result[i]['confidence'] = cofidence_series[i]
result[i]['support'] = support_series[ms.join(sorted(i.split(ms)))]

result = result.T.sort_values(['confidence','support'], ascending = False) #结果整理,输出
print(u'\n结果为:')
print(result)
return result

其他

数据挖掘六个步骤
每个步骤展开三个层次

例如:

第三个步骤 数据预处理
第一个层次 :数据缺省值 如何处理 数据的转换 处理方法,缺失值删除,属性删除,插值(均值插值 牛顿法 拉格朗日法)
第二个层次:……

实验代码

chapter 6

GM11.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#-*- coding: utf-8 -*-

def GM11(x0): #自定义灰色预测函数
import numpy as np
x1 = x0.cumsum() #1-AGO序列
z1 = (x1[:len(x1)-1] + x1[1:])/2.0 #紧邻均值(MEAN)生成序列
z1 = z1.reshape((len(z1),1))
B = np.append(-z1, np.ones_like(z1), axis = 1)
Yn = x0[1:].reshape((len(x0)-1, 1))
[[a],[b]] = np.dot(np.dot(np.linalg.inv(np.dot(B.T, B)), B.T), Yn) #计算参数
f = lambda k: (x0[0]-b/a)*np.exp(-a*(k-1))-(x0[0]-b/a)*np.exp(-a*(k-2)) #还原值
delta = np.abs(x0 - np.array([f(i) for i in range(1,len(x0)+1)]))
C = delta.std()/x0.std()
P = 1.0*(np.abs(delta - delta.mean()) < 0.6745*x0.std()).sum()/len(x0)
return f, a, b, x0[0], C, P #返回灰色预测函数、a、b、首项、方差比、小残差概率

01-lasso.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#-*- coding: utf-8 -*-

import numpy as np
import pandas as pd
from sklearn.linear_model import Lasso

inputfile = '../data/data.csv' # 输入的数据文件
data = pd.read_csv(inputfile) # 读取数据
lasso = Lasso(1000) # 调用Lasso()函数,设置λ的值为1000
lasso.fit(data.iloc[:,0:14],data['y'])
print('相关系数为:',np.round(lasso.coef_,5)) # 输出结果,保留五位小数

print('相关系数非零个数为:',np.sum(lasso.coef_ != 0)) # 计算相关系数非零的个数

mask = lasso.coef_ != 0 # 返回一个相关系数是否为零的布尔数组
print('相关系数是否为零:',mask)

outputfile ='../tmp/new_reg_data.csv' # 输出的数据文件
new_reg_data = data.iloc[:, mask] # 返回相关系数非零的数据
new_reg_data.to_csv(outputfile) # 存储数据
print('输出数据的维度为:',new_reg_data.shape) # 查看输出数据的维度

02-gm_predict.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#-*- coding: utf-8 -*-

import sys
sys.path.append('../code') # 设置路径
import numpy as np
import pandas as pd
from GM11 import GM11 # 引入自编的灰色预测函数

inputfile1 = '../tmp/new_reg_data.csv' # 输入的数据文件
inputfile2 = '../data/data.csv' # 输入的数据文件
new_reg_data = pd.read_csv(inputfile1) # 读取经过特征选择后的数据
data = pd.read_csv(inputfile2) # 读取总的数据
new_reg_data.index = range(1994, 2014)
new_reg_data.loc[2014] = None
new_reg_data.loc[2015] = None
# l = ['x1', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x13']
l = ['x1', 'x4', 'x5', 'x6', 'x7', 'x8']
for i in l:
f = GM11(new_reg_data.loc[range(1994, 2014),i].values)[0]
new_reg_data.loc[2014,i] = f(len(new_reg_data)-1) # 2014年预测结果
new_reg_data.loc[2015,i] = f(len(new_reg_data)) # 2015年预测结果
new_reg_data[i] = new_reg_data[i].round(2) # 保留两位小数
outputfile = '../tmp/new_reg_data_GM11.xls' # 灰色预测后保存的路径
y = list(data['y'].values) # 提取财政收入列,合并至新数据框中
y.extend([np.nan,np.nan])
new_reg_data['y'] = y
new_reg_data.to_excel(outputfile) # 结果输出
print('预测结果为:\n',new_reg_data.loc[2014:2015,:]) # 预测结果展示

03-svr_predict.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#-*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.svm import LinearSVR

inputfile = '../tmp/new_reg_data_GM11.xls' # 灰色预测后保存的路径
data = pd.read_excel(inputfile) # 读取数据
np.array(data)
# feature = ['x1', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x13'] # 属性所在列
feature = ['x1', 'x4', 'x5', 'x6', 'x7', 'x8'] # 属性所在列
data_train = data.loc[range(0,20)].copy() # 取2014年前的数据建模
data_mean = data_train.mean()
data_std = data_train.std()
data_train = (data_train - data_mean)/data_std # 数据标准化
x_train = data_train[feature].values # 属性数据
y_train = data_train['y'].values # 标签数据

linearsvr = LinearSVR() # 调用LinearSVR()函数
linearsvr.fit(x_train,y_train)
x = ((data[feature] - data_mean[feature])/data_std[feature]).values # 预测,并还原结果。
data[u'y_pred'] = linearsvr.predict(x) * data_std['y'] + data_mean['y']
outputfile = '../tmp/new_reg_data_GM11_revenue.xls' # SVR预测后保存的结果
data.to_excel(outputfile)

print('真实值与预测值分别为:\n',data[['y','y_pred']])

fig = data[['y','y_pred']].plot(subplots = True, style=['b-o','r-*']) # 画出预测结果图
plt.show()

chapter 7

01-data_explore.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#-*- coding: utf-8 -*- 

# 对数据进行基本的探索
# 返回缺失值个数以及最大最小值

import pandas as pd

datafile= '../data/air_data.csv' # 航空原始数据,第一行为属性标签
resultfile = '../tmp/explore.csv' # 数据探索结果表

# 读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)
data = pd.read_csv(datafile, encoding = 'utf-8')

# 包括对数据的基本描述,percentiles参数是指定计算多少的分位数表(如1/4分位数、中位数等)
explore = data.describe(percentiles = [], include = 'all').T # T是转置,转置后更方便查阅
explore['null'] = len(data)-explore['count'] # describe()函数自动计算非空值数,需要手动计算空值数

explore = explore[['null', 'max', 'min']]
explore.columns = [u'空值数', u'最大值', u'最小值'] # 表头重命名
'''
这里只选取部分探索结果。
describe()函数自动计算的字段有count(非空值数)、unique(唯一值数)、top(频数最高者)、
freq(最高频数)、mean(平均值)、std(方差)、min(最小值)、50%(中位数)、max(最大值)
'''

explore.to_csv(resultfile) # 导出结果

02-data_distribution.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#-*- coding: utf-8 -*- 

# 对数据的分布分析

import pandas as pd
import matplotlib.pyplot as plt

datafile= '../data/air_data.csv' # 航空原始数据,第一行为属性标签

# 读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)
data = pd.read_csv(datafile, encoding = 'utf-8')

# 客户信息类别
# 提取会员入会年份
from datetime import datetime
ffp = data['FFP_DATE'].apply(lambda x:datetime.strptime(x,'%Y/%m/%d'))
ffp_year = ffp.map(lambda x : x.year)
# 绘制各年份会员入会人数直方图
fig = plt.figure(figsize = (8 ,5)) # 设置画布大小
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
plt.hist(ffp_year, bins='auto', color='#0504aa')
plt.xlabel('年份')
plt.ylabel('入会人数')
plt.title('各年份会员入会人数')
plt.show()
plt.close

# 提取会员不同性别人数
male = pd.value_counts(data['GENDER'])['男']
female = pd.value_counts(data['GENDER'])['女']
# 绘制会员性别比例饼图
fig = plt.figure(figsize = (7 ,4)) # 设置画布大小
plt.pie([ male, female], labels=['男','女'], colors=['lightskyblue', 'lightcoral'],
autopct='%1.1f%%')
plt.title('会员性别比例')
plt.show()
plt.close

# 提取不同级别会员的人数
lv_four = pd.value_counts(data['FFP_TIER'])[4]
lv_five = pd.value_counts(data['FFP_TIER'])[5]
lv_six = pd.value_counts(data['FFP_TIER'])[6]
# 绘制会员各级别人数条形图
fig = plt.figure(figsize = (8 ,5)) # 设置画布大小
plt.bar(x=range(3), height=[lv_four,lv_five,lv_six], width=0.4, alpha=0.8, color='skyblue')
plt.xticks([index for index in range(3)], ['4','5','6'])
plt.xlabel('会员等级')
plt.ylabel('会员人数')
plt.title('会员各级别人数')
plt.show()
plt.close()

# 提取会员年龄
age = data['AGE'].dropna()
age = age.astype('int64')
# 绘制会员年龄分布箱型图
fig = plt.figure(figsize = (5 ,10))
plt.boxplot(age,
patch_artist=True,
labels = ['会员年龄'], # 设置x轴标题
boxprops = {'facecolor':'lightblue'}) # 设置填充颜色
plt.title('会员年龄分布箱线图')
# 显示y坐标轴的底线
plt.grid(axis='y')
plt.show()
plt.close



# 乘机信息类别
lte = data['LAST_TO_END']
fc = data['FLIGHT_COUNT']
sks = data['SEG_KM_SUM']

# 绘制最后乘机至结束时长箱线图
fig = plt.figure(figsize = (5 ,8))
plt.boxplot(lte,
patch_artist=True,
labels = ['时长'], # 设置x轴标题
boxprops = {'facecolor':'lightblue'}) # 设置填充颜色
plt.title('会员最后乘机至结束时长分布箱线图')
# 显示y坐标轴的底线
plt.grid(axis='y')
plt.show()
plt.close

# 绘制客户飞行次数箱线图
fig = plt.figure(figsize = (5 ,8))
plt.boxplot(fc,
patch_artist=True,
labels = ['飞行次数'], # 设置x轴标题
boxprops = {'facecolor':'lightblue'}) # 设置填充颜色
plt.title('会员飞行次数分布箱线图')
# 显示y坐标轴的底线
plt.grid(axis='y')
plt.show()
plt.close

# 绘制客户总飞行公里数箱线图
fig = plt.figure(figsize = (5 ,10))
plt.boxplot(sks,
patch_artist=True,
labels = ['总飞行公里数'], # 设置x轴标题
boxprops = {'facecolor':'lightblue'}) # 设置填充颜色
plt.title('客户总飞行公里数箱线图')
# 显示y坐标轴的底线
plt.grid(axis='y')
plt.show()
plt.close



# 积分信息类别
# 提取会员积分兑换次数
ec = data['EXCHANGE_COUNT']
# 绘制会员兑换积分次数直方图
fig = plt.figure(figsize = (8 ,5)) # 设置画布大小
plt.hist(ec, bins=5, color='#0504aa')
plt.xlabel('兑换次数')
plt.ylabel('会员人数')
plt.title('会员兑换积分次数分布直方图')
plt.show()
plt.close

# 提取会员总累计积分
ps = data['Points_Sum']
# 绘制会员总累计积分箱线图
fig = plt.figure(figsize = (5 ,8))
plt.boxplot(ps,
patch_artist=True,
labels = ['总累计积分'], # 设置x轴标题
boxprops = {'facecolor':'lightblue'}) # 设置填充颜色
plt.title('客户总累计积分箱线图')
# 显示y坐标轴的底线
plt.grid(axis='y')
plt.show()
plt.close



# 提取属性并合并为新数据集
data_corr = data[['FFP_TIER','FLIGHT_COUNT','LAST_TO_END',
'SEG_KM_SUM','EXCHANGE_COUNT','Points_Sum']]
age1 = data['AGE'].fillna(0)
data_corr['AGE'] = age1.astype('int64')
data_corr['ffp_year'] = ffp_year

# 计算相关性矩阵
dt_corr = data_corr.corr(method = 'pearson')
print('相关性矩阵为:\n',dt_corr)

# 绘制热力图
import seaborn as sns
plt.subplots(figsize=(10, 10)) # 设置画面大小
sns.heatmap(dt_corr, annot=True, vmax=1, square=True, cmap='Blues')
plt.show()
plt.close

03-data_clean.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#-*- coding: utf-8 -*- 

# 处理缺失值与异常值

import numpy as np
import pandas as pd

datafile = '../data/air_data.csv' # 航空原始数据路径
cleanedfile = '../tmp/data_cleaned.csv' # 数据清洗后保存的文件路径

# 读取数据
airline_data = pd.read_csv(datafile,encoding = 'utf-8')
print('原始数据的形状为:',airline_data.shape)

# 去除票价为空的记录
airline_notnull = airline_data.loc[airline_data['SUM_YR_1'].notnull() &
airline_data['SUM_YR_2'].notnull(),:]
print('删除缺失记录后数据的形状为:',airline_notnull.shape)

# 只保留票价非零的,或者平均折扣率不为0且总飞行公里数大于0的记录。
index1 = airline_notnull['SUM_YR_1'] != 0
index2 = airline_notnull['SUM_YR_2'] != 0
index3 = (airline_notnull['SEG_KM_SUM']> 0) & (airline_notnull['avg_discount'] != 0)
index4 = airline_notnull['AGE'] > 100 # 去除年龄大于100的记录
airline = airline_notnull[(index1 | index2) & index3 & ~index4]
print('数据清洗后数据的形状为:',airline.shape)

airline.to_csv(cleanedfile) # 保存清洗后的数据

04-zscore_data.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#-*- coding: utf-8 -*- 

# 属性选择、构造与数据标准化

import pandas as pd
import numpy as np

# 读取数据清洗后的数据
cleanedfile = '../tmp/data_cleaned.csv' # 数据清洗后保存的文件路径
airline = pd.read_csv(cleanedfile, encoding = 'utf-8')
# 选取需求属性
airline_selection = airline[['FFP_DATE','LOAD_TIME','LAST_TO_END',
'FLIGHT_COUNT','SEG_KM_SUM','avg_discount']]
print('筛选的属性前5行为:\n',airline_selection.head())



# 构造属性L
L = pd.to_datetime(airline_selection['LOAD_TIME']) - pd.to_datetime(airline_selection['FFP_DATE'])
L = L.astype('str').str.split().str[0]
L = L.astype('int')/30

# 合并属性
airline_features = pd.concat([L,airline_selection.iloc[:,2:]],axis = 1)
airline_features.columns = ['L','R','F','M','C']
print('构建的LRFMC属性前5行为:\n',airline_features.head())

# 数据标准化
from sklearn.preprocessing import StandardScaler
data = StandardScaler().fit_transform(airline_features)
np.savez('../tmp/airline_scale.npz',data)
print('标准化后LRFMC五个属性为:\n',data[:5,:])

05-KMeans_cluster.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#-*- coding: utf-8 -*- 

# K-means聚类

import pandas as pd
import numpy as np
from sklearn.cluster import KMeans # 导入kmeans算法

# 读取标准化后的数据
airline_scale = np.load('../tmp/airline_scale.npz')['arr_0']
k = 5 # 确定聚类中心数

# 构建模型,随机种子设为123
kmeans_model = KMeans(n_clusters = k,n_jobs=4,random_state=123)
fit_kmeans = kmeans_model.fit(airline_scale) # 模型训练

# 查看聚类结果
kmeans_cc = kmeans_model.cluster_centers_ # 聚类中心
print('各类聚类中心为:\n',kmeans_cc)
kmeans_labels = kmeans_model.labels_ # 样本的类别标签
print('各样本的类别标签为:\n',kmeans_labels)
r1 = pd.Series(kmeans_model.labels_).value_counts() # 统计不同类别样本的数目
print('最终每个类别的数目为:\n',r1)



%matplotlib inline
import matplotlib.pyplot as plt
# 客户分群雷达图
cluster_center = pd.DataFrame(kmeans_model.cluster_centers_,\
columns = ['ZL','ZR','ZF','ZM','ZC']) # 将聚类中心放在数据框中
cluster_center.index = pd.DataFrame(kmeans_model.labels_ ).\
drop_duplicates().iloc[:,0] # 将样本类别作为数据框索引
print(cluster_center)
labels = ['ZL','ZR','ZF','ZM','ZC']
legen = ['客户群' + str(i + 1) for i in cluster_center.index] # 客户群命名,作为雷达图的图例
lstype = ['-','--',(0, (3, 5, 1, 5, 1, 5)),':','-.']
kinds = list(cluster_center.iloc[:, 0])
# 由于雷达图要保证数据闭合,因此再添加L列,并转换为 np.ndarray
cluster_center = pd.concat([cluster_center, cluster_center[['ZL']]], axis=1)
centers = np.array(cluster_center.iloc[:, 0:])

# 分割圆周长,并让其闭合
n = len(labels)
angle = np.linspace(0, 2 * np.pi, n, endpoint=False)
angle = np.concatenate((angle, [angle[0]]))

# 绘图
fig = plt.figure(figsize = (8,6))
ax = fig.add_subplot(111, polar=True) # 以极坐标的形式绘制图形
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 画线
for i in range(len(kinds)):
ax.plot(angle, centers[i], linestyle=lstype[i], linewidth=2, label=kinds[i])
# 添加属性标签
ax.set_thetagrids(angle * 180 / np.pi, labels)
plt.title('客户特征分析雷达图')
plt.legend(legen)
plt.show()
plt.close