Wenhua


  • 首页

  • 标签

  • 分类

  • 归档

precision和accuracy的区别

发表于 2019-04-12 | 分类于 ai

confusion matrix

True positive(TP), 真正例, 被正确的划分为正例的个数, 即实际为正例且被分类器划分为正例的实例数/样本数
True negative(TN), 真负例, 被正确的划分为负例的个数, 即实际为负例且被分类器划分为负例的实例数
False positive(FP), 假正例, 被错误的划分为正例的个数, 即实际为负例且被分类器划分为正例的实例数
False negative(FN), 假负例, 被错误的划分为负例的个数, 即实际为正例且被分类器划分为负例的实例数
参考

实际值为正例的是True positive(TP)和False negative(FN)
实际值为负例的是True negative(TN)和False positive(FP)
预测值为正例的是True positive(TP)和False positive(FP)
预测值为负例的是True negative(TN)和False negative(FN)

预测值 预测值
正例 负例
实际值 正例 true positive(TP)真正例 false negative(FN)假负例
实际值 负例 false positive(FP)假正例 true negative(TN)真负例

还可以用如下的方式进行理解
正例记为+1, 负例记为-1, true用+1表示, false用-1表示, 那么

difference between accuracy and precision

In the fields of engineering, industry and statistics, the accuracy of a measurement system is the degree of closeness of measurements of aquantity to its actual (true) value. The precision of a measurement system, also called reproducibility or repeatability, is the degree to which repeated measurements under unchanged conditions show the same results.[1] Although the two words can be synonymous in colloquial use, they are deliberately contrasted in the context of the scientific method.

Accuracy(准确度), is the difference between the measured value and the true value of a tested material.
Precision(精确度), is the repeatability of successive measurements under the same conditions.

Accuracy is how close a measured value is to the actual(true) value.
Precision is how close the measured values are to each other.

Accuracy, 指在一定实验条件下多次测试的平均值和真实值相符合的程度, 以误差表示
Precision, 指多次重复测试同一量时各测定值之间彼此相符合的程度, 表征测定过程中随机误差的大小

Accuracy = 被正确划分的样本/所有预测的样本 =(TP + TN) / (TP + FP + TN + FN), 通常来说, 正确率越高, 分类器越好
Precision = 真正例/预测为正例的样本 = TP / (TP + FP), 实际值为正例的样本占预测值为正例的比例
recall = 真正例/实际值为正例 = TP / (TP + FN), 召回率是覆盖面的度量, 实际值为正例的样本占实际值的比例, 召回率也叫做查全率

用来描述被检索为正例的数量有多少是被正确检索的

用来描述所有希望被检索的正例对象有多少被检索到了

理解precision和recall的另外一种角度

ROC, AUC和F-measure

ROC(Receiver Operating Characteristic), 受试者工作特征曲线, 在于曲线上各点反映着相同的感受性, 都是对同一信号刺激的反应, 只不过是在几种不同判定标准下得到的结果而已.
ROC反映了敏感性和特异性连续变量的综合指标, 用构图法揭示敏感性和特异性之间的相互关系, 通过将连续变量设定出多个不同的临界值, 从而计算出一系列敏感性和特异性, 再以敏感性为纵坐标, (1-特异性)为横坐标

纵轴是TPR(True Positive Rate), 横轴是1 - FPR(False Positive Rate)

AUC是ROC曲线下面积(Area Under roc Curve)的简称, 顾名思义, AUC的值就是处于ROC curve下方的那部分面积的大小. 通常, AUC的值介于0.5到1.0之间, AUC越大, 诊断准确性越高. 在ROC曲线上, 最靠近坐标图左上方的点为敏感性和特异性均较高的临界值.

Measuring Object Detection models - mAP - What is Mean Average Precision?

补充

练习1

y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]

真实值中a=2个1, b=2个0
预测值中c=1个1, d=3个0

TP = a - c = 1
TN = b = 2
FP = 0
FN = d - b = 1

True condition True condition
Total population Condition positive Condition negative
Predicted condition Predicted condition positive TP=1 FP=0
Predicted condition Predicted condition negative FN=1 TN=2

precision = TP/(TP+FP) = 1/1 = 1
recall = TP/(TP+FN) = 1/(1+1) = 0.5
acc = (TP+TN)/(TP+TN+FP+FN) = (1+2)/(1+1+2)=0.75

上面是手算的结果

直接用程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn import metrics

y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]

accuracy_score = metrics.accuracy_score(y_true, y_pred)
recall_score = metrics.recall_score(y_true, y_pred)
precision_score = metrics.precision_score(y_true, y_pred)

print(accuracy_score)
print(precision_score)
print(recall_score)

练习2

假如某个班级有男生80人,女生20人,共计100人.目标是找出所有女生.
现在某人挑选出50个人,其中20人是女生,另外还错误的把30个男生也当作女生挑选出来了.
作为评估者的你需要来评估(evaluation)下他的工作

真实值中, 被正确的分为女生的为TP=20, 被正确的分为男生的为TN=50
预测值中, 被错误的分为女生的为FP=30, 被错误的分为男生的为FN=0

True condition True condition
condition positive condition negative
Predicted condition Predicted condition positive TP=20 FP=30
Predicted condition Predicted condition negative FN=0 TN=50

precision = TP/(TP+FP) = 20/(20+30) = 0.4
recall = TP/(TP+FN) = 20/(20+0) = 1
acc = (TP+TN)/(all) = (20+50)/(100) = 0.7
F1_measure = (0.412)/(0.4+1) = 0.5714

例子

练习3

假设一个班级有100个学生,其中男生70人,女生30人。不知道这些学生的性别,只知道他们的身高和体重。我们有一个程序(分类器),这个程序可以通过分析每个学生的身高和体重,对这100个学生的性别分别进行预测。最后的预测结果为,60人为男生,40人为女生

有两种方法来区分

第一种方法

设正例为男生, 那么负例就是女生
TP真正例, 实际值为男生, 预测值为男生
TN真负例, 实际值为女生, 预测值为女生
FP假正例, 实际值为女生, 预测值为男生
FN假负例, 实际值为男生, 预测值为女生

TP + FN = 70
TN + FP = 30
TP + FP = 60
TN + FN = 40

计算过程如下
TP, TN, FP, FN
1, 0, 0, 1, 70
0, 1, 0, 1, 40
0, 0, 1, -1, -10
0, 0, 0, 0, 0

FN - FP = 10

当FP=20, FN=30, TN=10, TP=40
acc = (TP+TN)/all = 50/100
precision = TP/(TP+FP) = 40/60
recall = TP/(TP+FN) = 40/70

当FP=10, FN=20, TN=20, TP=50
acc = (TP+TN)/all = 70/100
precision = TP/(TP+FP) = 50/60
recall = TP/(TP+FN) = 50/70

第二种方法

设正例为女生, 那么负例就是男生
TP真正例, 实际值为女生, 预测值为女生
TN真负例, 实际值为男生, 预测值为男生
FP假正例, 实际值为男生, 预测值为女生
FN假负例, 实际值为女生, 预测值为男生

TN+FP=70
TP+FN=30
TN+FN=60
TP+FP=40

TP TN FP FN b
0 1 1 0 70
1 0 0 1 30
0 1 0 1 60
1 0 1 0 40

1 0 0 1 30
1 0 1 0 40
0 1 1 0 70
0 1 0 1 60

1 0 0 1 30
0 1 1 0 70
0 0 1 -1 10
0 0 0 0 0

TP TN FP FN b
1 0 0 1 30
0 1 0 1 60
0 0 1 -1 10
0 0 0 0 0

TP=30-FN
TN=60-FN
FP=10+FN

令FN=10, TP=20, TN=50, FP=20
acc = (TP+TN)/all = 70/100
precision = TP/(TP+FP) = 20/40
recall = TP/(TP+FN) = 20/30

令FN=20, TP=10, TN=40, FP=30
acc = (TP+TN)/all = 50/100
precision = TP/(TP+FP) = 10/40
recall = TP/(TP+FN) = 10/30

梯度下降

发表于 2019-03-17 | 分类于 ai

梯度下降

梯度下降是常用的卷积神经网络模型参数的求解方法, 根据每次参数更新使用样本数量的多少, 可以分为以下三类:

  • 批量梯度下降(batch gradient descent, BGD)
  • 小批量梯度下降(mini-batch gradient descent, MBGD)
  • 随机梯度下降(stochastic gradient descent, SGD)

求参数过程即最小化损失函数过程, 比如有一个含有D个训练数据的数据集, 损失函数为:

$f_W(X^{(i)})$是单个样本$X^{(i)}$的损失, $\gamma(W)$是正则项, $\lambda$是权重

批量梯度下降

量梯度下降(batch gradient descent, BGD), 是梯度下降法最原始的形式, 具体思路是在更新每一组参数的时候都使用所有的样本进行更新, 如果是几百万个样本集的话, 训练时间和内存将都不可取

随机梯度下降

随机梯度下降(stochastic gradient descent, SGD), 是为了解决批量梯度下降法在训练过程中随着样本数量的增加而变得异常缓慢的问题提出的

小批量梯度下降

批量梯度下降和随机梯度下降都有各自的优缺点, 不能取得性能和准确率之间的平衡, 而小批量梯度下降(mini-batch gradient descent, MBGD), 是在每次更新参数时时使用b个样本(b一般为较小的数, 如100)

梯度下降法_L8

梯度下降法(Gradient Descent, GD)常用于求解无约束情况下凸函数(Convex Function)的极小值, 是一种迭代类型的算法, 因为凸函数只有一个极值点, 故求解出来的极小值就是函数的最小值点

导数: 一个函数在某一点的导数描述类这个函数在这一点附近的变化率, 也可以认为是函数在某一点的导数就是该函数所代表的曲线在这一点的切线斜率. 导数值越大, 表示函数在该点处的变化越大.

梯度: 梯度是一个向量, 表示某一函数在该点处的方向导数沿着该方向取的最大值, 即函数在该点处沿着该方向变化最快, 变化率最大(即该梯度向量的模); 当函数为一维函数的时候, 梯度就是导数

梯度下降法的优化思想是用当前位置负梯度方向作为搜索方向, 因为该方向为当前位置的最快下降方向, 所以梯度下降法也称为”最速下降法”. 梯度下降法中越接近目标值, 变量变化越小, 如下:

$\alpha$称为步长或者学习率(learning rate), 表示自变量$x$每次迭代变化的大小

收敛条件: 当目标函数的函数值变化非常小的时候或者达到最大迭代次数的时候, 就结束循环

由于梯度下降法中负梯度方向作为变量的变化方向, 所有有肯能导致最终解的值是局部最优解, 所以在使用梯度下降的时候, 一般需要进行一些调优策略

  • 学习率的选择: 学习率过大, 表示每次迭代更新的时候变化比较大, 有可能会跳过最优解; 学习率过小, 表示每次迭代更新的时候变化比较小, 就会导致迭代速度过慢, 很长时间都不能结束
  • 算法初始参数值的选择: 初始值不同, 最终获得的最小值也有可能不同, 因为梯度下降法求解的是局部最优解, 所以一般情况下, 选择多次不同初始值运行算法, 并最终返回损失函数最小情况下的结果值
  • 标准化: 由于样本不同特征的取值范围不同, 可能导致在各个不同参数上迭代速度不同, 为了减少特征取值的影响, 可以将特征进行标准化操作

批量梯度下降法(Batch Gradient Descent, BGD)

使用所有样本在当前点的梯度值对变量参数进行更新操作

随机梯度下降法(Stochastic Gradient Descent, SGD)

在更新变量参数的时候, 选取一个样本的梯度值来更新参数

小批量梯度下降法(Mini-batch Gradient Descent, MBGD)

集合BGD和SGD的特性, 从原始数据中, 每次选择n个样本来更新参数值, 一般n选择10

BGD/SGD/MBGD的区别

  • 当样本量为m的时候, 每次迭代BGD算法中对于参数值更新一次, SGD算法中对于参数值更新m次, MBGD算法中对于参数值更新$m/n$次, 相对来讲SGD算法的更新速度最快
  • SGD算法中对于每个样本都需要更新参数值, 当样本值不太正常的时候, 就有可能会导致本次的参数更新会产生相反的影响, 也就是说SGD算法的结果并不是完全收敛的, 而是在收敛结果处波动的
  • SGD算法是每个样本都更新一次参数值, 所以SGD算法特别适合样本数据量大的情况以及在线机器学习(Online ML)

L9

发表于 2019-02-14 | 分类于 ai

马尔可夫性质

设$\{X(t), t \in T\}$是一个随机过程, E是其状态空间, 若对于任意的$t_1 < t_2 < \cdots < t_n < t$, 任意的$x_1 < t_2 < \cdots < t_n < t$, 任意的$x_1, x_2, \cdots, x_n, x \in E$, 随机变量$X(t)$在已知变量$X(t_1) = x_1, \cdots, X(t_n) = x_n$下的条件分布函数只与$X(t_n)=x_n$有关, 而与$X(t_1)=x_1, \cdots, X(t_{n-1})=x_{n-1}$无关, 即条件分布函数满足下列等式, 此性质称为马尔可夫性质; 如果随机过程满足马尔可夫性质, 则该过程称为马尔可夫过程.

马尔可夫链

马尔可夫链是指具有马尔可夫性质的随机过程. 在过程中, 在给定当前信息的情况下, 过去的信息状态对于预测未来状态是无关的.

在马尔可夫链的每一步, 系统根据概率分布, 可以从一个状态变成另外一个状态, 也可以保持当前状态不变. 状态的改变叫做转移, 状态改变的相关概率叫做转移概率

马尔可夫链中的三元素是: 状态空间S, 转移概率矩阵P, 初始概率分布$\pi$

HMM

隐马尔可夫模型(Hidden Markov Model, HMM)是一种统计模型, 在语音识别, 行为识别, NLP, 故障诊断等领域具有高效的性能.

HMM是关于时序的概率模型, 描述一个含有未知参数的马尔可夫链所生成的不可观测的状态随机序列, 再由各个状态生成观测随机序列的过程. HMM是一个双重随机过程, 具有一定状态的隐马尔可夫链和随机的观测序列.

HMM随机生成的状态随机序列被称为状态序列; 每个状态生成一个观测, 由此产生的观测随机序列被称为观测序列.

$z_1, z_2, \cdots, z_n$是不可观测的状态, $x_1, x_2, \cdots, x_n$是可观测到的序列; 不可观测的状态决定可观测序列的值(z的取值决定x的取值)

HMM由隐含状态S, 可观测状态O, 初始状态概率矩阵$\pi$, 隐含状态转移概率矩阵A, 可观测值转移概率矩阵B(也称为混淆矩阵, Confusion Matrix)

$\pi$和A决定了状态序列, B决定观测序列, 因此HMM可以使用三元符号表示, 称为HMM三元素

HMM参数说明

HMM模型

S是所有可能的状态集合

O是所有可能的观测集合

I是长度为T的状态序列, Q对应的观测序列

A是隐含状态转移概率矩阵

其中$a_{ij} = a_{i_t i_{t+1}}= p(i_{t+1}=s_j | i_t = s_i)$, 表示在时刻$t$处于状态序列中$s_i$状态的条件下时刻$t+1$转移到状态$s_j$的概率

B是可观测值转移概率矩阵

其中$b_{ij} = b_{i_t q_t} = p( q_t = o_j | i_t=s_i)$, 表示在时刻$t$处于状态序列中$s_i$状态的条件下, 生成可观测状态$o_j$的概率

$\pi$是初始状态概率向量

其中$\pi_{i_1} = p(i_1 = s_i)$, 表示在时刻$t=1$处于状态序列中$s_i$的概率

HMM的两个性质

看这个意思就是当前状态的概率只和上一个状态的概率有关, 与其他都没有关系

HMM案例

假设有三个盒子, 编号分别为1, 2, 3; 每个盒子都装有黑白两种颜色的小球, 小球的比例如下:

编号 白球 黑球
1 4 6
2 8 2
3 5 5
  • 按照$\pi$的概率选择一个盒子, 从盒子中随机抽取一个小球, 记录颜色后, 放回盒子中
  • 按照某种条件概率选择新的盒子, 重复该操作
  • 最终得到的观测序列为: “白黑白白黑”

对该题目的理解如下:

有放回的按照概率$\pi$来抽取, 假如第一次抽取的是1号盒子, 第二次抽取的是3号盒子, 接下来是2号, 2号, 3号, 举个例子, 所以

3号 -> 2号 -> 1号 -> 1号 -> 2号, 状态序列
白球 -> 黑球 -> 白球 -> 白球 -> 黑球, 观测序列

HMM的的三个问题

  • 概率计算问题
    给定模型$\lambda=(A, B, \pi)$和观测序列$Q = \{q_1, q_2, \cdots, q_T\}$, 利用前向-后向算法计算模型$\lambda$之下观测到序列Q出现的概率
  • 学习问题
    已知观测序列$Q = \{q_1, q_2, \cdots, q_T\}$, 使用Baum-Welch算法估计模型$\lambda=(A, B, \pi)$的参数, 使得在该模型下观测序列$p(Q|\lambda)$最大
  • 预测问题
    给定模型$\lambda=(A, B, \pi)$和观测序列$Q = \{q_1, q_2, \cdots, q_T\}$, 利用Viterbi算法求解给定观测序列条件概率$p(I|Q, \lambda)$的最大状态序列$I$

概率计算问题

直接计算法/暴力算法

给定模型$\lambda=(A, B, \pi)$和观测序列$Q = \{q_1, q_2, \cdots, q_T\}$, 计算在模型$\lambda$的情况下, 得到观测序列Q出现的概率$p(Q; \lambda)$

要想得到观测序列”白球 -> 黑球 -> 白球 -> 白球 -> 黑球”这样的结果, 又因为每个盒子都是有白球和黑球的, 然而我们并不知道状态序列及抽取的盒子的序列是什么样的, 所以如下:

按照概率公式, 列举所有可能的长度为T的状态序列$I = \{ i_1, i_2, \cdots, i_T\}$, 先求出各个状态序列与观测序列$Q=\{q_1, q_2, \cdots, q_T\}$的联合概率$P(Q,I; \lambda)$, 然后对所有可能的状态序列求和, 从而得到最后的概率$p(Q;\lambda)$

假设抽取盒子的状态序列 $I = 3号, 2号, 1号, 1号, 2号$, 那么该状态序列的长度$T = 5$

上述只是求出了一种盒子的状态序列, 因为每个盒子里边既有白球又有黑球, 所以盒子的状态序列总共有$3^5$种可能.

然后对所有可能的状态序列求和

前向概率/后向概率

$\alpha_t$是给定$q_t$, 时刻1到时刻t所有观测值$y_1, y_2, \cdots, y_t, q_t$出现的联合概率
$\beta_t$是给定$q_t$, 时刻t+1到时刻T, 所有观测值$y_{t+1}, y_{t+2}, \cdots, y_T$出现的联合概率

前向概率-后向概率指的是在一个观测序列中, 时刻t对应状态$s_i$的概率值转换过来的信息

前向算法

给定$\lambda$, 定义前向概率为, 在时刻t观测序列为$q_1, q_2, \cdots, q_t$, 状态序列的当前状态为$s_i$的概率, 记为:

初值$\alpha_1(i) = p(q_1, i_1=s_i; \lambda) = \pi_i b_{i q_1}$, 表示在时刻$t=1$, 观测序列为$q_1$和状态序列的当前状态为$s_i$的联合概率

递推: 对于$t=1, 2, \cdots, T-1$

最终

后向算法

给定$\lambda$, 定义后向概率为, 在时刻t状态序列的当前状态为$s_i$的前提下, 从时刻$t+1$到时刻T部分的观测序列为$q_{t+1}, q_{t+2}, \cdots, q_T$的概率, 记为:

初值: $\beta_T(i) = 1$, 根据$\beta_t(i)$的公式, 令$t=T$, 那么整个状态序列和观测序列总共只有T个时刻, 是不可能有$T+1$时刻的, 所以$T+1$时刻之后发生的是必然事件, 所以$\beta_T(i) = 1$
递推: 对于$t = T-1, T-2, \cdots, 1$, 倒着推导

最终

根据上述$\beta_t$的定义, $\beta_t(i)$是给定$q_t$, 时刻$t+1$到时刻$T$, 所有观测值$y_{t+1}, y_{t+2}, \cdots, y_T$的联合概率, 如下图所示:

那么$\beta_{t+1}(i)$就是给定$q_t$(这里为什么不是$q_{t+1}$), 时刻$t+2$到时刻$T$, 所有观测值$y_{t+2}, \cdots, y_T$的联合概率, 如下图所示:

单个状态的概率

求给定模型$\lambda$和观测序列Q的情况下, 在时刻t处于状态序列中$s_i$的概率, 计作:

单个状态概率的意义主要是用于判断在每个时刻最可能存在的状态序列中的状态, 从而可以得到整个状态序列作为最终的预测结果

两个状态的联合概率

求给定模型$\lambda$和观测序列Q的情况下, 在时刻t处于状态$s_i$并且在时刻$t+1$处于状态$s_j$概率, 计作:

学习问题

若训练数据包含观测序列和状态序列, 则HMM的学习问题非常简单, 是监督学习算法
若训练数据值包含观测序列, 则HMM的学习问题需要使用EM算法求解, 是非监督学习算法

学习问题-监督学习

直接利用大数定理的结论”频率的极限是概率”, 直接给出HMM的参数估计

学习问题-非监督学习

预测问题

近似算法

直接在每个时刻t时候最有可能的状态作为最终的预测状态, 使用下列公式计算概率值

viterbi算法

viterbi算法实际是用动态规划的思路求解HMM预测问题, 求概率最大的”路径”, 每条”路径”对应一个状态序列

viterbi算法案例

给定参数$\pi, A, B$, 得到观测序列为”白黑白白黑”, 求出最优的隐藏状态序列

同样的方法继续计算$\delta_3(i), \delta_4(i), \delta_5(i)$, 得到如下:

从$\delta_5$得知, $\delta_5(3)$最大, 往前推导, 第5个状态是由$\delta_4$的哪个产生的?
由$max(0.00384 \ast 0.1, 0.00768 \ast 0.6, 0.0144 \ast 0.3)$
得到是由$\delta_4(2)$来的, 依次往回倒推

1
2
5 -> 4 -> 3 -> 2 -> 1
3 -> 2 -> 2 -> 3 -> 2

可以看出盒子的序列为(2, 3, 2, 2, 3)

参考
盒子顺序的正确解释

L8

发表于 2019-02-05 | 分类于 ai

多项式回归

在线性回归中, 可以通过多项式扩展将低维度扩展成为高维度数据, 从而可以使用线性回归模型来解决问题. 即对于二维空间中不是线性可分的数据, 将其映射到高维空间中后, 变成了线性可分的数据

两维线性模型:

五维线性模型:

核函数

假设函数$\phi$是一个从低维特征空间到高维特征空间到一个映射, 那么如果存在函数$K(x,z)$, 对于任意的低维度特征向量x和z, 都有$K(x, z) = \phi(x) \cdot \phi(z)$, 该函数称为核函数

核函数在解决线性不可分问题的时候, 采用的方式是: 使用低维特征空间的计算来避免在高维特征空间中向量内积的恐怖计算量, 也就是说此时SVM模型可以应用在高维特征空间中数据可线性分割的优点, 同时也避免来引入这个高维特征空间恐怖的内积计算量

设两个向量$x_1 = (\mu_1, \mu_2)^T$和$x_2 = (\eta_1, \eta_2)^T$, 映射过后的内积为:

同时发现另外一个公式:

上述两个公式非常相似, 只要乘上一个相关系数, 就可以让两个式子的值相等, 这样就可以将五维空间的一个内积转换为两维的内积运算

  • 线性核函数(Linear Kernel)
  • 多项式核函数(polynomial Kernal), 其中$\gamma, r, d$属于超参, 需要调参定义
  • 高斯核函数(Gaussian Kernal), 其中$\gamma$属于超参, 要求大于0, 需要调参定义
  • Sigmoid核函数(Sigmoid Kernal), 其中$\gamma, r$属于超参, 需要调参定义

核函数总结

  • 核函数可以自定义, 核函数必须是正定核函数, 即Gram矩阵是半正定矩阵
  • 核函数的价值在于它虽然也是将特征进行从低维度到高维度的转换, 但核函数事先在低维上进行计算, 而将实质的分类效果表现在了高维上, 也就避免了直接在高维空间上的复杂计算
  • 通过核函数, 可以将非线性可分的数据转换为线性可分数据

\begin{bmatrix}
{K(x_1, x_1)}&{K(x_1, x_2)}&{\cdots}&{K(x_1, x_m)}\\
{K(x_2, x_1)}&{K(x_2, x_2)}&{\cdots}&{K(x_2, x_m)}\\
{\vdots}&{\vdots}&{\ddots}&{\vdots}\\
{K(x_m, x_1)}&{K(x_m, x_2)}&{\cdots}&{K(x_m, x_m)}\\
\end{bmatrix}

高斯核函数

令$z=x$, 进行多维变换后, 应该是同一个向量, 从而得到以下公式:

非线性可分SVM

不管是线性可分SVM还是加入惩罚系数的软间隔线性可分SVM其实都是要求数据本身都是线性可分的, 对于完全不可以线性可分的数据, 这两种算法模型就没法解决这个问题了

SMO

未完待续

贝叶斯算法

贝叶斯定理相关公式

朴素贝叶斯算法

朴素贝叶斯算法推导

朴素贝叶斯算法流程

高斯朴素贝叶斯

伯努利朴素贝叶斯

多项式朴素贝叶斯

案例一: 鸢尾花数据分类

案例二: 文本数据分类

贝叶斯网络

最简单的贝叶斯网络

全连接贝叶斯网络

正常贝叶斯网络

实际贝叶斯网络: 判断是否下雨

贝叶斯网络判定条件独立

如果x是连续的, 一般选择高斯朴素贝叶斯; 如果x是离散的, 一般选择多项式朴素贝叶斯; 如果x既有连续值又有离散值, 选择高斯朴素贝叶斯

EM

最大似然估计回顾

MLE就是利用已知的样本结果, 反推最有可能(最大概率)导致这样结果的参数值的计算过程. 就是给定了一定的数据, 假定知道数据是从某种分布中随机抽取出来的, 但是不知道这个分布具体的参数值, 即”模型已定, 参数未知”, MLE就是用来估计模型的参数的. MLE的目标是找出一组参数(模型中的参数), 使得模型产出观察数据的概率最大.

贝叶斯算法估计

  • 贝叶斯算法估计是一种从先验概率和样本分布情况来计算后验概率的一种方式
  • 贝叶斯算法中的常见概念
    • p(A)是事件A的先验概率或者边缘概率
    • p(A|B)是已知B发生后A发生的条件概率, 也称为A的后验概率
    • p(B|A)是已知A发生后B发生的条件概率, 也称为B的后验概率
    • p(B)是事件B的先验概率或者边缘概率

假设有5个盒子, 假定每个盒子中都有黑白两种球, 并且黑白球的比例如下; 已知从这5个盒子中的任意一个盒子中有放回的抽取两个球, 且均为白球, 问这两个球是从哪个盒子中抽取出来的?

盒子编号 白球(p) 黑球(q)
1 0 1
2 0.3 0.7
3 0.5 0.5
4 0.7 0.3
5 1 0
1 2 3 4 5
p(A) 0.2 0.2 0.2 0.2 0.2

使用MLE(最大似然估计), 结论是从第5个盒子抽取的球:

使用贝叶斯算法估计, 结论是从第5个盒子抽取的球: 假设抽出白球为事件B, 从第i个盒子中抽取为事件$A_i$

$p(B|A_i)$, 抽到第i个盒子的概率 乘以 在第i个盒子中第一次抽出的球为白球的概率 乘以 在第i个盒子中第二次抽出的球为白球的概率

$p(B)$, 从任意一个盒子中有放回的抽取两个球, 且均为白球的概率

$p(A_1|B)$, 两抽为白的是第一个盒子的后验概率
$p(A_1)$, 抽到第一个盒子的先验概率
$p(B|A_1)$, 抽到第一个盒子并且两抽为白的条件概率
$p(B)$, 任意的盒子, 两抽为白的边缘概率

现在不是从5个盒子中任选一个盒子进行抽取, 而是按照一定的概率选择对应的盒子, 概率如下. 结论是从第4个盒子抽取的

1 2 3 4 5
p(A) 0.1 0.2 0.2 0.4 0.1

最大后验概率估计

MAp(Maximum a posteriori estimation), 和MLE一样, 都是通过样本估计参数$\theta$的值; 在MLE中, 是使得似然函数$p(X|\theta)$最大的时候参数$\theta$的值, MLE中假设先验概率是一个等值的; 而在MAp中, 则是求$\theta$使$p(X|\theta)p(\theta)$的值最大, 这就要求$\theta$值不仅仅是让似然函数最大, 同时要求$\theta$本身出现的先验概率也得比较大

可以认为MAp是贝叶斯算法的一种应用

K-means算法回顾

K-means算法, 也叫做k-均值聚类算法, 是一种非常广泛使用的聚类算法之一
假定输入样本为$S=x_1, x_2, \cdots, x_m$, 则算法步骤为:

  • 选择初始的k个簇中心点$\mu_1, \mu_2, \cdots, \mu_k$
  • 将样本$x_i$标记为距离簇中心最近的簇: $label_i = arg \min \limits_{1 \le j \le k} \Vert x_i - \mu_j \Vert$
  • 迭代处理所有样本数据, 计算出各个样本点所属的对应簇
  • 更新簇中心点坐标$\mu_i = \displaystyle \frac{1}{\vert C_i \vert} \sum_{j \in C_i} x_j$
  • 重复上述三个操作, 直到算法收敛
    算法收敛条件: 迭代次数/簇中心变化率/MSE/MAE

EM算法引入

公司有男同事=[A,B,C],同时有很多漂亮的女职员=[小甲,小章,小乙]。(请勿对号入座)你迫切的怀疑这些男同事跟这些女职员有“问题”。为了科学的验证你的猜想,你进行了细致的观察。于是:
观察数据:

  • A,小甲、小乙一起出门了;
  • B,小甲、小章一起出门了;
  • B,小章、小乙一起出门了;
  • C,小乙一起出门了;
初始化

你觉得三个同事一样帅,一样有钱,三个美女一样漂亮,每个人都可能跟每个人有关系。所以,每个男同事跟每个女职员“有问题”的概率都是1/3;

EM算法中的E步骤
  • A和小甲出去过的次数为$\displaystyle \frac{1}{2} \cdot \frac{1}{3} = \frac{1}{6}$, 和小乙出去的次数也是$\displaystyle \frac{1}{6}$
  • B和小甲, 小章出去的次数分别为$\displaystyle \frac{1}{6}$
  • B和小章, 小乙出去的次数分别为$\displaystyle \frac{1}{6}$
  • C和小乙出去的次数为$\displaystyle \frac{1}{3}$

归纳总结:

  • A和小甲出去了$\displaystyle \frac{1}{6}$次, 和小乙出去了$\displaystyle \frac{1}{6}$次
  • B和小甲出去了$\displaystyle \frac{1}{6}$次, 和小乙出去了$\displaystyle \frac{1}{6}$次, 和小章出去了$\displaystyle \frac{1}{3}$次
  • C和小乙出去了$\displaystyle \frac{1}{3}$次
EM算法中的M步骤
  • A和小甲, 小乙有问题的概率为$\displaystyle \frac{1/6}{1/6 + 1/6} = \frac{1}{2}$
  • B和小甲, 小乙有问题的概率为$\displaystyle \frac{1/6}{1/6 + 1/6 + 1/6 + 1/6} = \frac{1}{4}$
  • B和小章有问题的概率为$\displaystyle \frac{1/3}{1/6 + 1/6 + 1/3} = \frac{1}{2}$
  • C和小乙有问题的概率为$\displaystyle \frac{1/3}{1/3} = 1$
第二次迭代EM算法中的E步骤

根据已知条件

  • A,小甲、小乙一起出门了;
  • B,小甲、小章一起出门了;
  • B,小章、小乙一起出门了;
  • C,小乙一起出门了;

结合上个M步骤更新的概率

  • A和小甲出去了$\displaystyle \frac{1}{2} \cdot \frac{1}{2} = \frac{1}{4}$次, 和小乙出去了$\displaystyle \frac{1}{4}$次
  • B和小甲出去了$\displaystyle \frac{1}{2} \cdot \frac{1}{4} = \frac{1}{8}$次, 和小章出去了$\displaystyle \frac{1}{2} \cdot \frac{1}{2} = \frac{1}{4}$次,
  • B和小章出去了$\displaystyle \frac{1}{2} \cdot \frac{1}{2} = \frac{1}{4}$次, 和小乙出去了$\displaystyle \frac{1}{2} \cdot \frac{1}{4} = \frac{1}{8}$次
  • C和小乙出去了1次

归纳总结:

  • A和小甲出去了$\displaystyle \frac{1}{4}$次, 和小乙出去了$\displaystyle \frac{1}{4}$次
  • B和小甲出去了$\displaystyle \frac{1}{8}$次, 和小乙出去了$\displaystyle \frac{1}{8}$次, 和小章出去了$\displaystyle \frac{1}{2}$次
  • C和小乙出去了1次
第二次迭代EM算法中的M步骤
  • A和小甲, 小乙有问题的概率为$\displaystyle \frac{1/4}{1/4 + 1/4} = \frac{1}{2}$
  • B和小甲, 小乙有问题的概率为$\displaystyle \frac{1/8}{1/8 + 1/8 + 1/2} = \frac{1}{6}$
  • B和小章有问题的概率为$\displaystyle \frac{1/2}{1/8 + 1/8 + 1/2} = \frac{2}{3}$
  • C和小乙有问题的概率为1

你继续计算,反思,总之,最后,你得到了真相。

通过上面的计算我们可以得知,EM算法实际上是一个不停迭代计算的过程,根据我们事先估计的先验概率A,得出一个结果B,再根据结果B,再计算得到结果A,然后反复直到这个过程收敛。
可以想象饭店的后方大厨,炒了两盘一样的菜,现在,菜炒好后从锅中倒入盘,不可能一下子就分配均匀,所以先往两盘中倒入,然后发现B盘菜少了,就从A中匀出一些,A少了,从B匀…..

EM算法

EM算法原理

给定m个训练样本${x(1), x(2), \cdots, x(m)}$, 样本间独立, 找出样本的模型参数$\theta$, 极大化模型参数的对数似然函数, 如下:

假定样本中存在隐含数据$z={z(1), z(2), \cdots, z(k)}$, 此时极大化模型分布的对数似然函数如下:

Q(z)是一个随机变量的分布, 每一个取值对应的概率密度之和等于1.
$E(Y) = E(g(x)) = \sum_i g(x_i)p_i$, $\displaystyle \sum_z Q(z; \theta) = 1$

令z的分布为$Q(z; \theta)$, 并且$Q(z; \theta) \ge 0$, 那么如上的极大似然估计的最大化的函数$l(\theta)$

一般情况下, z是隐含变量, 不知道应该取多少合适, 但是可以通过最后得到的公式对z进行求解. 如果最后两步相等的话, 就用公式的最后一步去替代$l(\theta)$, 进而得到新公式的最大值. 那么最后两步在什么情况下才能相等?

根据不等式的性质, 当下面式子中的对数中的随机变量为常数的时候, $l(\theta)$和右边的式子取等号

所以最后, 当$Q(z; \theta) = p(z|x; \theta)$的时候$l(\theta)$函数取得等号

EM算法流程

样本数据$X={x_1, x_2, \cdots, x_m}$, 联合分布$p(x, z; \theta)$, 条件分布$p(z|x; \theta)$, 最大迭代次数J

  • 随机初始化模型参数$\theta$的初始值$\theta_0$
  • 开始EM算法的迭代处理:
    • E步: 计算联合分布的条件概率期望, $Q^j = p(z|x; \theta^j) \quad l(\theta) = \displaystyle \sum_{i=1}^{m} \sum_z Q^j log(p(x, z; \theta^j))$
    • M步: 极大化L函数, 得到$\theta^{j+1}$, $\theta^{j+1} = arg \max \limits_{\theta} l(\theta)$
    • 如果$\theta^{j+1}$已经收敛, 则算法结束, 输出最终的模型参数$\theta$, 否则继续迭代处理
EM算法直观案例

假设现有两个装有不定数量黑球和白球的盒子, 随机从盒子中抽取出一个白球的概率分布为$p_1$和$p_2$; 为了估计这两个概率, 每次选择一个盒子, 有放回的连续随机抽取5个球, 记录如下:

盒子编号 1 2 3 4 5 统计
1 白 白 黑 白 黑 3白2黑
2 黑 黑 白 白 黑 2白3黑
1 白 黑 黑 黑 黑 1白4黑
2 白 黑 白 黑 白 3白2黑
1 黑 白 黑 白 黑 2白3黑

使用MLE最大似然估计:

同理

如果现在不知道具体的盒子编号, 但是同样还是为了求解$p_1$和$p_2$的值, 这个时候就相当于多了一个隐藏变量z, z表示每次抽取的时候选择的盒子编号, 比如$z_1$表示第一次抽取的时候选择的是盒子1还是盒子2

盒子编号 1 2 3 4 5 统计
z1 白 白 黑 白 黑 3白2黑
z2 黑 黑 白 白 黑 2白3黑
z3 白 黑 黑 黑 黑 1白4黑
z4 白 黑 白 黑 白 3白2黑
z5 黑 白 黑 白 黑 2白3黑

随机初始化一个概率值: $p_1=0.1$和$p_2=0.9$; 然后使用最大似然估计计算每轮操作中从两个盒子中抽取的最大概率. 然后使用计算出来的z值, 重新使用极大似然估计法估计概率值

轮数 盒子1 盒子2
1 0.00081 0.00729
2 0.00729 0.00081
3 0.06561 0.00009
4 0.00081 0.00729
5 0.00729 0.00081

在这里, 切记$p_1$表示从盒子1中抽取到白球的概率, $p_2$表示从盒子2中抽取到白球的概率, 那么上述表格就表示第1轮从盒子2中抽取的概率较大, 第2轮从盒子1中抽取的概率较大, 总结一下就是第1, 4轮从盒子1中抽取的概率较大, 第2, 3, 5轮从盒子2中抽取的概率较大

那么更新一下原始表格如下:

盒子编号 1 2 3 4 5 统计
2 白 白 黑 白 黑 3白2黑
1 黑 黑 白 白 黑 2白3黑
1 白 黑 黑 黑 黑 1白4黑
2 白 黑 白 黑 白 3白2黑
1 黑 白 黑 白 黑 2白3黑

根据此表格, 得出$p_2=\frac{6}{10}=0.6, \quad p_1=\frac{5}{15}=\frac{1}{3}$

轮数 盒子1 盒子2
1 0.01565 0.03456
2 0.0313 0.02304
3 0.0626 0.01536
4 0.01565 0.03456
5 0.0313 0.02304

使用最大似然概率法则估计z和p的值, 但是在这个过程中, 只使用一个最有可能的值. 如果考虑所有的z值, 然后对每一组z值都估计一个概率p, 那么这个时候估计出来的概 率可能会更好, 可以用期望的方式来简化这个操作

归一化操作

轮数 盒子1 盒子2
1 0.00081/(0.00081+0.00729) = 0.1 0.00729/(0.00081+0.00729) = 0.9
2 0.00729 0.00081
3 0.06561 0.00009
4 0.00081 0.00729
5 0.00729 0.00081
EM算法收敛证明

EM算法的收敛性只要能够证明对数似然函数的值在迭代过程中是增加的就可以

构造函数如下:

而

然而如下问题
随机选择1000名用户, 测量用户的身高; 若样本中存在男性和女性, 身高分别服从高斯分布$N(\mu_1, \sigma_1)$和$N(\mu_2, \sigma_2)$的分布, 试估计参数: $\mu_1, \sigma_1, \mu_2, \sigma_2$;

解析:

  • 如果明确的知道样本的情况(即男性和女性数据是分开的), 那么我们使用极大似然估计来估计这个参数值
  • 如果样本是混合而成的, 不能明确的区分开, 那么就没法直接使用极大似然估计来进行参数的估计. 可以使用EM算法来估计男女这两个参数值, 即男女这两个性别就变成了隐含变量. 实际上, EM算法在某些层面上是在帮助我们做聚类的操作. 即帮助我们找到隐含变量的取值.

GMM

GMM(Gaussian Mixture Model), 高斯混合模型, 是指该算法由多个高斯模型线性叠加混合而成, 每个高斯模型称为component. GMM算法描述的是数据本身存在的一种分布
GMM常用于聚类应用中, component的个数就可以认为是类别的数量
假定GMM由k个Gaussian分布线性叠加而成, 那么概率密度函数如下:

对数似然函数

E step

M step

对均值求偏导


对方差求偏导

对概率使用拉格朗日乘子法求解

多分类及多标签分类

单标签二分类

单标签多分类

多标签分类算法

L7

发表于 2019-01-20 | 分类于 ai

回顾

决策树和集成学习

  • 分类决策树和回归决策树
  • 决策树的构建

    • 目的: 让同一个类别/y的取值接近的样本在同一个叶子节点中, 让一个叶子节点中的样本足够的”纯”
    • “纯”的度量方式(值越大表示数据越不”纯”)
      • 信息熵(分类)
      • gini系数(分类)
      • 错误率(分类)
      • MSE(回归)
      • MAE(回归)
    • 进行数据划分的特征属性的选择
      • 基于划分前”纯”度的指标和划分后”纯”度值之间的差距, 作为特征属性的选择, 叫做信息增益, 选择增益越大的特征属性作为最终的划分数据
        基于划分前”纯”度的指标和划分后”纯”度值之间的差距, 然后相对于划分属性的”纯”度值的比率, 作为特征属性选择的依据, 叫做信息增益率, 选择增益率最大的特征属性作为最终的划分属性
    • 数据的划分方式
      • 对于离散数据, 如果是构建多叉树, 那么此时一个特征的取值就是一个分支
      • 对于离散数据, 如果是构建二叉树, 那么将离散数据转换为”属于该值”和”不属于该值”两个类别, 然后再每个类别一个分支
      • 对于连续数据, 在连续数据中找出一个split_point点, 然后让大于等于split_point的数据属于一个分支, 让其他数据属于另外一个分支
  • 决策树的预测

  • 欠拟合和过拟合

    • 欠拟合解决方案: 可以通过增加树的层次来解决这个问题, 但是如果层次足够高的话又会导致过拟合
    • 过拟合解决方案: 剪枝(前剪枝和后剪枝), 或者多棵树的集成学习(随机森林), 在选择划分的特征属性的时候不进行全局最优选择, 而是进行局部最优选择
  • 常见的算法

    • ID3
    • C4.5
    • CART
  • 集成学习

    • 思路, 将多个模型进行融合, 使用融合后的结果作为真实的预测值
    • bagging, 对数据进行重采样, 然后使用重采样的数据进行模型训练, 然后将训练的多个模型预测结果进行融合; 如果是分类就多数投票或者加权的多数投票, 如果是回归就均值或者加权均值
      • 代表算法是随机森林
    • boosting, 对训练数据进行更改(样本权重的更改, 或者样本数据值的更改), 然后使用更改后的数据来训练模型, 训练之后对模型进行加权的操作

      • 代表算法有两种, adaboost基于样本的权重进行模型构建, 权重越高的样本在模型训练的时候起到的决策性作用越大; 样本的更新规则, 如果一个样本被前面的模型预测错误, 那么当前这个样本的权重就增大; 模型的权重给定规则, 如果一个模型的预测越准确, 模型的权重越高
      • adaboost本质是每次迭代构建模型的时候, 对于之前分类错误的样本着重考虑
      • GBDT, 梯度提升树, 在每次迭代的时候使用上一次的训练数据和上一次训练之后模型的预测值之间的残差作为当前模型的输入
      • GBDT本质, 每次迭代模型的时候, 都是在之前模型预测的结果的基础上进行预测, 每次产生的模型都让误差/偏度变得更小
      • GBDT中所有模型权重相同
      • 衰减因子, 每次考量模型的时候, 不是完全的相信模型效果, 所以可以对模型进行一个缩放操作; 每次更新的时候不是基于全部的预测值(y_true - y_predict), 而是采用变化一小点的策略(y_true - alpha * y_predict)
    • stacking

      • 使用原始数据和算法模型(不要求一样)训练多个模型
      • 使用第一步训练的多个模型在训练集上的预测值组成一个特征举证X, 使用原始数据中的目标属性作为Y, 然后再训练一个模型, 就相当于模型的算法集成, 而不是通过数据上的算法集成

聚类算法

课程内容

  • Jaccard相似度, Pearson相似度
  • K-means聚类
  • 聚类算法效果评估(准确率, 召回率等)
  • 层次聚类算法
  • 密度聚类算法
  • 谱聚类算法

什么是聚类

聚类就是对大量未知标注对数据集, 按照数据内部存在的数据特征将数据划分为多个不同的类别, 使类别内的数据比较相似, 类别之间的数据相似度比较小; 属于无监督学习

聚类算法的重点是计算样本项之间的相似度, 有时候也称为样本间的距离

和分类算法的区别

  • 分类算法属于有监督学习, 基于有标注的历史数据进行算法模型构建
  • 聚类算法属于无监督学习, 数据集中的数据是没有标注的

相似度/距离公式

闵可夫斯基距离(Minkovski)

  • 当p为1的时候就是曼哈顿距离(Manhattan)
  • 当p为2的时候就是欧式距离(Euclidean)
  • 当p为无穷大的时候就是切比雪夫距离(Chebyshev)

标准化欧式距离(Standardized Euclidean Distance)

夹角余弦相似度(Cosine)

KL距离(相对熵)

杰卡德相似系数(Jaccard)

Pearson相关系数

聚类的思想

给定一个有M个对象的数据集, 构建一个具有k个簇的模型, 其中$k \le M$, 满足以下条件:

  • 每个簇至少包含一个对象
  • 每个对象属于且仅属于一个簇
  • 将满足上述条件的k个簇称为一个合理的聚类划分

基本思想: 对于给定的类别数据k, 首先给定初始划分, 通过迭代改变样本和簇的隶属关系, 使得每次处理后的得到的划分比上一次的好(总的数据集之间的距离和变小了)

K-means算法

K-means算法, 也称为K平均或者K均值, 是使用广泛的最基础的聚类算法

假设输入样本为$T=X_1, X_2, \cdots, X_m$, 则算法步骤(使用欧几里得距离公式)为:

  • 选择初始化的k个类别中心$a_1, a_2, \cdots, a_k$
  • 对于每个样本$X_i$, 将其标记为距离类别中心$a_j$最近的类别j
  • 更新每个类别的中心点$a_j$为隶属于该类别的所有样本的均值
  • 重复上述两步操作, 直到达到某个终止条件

终止条件

  • 迭代次数, 最小平方误差MSE, 簇中心点变化率

K-means算法过程

记K个簇中心分别为$a_1, a_2, \cdots, a_K$, 每个簇的样本数量为$N_1, N_2, \cdots, N_K$
使用平方误差作为目标函数(使用欧几里得距离), 公式为:

要获取最优解, 即使得目标函数尽可能的小, 对函数J求偏导, 可以得到簇中心点a更新对公式:

K-means算法在迭代过程中使用所有点的均值作为新的质心(中心点), 如果簇中存在异常点, 将导致均值偏差比较严重
比如一个簇中有2, 4, 6, 8, 100五个数据, 那么新的质心为24, 显然这个质心离绝大多数点都比较远, 在当前情况下, 使用中位数6可能比使用均值的想法更好, 使用中位数的聚类方法叫做K-Mediods聚类(K中值聚类)

K-means算法初值敏感

K-means算法是初值敏感的, 选择不同的初始值可能导致不同的簇划分规则, 为了避免初值敏感最终导致的结果异常, 可以采用初始化多套初始节点构造不同的分类规则, 然后选择最优的构造规则

K-means算法初优缺点

缺点:

  • K值是用户给定的, 在进行数据处理前, K值是未知的, 不同的K值得到的结果也不一样
  • 对初始簇中心点是敏感的
  • 不适合发现非凸形状的簇或者大小差别较大的簇
  • 特殊值(离群值)对模型的影响比较大

优点:

  • 理解容易, 聚类效果不错
  • 处理大数据集的时候, 该算法可以保证较好的伸缩性和高效率
  • 当簇近似高斯分布的时候, 效果非常不错

K-means算法案例

二分K-means算法

解决K-means算法对初始簇中心比较敏感的问题, 二分K-means算法是一种弱化初始质心的一种算法, 具体思路步骤如下:

  • 将所有样本数据作为一个簇放到一个队列中
  • 从队列中选择一个簇进行K-means算法划分, 划分为两个簇, 并将子簇添加到队列中
  • 循环迭代第二步操作, 知道终止条件达到(聚簇数量, 最小平方误差, 迭代次数)
  • 队列中的簇就是最终的分类簇集合

从队列中选择划分聚簇的规则一般有两种方式:

  • 对所有簇计算误差和SSE(SSE也可以认为是距离函数的一种变种), 选择SSE最大的聚簇进行划分操作(优先这种策略)
  • 选择样本数据量最多的簇进行划分操作

K-means++算法

K-means$\Vert$算法

Canopy算法

Mini Batch K-means算法

K-means和Mini Batch K-means算法比较案例

聚类算法的衡量指标

  • 混淆矩阵
  • 均一性
  • 完整性
  • V-measure
  • 调整兰德系数(ARI)
  • 调整互信息(AMI)
  • 轮廓系数(Silhouette)

均一性

  • 均一性: 一个簇中只包含一个类别的样本, 则满足均一性; 其实也可以认为是正确率(每个聚簇中正确分类的样本数占该聚簇总样本书的比例和)N表示数量, $C_i$表示实际的类别, $K_i$表示在簇中间的类别, 总共k个簇

完整性

  • 完整性: 同类别样本被归类到相同簇中, 则满足完整性; 每个聚簇中正确分类的样本数占该类型的总样本比例的和, 和之前讲的”召回率”有点类似
    - V-measure: 均一性和完整性的加权平均

V-measure

轮廓系数

  • 簇内不相似度
  • 簇间不相似度
  • 轮廓系数

层次聚类方法

凝聚的层次聚类AGNES算法

分裂的层次聚类DIANA算法

AGNES和DIANA算法优缺点

AGNES算法中簇间距离

层次聚类优化算法

BIRCH算法

CURE算法

BRICH算法案例

密度聚类算法

密度聚类方法的指导思想是: 只要样本点的密度大于某个阈值, 则将样本添加到最近的簇中

这类算法可以客服基于距离的算法只能发现凸聚类的缺点, 可以发现任意形状的聚类, 而且对噪声数据不敏感

计算复杂度高, 计算量大
常用的算法有:

  • DBSCAN
  • 密度最大值算法

DBSCAN算法

密度最大值聚类算法(MDCA)

密度聚类算法案例

谱聚类

拉普拉斯矩阵变换

谱聚类应用场景及面临的问题

谱聚类应用案例

聚类综合案例

不同聚类算法在不同数据分布情况下的聚类效果

图片压缩

有约束的最优化问题

  • 最优化问题一般是指对于某一个函数而言, 求解在其指定作用域上的全局最小值问题, 一般分为三种情况, 这三种方法求出来的解都有可能有局部最小值, 只有当函数是凸函数的时候, 才可以得到全局最小值
    • 无约束问题, 一般求解方式为梯度下降法, 牛顿法, 坐标轴下降法, $ \displaystyle \min \limits_{x}f(x)$
    • 等式约束条件, 求解方式为拉格朗日乘子法, $\displaystyle \min \limits_{x}f(x); s.t: h_k(x)=0, k=1,2,\cdots, p$
    • 不等式约束条件, 求解方式为KKT条件

拉格朗日乘子法

对偶问题

在优化问题中, 目标函数f(x)存在多种形式, 如果目标函数和约束条件都为变量x的线性函数, 则称问题为线性规划; 如果目标函数为二次函数, 则称优化问题为二次规划; 如果目标函数或者约束条件为非线性函数, 则称最优化问题为非线性规划. 每个线性规划问题都有一个对偶问题

  • 对偶问题的对偶是愿问题
  • 无论原始问题是否是凸的, 对偶问题都是凸优化问题
  • 对偶问题可以给出原始问题的一个下界
  • 当满足一定条件的时候, 原始问题和对偶问题的解是完美等价的

KKT条件

KKT条件是泛拉格朗日乘子法的一种形式, 主要应用在当我们的优化函数存在不等值约束的情况下的一种最优化解决方式; KKT条件即满足不等值约束的条件

考虑简化的形式

从上式可以看到, $\beta_i g_i(x) \le 0$, 那么它的最大值顶多是0, 那么$f(x) = L(x, \beta) - \displaystyle \sum_{i=1}^q{\beta_ig_i(x)}$, 由此可以得到$L(x, \beta)$的最大值顶多就是$f(x)$, 所以最后如果要求解$f(x)$的最小值, 即可以求解$\displaystyle \max \limits_{\beta}L(x, \beta)$的最小值

KKT条件总结

  • 拉格朗日取得可行解的充要条件, $\nabla_xL(x, \alpha, \beta) = 0$
  • 将不等式约束转换后的一个约束, 称为松弛互补条件, $\beta_ig_i(x) = 0, \quad i=1,2,\cdots,q$
  • 初始约束条件, $h_i(x)=0, \quad i=1,2,\cdots,p$
  • 初始约束条件, $g_i(x)\le0,\quad i=1,2,\cdots,q$
  • 不等式约束需要满足的条件, $\beta_i\ge0,\quad i=1,2,\cdots,q$

参考拉格朗日乘子法和KKT条件




感知器模型

感知器模型的前提是数据线性可分

对于m个样本, 每个样本n维特征以及一个二元类别输出y, 如下:

目标是找到一个超平面, 即

让一个类别的数据满足$\theta x > 0$, 另外一个类别满足$\theta x < 0$
感知器模型, $y=sign(\theta x )\begin{cases}
+1, \theta x > 0\\
-1, \theta x < 0\\
\end{cases}$

定义正确分类为: $y\theta x>0$, 定义错误分类为: $y\theta x<0$, 所以定义的损失函数为: 期望使分类错误的所有样本(m条样本)到超平面的距离之和最小

分子分母简化后

直接使用梯度下降法对损失函数进行求解, 由于m是分类错误对样本集合, 不是固定的, 所以我们不能使用批量梯度下降法(BGD)求解, 只能使用随机梯度下降(SGD)和小批量梯度下降法(MBGD), 一般使用SGD求解

SVM

  • 梯度下降法, 拉格朗日乘子法, KKT条件回顾
  • 感知器模型
  • SVM线性可分
  • SVM线性不可分
  • 核函数
  • SMO

线性可分SVM

在感知器模型中, 是可以找到多个可以分类的超平面将数据分开. 并且希望所有的点都离超平面尽可能的远, 但是实际上离超平面足够远的点基本上都是被正确分类的, 所以这个是没有意义的. 反而是离超平面很近的点, 这些点比较容易分错. 所以只要让离超平面比较近的点尽可能的远离这个超平面, 这样模型分类效果就会不错, 此即为SVM的思想.

  • 支持向量到超平面的距离为:

在SVM中支持向量到超平面的函数距离一般设置为1

SVM模型是让所有的分类点在各自类别的支持向量的两边(见公式(2)), 同时要求支持向量尽可能的远离这个超平面(见公式(1)), 用数学公式表示如下:

优化问题等价于$ \min \limits_{w, b} \Vert w \Vert_2; \quad s.t: y^{(i)}(w^Tx^{(i)}+b) \ge 1, \quad i=1, 2, \cdots, m$
那么SVM的目标函数/损失函数为:

优化目标为$w^{\ast}, b^{\ast} = \min \limits_{w, b} J(w)$
这时可以将此此时的目标函数和约束条件使用KKT条件转换为拉格朗日函数, 从而转化为无约束优化函数:

引入拉格朗日乘子之后, 优化目标变成了:

根据拉格朗日对欧化特性, 将优化目标转换为等价的对偶问题

对于该优化函数, 要先求优化函数对于w和b的极小值, 然后再求解对于拉格朗日乘子$\beta$的极大值

优化函数L对于w和b的极小值, 可以通过对函数L分别对w和b求偏导数得到

将求解出的w和b带入优化函数L中, 那么优化后的函数如下:

此时得到的优化函数只和$\beta$有关, 这时直接最大化优化函数得到$\beta$值, 从而最终得到w和b的值

该优化问题等价于:

即:

$\beta$值的求解采用SMO算法

假设求解得到的$\beta$值为$\beta^{\ast}$, 则根据w, b, $\beta$的关系, 分别计算如下:

b的计算采用所有支持向量的计算均值

在这里$(x^s, y^s)$是支持向量, 根据KKT条件中的对欧互补条件(松弛约束条件), 支持向量必须满足以下公式:

线性可分SVM算法流程

输入线性可分的m个样本数据$\{ (x^1, y^1), (x^2, y^2), \cdots, (x^m, y^m)\}$, 其中x为n维的特征向量, y为二元输出, 取值为$+1$或者$-1$, SVM输出为参数$w$, $b$以及分类决策函数.

  • 构造约束优化维问题, $\displaystyle \min \limits_{\beta_i \ge 0} \frac{1}{2} ( \sum_{i=1, j=1}^{m} \beta_i \beta_j y^{(i)} y^{(j)} {x^{(i)}}^T x^{(j)} - \sum_{i=1}^{m} \beta_i); \quad s.t: \sum_{i=1}^{m} \beta_i y^{(i)} = 0 $
  • 使用SMO算法求出上述优化中对应的最优解$\beta^{\ast}$
  • 找出所有的支持向量集合$S = \{ (x^{(i)}, y^{(i)}) \quad | \quad \beta_i > 0, \quad i=1,2,\cdots,m \}$
  • 更新参数$w^{\ast}$和$b^{\ast}$的值, $w^{\ast} = \displaystyle \sum_{i=1}^{m} \beta_i^{\ast} y^{(i)} x^{(i)}, \quad b^{\ast} = \frac{1}{s} \sum_{s=1}^{S} ({y^s} - \sum_{i=1}^{m} \beta_i^{\ast} y^{(i)} {x^{(i)}}^T x^s) $
  • 构建最终的分类决策函数, $f(x)=sign(w^{\ast} \cdot x + b^{\ast})$

这里的例子没有理解

svm参考例子1

线性可分SVM总结

  • 要求数据必须是线性可分的
  • 纯线性可分的SVM模型对于异常数据的预测可能会不太准
  • 对于线性可分的数据, SVM分类器的效果非常不错

SVM的软间隔模型

线性可分SVM中要求数据必须是线性可分的, 才可以找到分类的超平面, 但是有的时候线性数据集中存在少量的异常点, 由于这些异常点导致了数据集不能够线性可分; 正常数据是线性可分的, 但是由于存在异常点数据, 导致数据集不能够线性可分

如果线性数据中存在异常点导致没法直接使用SVM线性分割模型的时候, 那我们可以通过引入软间隔的概念来解决这个问题

  • 硬间隔: 认为线性可分SVM中的距离度量就是硬间隔, 在线性划分SVM中, 要求函数距离一定是大于1的, 最大化硬间隔条件为:
  • 软间隔: SVM对于训练集中的每个样本都引入一个松弛因子($\xi$), 使得函数距离加上松弛因子后的值是大于或者等于1; 这表示相对于硬间隔, 对样本到超平面距离的要求放松了
  • 松弛因子($\xi$)越大, 表示样本点离超平面越近, 如果松弛因子大于1, 那么允许该样本点分错, 所以加入松弛因子是有成本的, 过大的松弛因子可能会导致模型分类错误, 所以最终的目标函数就转换成为:

    其中, 函数中的$C > 0$是惩罚系数, 是一个超参, 类似于L1/L2 norm中的参数; C越大表示对误分类的惩罚越大, C越小表示对误分类的惩罚越小; C值的给定需要调参

  • 同线性可分SVM, 构造软间隔最大化的约束问题对应的拉格朗日函数如下:

    从而可以将优化目标函数转换为:

  • 优化条件同样满足KTT条件, 所有使用拉格朗日对偶将优化问题转换为等价的对偶问题

先求优化函数对于$w,b,\xi$的极小值, 这个可以通过分别优化函数L求$w,b,\xi$的偏导数, 从而可以得到$w,b,\xi$关于$\beta$和$\mu$之间的关系

将$w,b,\xi$的值带入L函数中, 就可以消去优化函数中的$w,b,\xi$, 定义优化中后的函数如下:

最终优化后的目标函数/损失函数和线性可分SVM模型基本一样, 除了约束条件不同而已, 也就是说也可以使用SMO算法来求解

  • 在硬间隔最大化的时候, 支持向量比较简单, 就是离超平面的函数距离为1的样本点就是支持向量
  • 在软间隔中, 根据KKT条件中的对偶互补条件: $\beta(y(wx+b)-1+\xi)=0$, 从而有:
    • 当$0<\beta_i \le C$的时候, 并且$\xi_i=0$的样本点均是支持向量(即所有的$0<\beta_i < C$). 即满足$|wx+b|=1$的所有样本均是支持向量
    • 软间隔和硬间隔中的支持向量的规则是一样的

SVM软间隔模型算法流程

输入线性可分的m个样本数据${(x^1, y^1), (x^2, y^2), \cdots, (x^m, y^m)}$, 其中x为n维的特征向量, y为二元输出, 取值为+1或者-1; SVM模型输出为参数$w,b$以及分类决策函数

  • 选择一个惩罚系数C>0, 构造约束优化问题, $\displaystyle \min \limits_{\beta_i \ge 0} \frac{1}{2} ( \sum_{i=1, j=1}^{m} \beta_i \beta_j y^{(i)} y^{(j)} {x^{(i)}}^T x^{(j)} - \sum_{i=1}^{m} \beta_i); \quad s.t: \sum_{i=1}^{m} \beta_i y^{(i)} = 0, 0 \le \beta_i \le C, i=1,2,\cdots,m$
  • 使用SMO算法求出上述优化中对应的最优解$\beta^*$
  • 找出所有的支持向量集合$S = \{ (x^{(i)}, y^{(i)}) \quad | \quad 0 < \beta_i \le C, \xi_i = 0, i = 1, 2, \cdots, m $
  • 更新参数$w^{\ast}$和$b^{\ast}$的值, $w^{\ast} = \displaystyle \sum_{i=1}^{m} \beta_i^{\ast} y^{(i)} x^{(i)}, \quad b^{\ast} = \frac{1}{s} \sum_{s=1}^{S} ({y^s} - \sum_{i=1}^{m} \beta_i^{\ast} y^{(i)} {x^{(i)}}^T x^s) $
  • 构建最终的分类器$f(x)=sign(w^{\ast} x + b^{\ast})$

SVM软间隔模型总结

  • 可以解决线性数据中携带异常点的分类模型构建的问题
  • 通过引入惩罚系数(松弛因子), 可以增加模型的泛化能力, 即鲁棒性
  • 如果给定的惩罚系数越小, 表示在模型构建的时候, 就允许存在越多的分类错误的样本, 表示此时模型的准确率会比较低; 如果惩罚系数越大, 表示模型在构建的时候, 就越不允许存在分类错误的样本, 表示此时模型的准确率会比较高

信息熵和决策树

发表于 2018-12-31 | 分类于 ai

熵

信息熵

H(X)就叫做随机变量X的信息熵

  • 信息量: 指的是一个样本/事件所蕴含的信息, 如果一个事件的概率越大, 就认为该事件所蕴含的信息越少. 极端情况下, “太阳从东方升起”, 因为是确定事件, 所以不携带任何信息量
  • 信息熵, 一个系统越有序, 信息熵就越低, 一个系统越混乱, 信息熵就越高, 所以信息熵被认为是一个系统有序程度的度量
  • 信息熵就是用来描述系统信息量的不确定度
  • High Entropy(高信息熵): 表示随机变量X是均匀分布的, 各种去追情况是等概率出现
  • Low Entropy(低信息熵): 表示随机变量X各种取值不是等概率出现, 可能出现有的事件概率很大, 有的事件概率很小

信息熵

条件熵

  • 给定条件X的情况下, 随机变量Y的信息熵叫做条件熵
专业(X) 性别(Y)
数学 M
IT M
英语 F
数学 F
数学 M
IT M
英语 F
数学 F
  • 当专业(X)为数学的时候, Y的信息熵的值为H(Y|X=数学)
专业(X) 性别(Y)
数学 M
数学 F
数学 M
数学 F

同理

专业(X) 性别(Y)
IT M
IT M
专业(X) 性别(Y)
英语 F
英语 F
$v_j$ $P(X=v_j)$ $H(Y \mid X=v_j)$
数学 0.5 1
IT 0.25 0
英语 0.25 0
  • 事件(X, Y)发生所包含的熵, 减去事件X单独发生的熵, 即为在事件X发生的前提下, Y发生”新”带来的熵

决策树

  • 决策树(Decision Tree)是在已知各种情况发生概率的基础上, 通过构建决策树来进行分析的一种方式, 是一种直观应用概率分析的一种图解法; 决策树是一种预测模型, 代表的是对象属性与对象值之间的映射关系; 决策树是一种树形结构, 其中每个内部节点表示一个属性的测试, 每个分支表示一个测试输出, 每个叶节点代表一种类别; 决策树是一种非常常用的有监督的分类算法
  • 决策树的决策过程就是从根节点开始, 测试待分类项中对应的特征属性, 并按照其值选择输出分支, 直到叶子节点, 将叶子节点的存放类别作为决策结果
  • 决策树分为两大类: 分类树和回归树, 前者用于分类标签值, 后者用于预测连续值, 常用的算法有ID3, C4.5, CART等

决策树构建过程

  • 决策树算法的重点就是决策树的构造; 决策树的构造就是进行属性选择度量, 确定各个特征属性之间的拓扑结构(树结构); 构建决策树的关键步骤就是分裂属性, 分裂属性是指某个节点按照某一类特征属性的不同划分构建不同的分支, 其目标就是让各个分裂子集尽可能的纯(让一个分裂子类中待分类的项尽可能的属于同一个类别)
  • 构建步骤如下:
    • 将所有的特征看成一个一个的节点;
    • 遍历每个特征的每一种分割方式, 找到最好的分割点; 将数据划分为不同的子节点, $N_1, N_2, \cdots N_m$, 计算划分后所有子节点的”纯度”信息;
    • 对第二步产生的分割, 选择出最优的特征以及最优的划分方式; 得出最终的子节点$N_1, N_2, \cdots N_m$
    • 对子节点$N_1, N_2, \cdots N_m$分别继续执行2-3步, 直到每个最终的子节点都足够”纯”

决策树特征属性类型

根据特征属性的类型不同, 在构建决策树的时候, 采用不同的方式, 具体如下:

  • 属性是离散值, 而且不要求生成的是二叉决策树, 此时一个属性就是一个分支
  • 属性是离散值, 而且要求生成的是二叉决策树, 此时使用属性划分的子集进行测试, 按照”属于此子集”和”不属于此子集”分成两个分支
  • 属性是连续值, 可以确定一个值作为分裂点split_point, 按照> split_point和$\le$split_point生成两个分支

决策树分割属性选择

  • 决策树算法是一种”贪心”算法策略, 只考虑在当前数据特征下的最好分割方式, 不能进行回溯操作
  • 对于整体的数据集而言, 按照所有的特征属性进行划分操作, 对所有划分操作的结果集的”纯度”进行比较, 选择”纯度”越高的特征属性作为当前需要分割的数据集进行分割操作, 持续迭代, 直到得到最终结果. 决策树是通过”纯度”来进行分割特征属性点的

决策树量化纯度

  • 决策树的构建是通过样本概率和纯度进行构建操作的, 那么进行判断数据集是否”纯”可以通过三个公式进行判断, 分别是Gini系数, 熵(Entropy), 错误率, 这三个公式值越大, 表示数据越”不纯”; 越小表示越”纯”, 这三个公式效果差不多, 一般使用熵公式
  • 当计算出各个特征属性的量化纯度值后使用信息增益度来选择出当前数据集的分割特征属性; 如果信息增益度的值越大, 表示在该特征属性上会损失的纯度越大, 那么该属性就越应该在决策树的上层, 计算公式为:
    • Gain为特征A对训练集D的信息增益, 它为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差

决策树算法的停止条件

一般情况下有两个停止条件:

  • 当每个子节点只有一种类型的时候停止构建
  • 当前节点中记录数小于某个阈值, 同时迭代次数达到给定值时, 停止构建过程, 此时使用$max(p(i))$作为节点的对应类型
    方式一可能会使树的节点过多, 导致过拟合等问题; 比较常用的方式是使用方式二作为停止条件

决策树算法效果评估

  • 决策树的效果评估和一般的分类算法一样, 采用混淆举证来进行计算准确率, 召回率和精确率等指标
  • 也可以采用叶子节点的纯度值总和来评估算法的效果, 值越小, 效果越好

决策树生成算法

建立决策树主要有三种算法

  • ID3
  • C4.5
  • CART(Classification And Regression Tree)

ID3算法

ID3算法是决策树比较经典的一个构造算法, 内部使用信息熵以及信息增益来进行构造; 每次迭代选择信息增益最大的特征属性作为分割属性

优点: 决策树构建速度快, 实现简单
缺点:

  • 计算依赖于特征数目比较多的特征, 而属性值最多的属性不一定最优
  • ID3算法不是递增算法
  • ID3算法是单变量决策树, 对于特征属性之间的关系不会考虑
  • 抗噪性差
  • 只适合小规模数据集, 需要将数据放到内存中

C4.5算法

使用信息增益率来取代ID3算法中的信息增益, 在树的构造过程中会进行剪枝操作进行优化; 能够自动完成对连续属性的离散化处理; C4.5算法在选中分割属性的时候选择信息增益率最大的属性, 涉及到的公式为:

优点:

  • 产生的规则容易理解
  • 准确率较高
  • 实现简单

缺点:

  • 对数据集需要进行多次顺序扫描和排序, 效率较低
  • 只适合小规模数据集, 需要将数据放到内存中

CART算法

使用基尼系数作为数据纯度的量化指标来构建决策树, 使用GINI增益作为分割属性选择的标准, 选择GINI增益最大的作为当前数据集的分割属性; 可用于分类和回归两类问题. CART构建是二叉树

ID3, C4.5, CART分类算法总结

  • ID3和C4.5算法均只适合在小规模数据集上使用
  • ID3和C4.5算法都是单变量决策树
  • 当属性值取值比较多的时候,最好考虑C4.5算法,ID3得出的效果会比较差
  • 决策树分类一般情况只适合小数据量的情况(数据可以放内存)
  • CART算法是三种算法中最常用的一种决策树构建算法
  • 三种算法的区别仅仅只是对于当前树的评价标准不同而已,ID3使用信息增益, C4.5使用信息增益率、CART使用基尼系数
  • CART算法构建的一定是二叉树,ID3和C4.5构建的不一定是二叉树
算法 支持模型 树结构 特征选择 连续值处理 缺失值处理 剪枝 特征属性多次使用
ID3 分类 多叉树 信息增益 不支持 不支持 不支持 不支持
C4.5 分类 多叉树 信息增益率 支持 支持 支持 不支持
CART 分类, 回归 二叉树 基尼系数, 均方差 支持 支持 支持 支持

决策树优化策略

  • 剪枝优化, 决策树过拟合一般情况是由于节点太多导致的, 剪枝优化对决策树的正确率影响是比较大的, 也是最常用的一种优化方式
  • Random Forest, 利用训练数据随机产生多个决策树, 形成一个森林, 然后使用这个森林对数据进行预测, 选取最多结果作为预测结果

决策树剪枝

  • 前置剪枝: 在构建决策树过程中, 提前停止, 得到的决策树一般比较小, 实践证明这种策略无法得到比较好的结果
  • 后置剪枝: 在决策树构建好之后, 然后再开始裁剪, 一般使用两种方法, 后置剪枝的主要问题是计算效率问题, 存在一定的浪费情况
    • 用单一叶子节点代替整个子树, 叶子节点的分类采用子树中最主要的分类
    • 将一个子树完全代替另外一颗子树
  • 后剪枝总体思路(交叉验证):
    • 由完全树$T_0$开始, 剪枝部分节点得到$T_1$, 再次剪枝得到$T_2$……直到仅剩树根的树$T_k$
    • 在验证数据集上对这$k+1$个树进行评价, 选择最优树$T_a$(即损失函数最小的树)
  • 对于给定的决策树$T_0$
    • 计算所有内部非叶子节点的剪枝系数
    • 查找最小剪枝系数的节点, 将其子节点进行删除操作, 进行剪枝得到决策树$T_k$; 如果存在多个最小剪枝系数节点, 选择包含数据项最多的节点进行了剪枝操作
    • 重复上述操作, 直到产生的剪枝决策树$T_k$只有1个节点
    • 得到决策树$T_0T_1 \cdots T_k$
    • 使用验证样本集选择最优子树$T_a$
  • 使用验证集选择最优子树的标准, 可以使用原始损失函数来考虑:
  • 叶节点越多, 决策树越复杂, 损失越大; 修正添加剪枝系数, 修改后的损失函数为:
  • 考虑根节点为r的子树, 剪枝前后的损失函数分别为loss(R)和loss(r), 当这两者相等的时候, 可以求的剪枝系数

GridSearchCV: 网格交叉验证, 主要用于模型开发阶段找出模型的最优参数的一种方式, 内部会利用交叉验证

现在对于A和B的每个参数组合都进行一次k折交叉验证, 将k折交叉验证得到的k个模型的score(model.score(x,y))均值作为当前这组参数在训练集上的模型整体效果, GridSearchCV最终认为模型整体效果最优的对应参数是最优参数

分类树和回归树的区别

  • 分类树采用信息增益、信息增益率、基尼系数来评价树的效果,都是基于概率值进行判断的;而分类树的叶子节点的预测值一般为叶子节点中概率最大的类别作为当前叶子的预测值。
  • 在回归树种,叶子节点的预测值一般为叶子节点中所有值的均值来作为当前叶子 节点的预测值。所以在回归树中一般采用MSE作为树的评价指标,即均方差。
  • 一般情况下只使用CART算法构建回归树

使用特征树实现特征选择
因为决策树构建过程中, 每次选择的划分特征的目的/方向是让数据具有更加明显的区分能力; 也就是我们每次选择的特征其实是具有明显的区分能力的, 可以认为这些被选择的特征其实对于y的取值具有更大的影响, 所有我们可以使用决策树来实现特征选择的操作, 即选择clf.feature_importances_返回列表中, 权重比较大的特征

决策树

  • 区别

    • 分类树中使用信息熵, gini系数, 错误率作为”纯度”的度量指标, 回归树中使用MSE/MAE作为树的”纯度”的度量指标
    • 分类树使用叶子节点中包含最多的那个类别作为当前叶子的预测值, 回归树中使用叶子节点中包含的所有样本的目标属性的均值作为叶子的预测值
  • 决策树的构建

    • 让每次分裂数据集的时候, 让分裂之后的数据集更加的”纯”
  • 决策树分裂属性选择方式

    • 基于最优划分的规则进行选择, 迭代计算特征属性上所有划分方式的”纯度”, 选择划分后更加”纯”的一种方式(信息增益, 信息增益率), 该方法只能说明在当前数据集上是最优的, 可能会存在一定的过拟合情况
    • 基于随机的划分规则: 每次划分的时候, 都是先选择一定数目的特征, 然后在这部分特征中选择出一个最优的划分特征. 因为每次选择的划分特征都是局部最优的, 相对来讲可以增加模型的鲁棒性
  • 决策树的欠拟合和过拟合

    • 通过增加树的深度来缓解决策树的欠拟合问题
    • 通过限制树的复杂程度来缓解这个过拟合的问题
  • 网格交叉验证(GridSearchCV)

  • 决策树的效果评估

matplotlib

发表于 2018-10-04 | 分类于 ai

显示

1
2
%matplotlib tk  # 在GUI中显示
%matplotlib inline # 行内显示, 默认是行内显示

颜色,标记, 线形

  • LineStyle 线形
  • LineWidth 线宽
  • Color 颜色
  • Marker 标记点的形状
  • Label 图例的标签

刻度, 标题, 标签和图例

  • legend, 为了展示每个数据对应的图像名称和数据结构, 生成默认图例
  • xlabel/ylabel, 设置x/y轴标签
  • title, 设置标题
  • xlim/ylim, 控制图标的范围
  • xticks/yticks, 控制图标的刻度
  • gca, 获取当前坐标轴信息
  • spines, 设置边框
  • set_color, 设置边框颜色

中文显示问题

1
2
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

x1 = [1,2,3]
y1 = [5,7,4]
x2 = [1,2,3]
y2 = [10,14,12]

plt.plot(x1, y1, 'ro--', label="1st line")
plt.plot(x2, y2, 'b-', label="2nd line")
plt.xlabel('月份')
plt.ylabel('年份')
plt.xlim(1,3)
plt.ylim(0,15)
plt.xticks(np.linspace(0, 6, 5))
plt.yticks(np.arange(1, 15, 3), ['2011年', '2012年', '2013年', '2014年', '2015年'])
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.legend()
plt.show()

subplot子图

figure对象下边创建一个或多个subplot对象(即axes)用于绘制图像

subplot(numRows, numCols, plotNum)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

x1 = [1,2,3]
y1 = [5,7,4]
x2 = [1,2,3]
y2 = [10,14,12]

plt.subplot(221)
plt.plot(x1, y1, 'r-')
plt.subplot(224)
plt.plot(x2, y2, 'b--')
plt.show()

面向对象的形式

1
2
fig = plt.figure()  # figure实例, 可以添加axes实例
ax = fig.add_subplot(111) # 返回axes实例, 参数1是子图的总行数, 参数2是子图的总列数, 参数3是子图的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize=(8, 6))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)

ax1.plot(np.random.randn(50).cumsum(), 'g-')
ax2.plot(np.random.randn(50).cumsum(), 'b--')
ax3.plot(np.random.randn(50).cumsum(), 'k--')

plt.show()

subplots

返回一个图像和多个子图
参数: nrows=x, ncols=x, sharex=True, sharey=False, gridspec_kw={‘height_ratios’:[2, 2, 1, 1]}

fig, ax = plt.subplots(2, 2), 参数表示子图的行数和列数, 总共2 * 2个子图, 函数返回一个fig图像和一个子图ax的array列表.

e.g.1

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=4, ncols=1, sharex=True, sharey=False)

print(dir(fig))
fig.suptitle('test', fontsize=20)

axes[0].plot(range(10), 'ro-')
axes[1].plot(range(10), 'bo-')
axes[2].plot(range(10), 'go-')
axes[3].plot(range(10), 'mo-')

plt.show()

e.g.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

fig, axes = plt.subplots(2, 2)

for i in range(2):
for j in range(2):
axes[i, j].hist(np.random.randn(100), 10, color='g', alpha=0.75)
fig.subplots_adjust(wspace=0, hspace=0)
plt.show()

图像保存文件

plt.savefit(文件名称)

matplotlib柱状图

1
2
matplotlib.pyplot.bar(*args, **kwargs)
bar(x, height, width, bottom, *args, align='center', **kwargs)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt
import matplotlib as mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

plt.figure()
plt.bar([1,3,5,7,9,11], [5,2,7,8,2,6], label="xxoo", color='y')
plt.bar([2,4,6,8,10,12], [8,6,2,5,6,3], label="ooxx", color='g')

plt.legend()
plt.xlabel('bar number')
plt.ylabel('bar height')

plt.title('hello')
plt.show()

matplotlib直方图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
plt.hist(x, 100, normed=1, facecolor='g', alpha=0.75)
plt.title('直方图')
plt.text(60, 0.025, r'$\mu=100, \ \sigma=15$')
plt.axis([40, 160, 0, 0.03])
plt.grid(True)
plt.show()

matplotlib散点图

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import numpy as np

x = [1, 2, 3, 4, 5, 6, 7, 8]
y = [5, 2, 4, 2, 1, 4, 5, 2]
T = np.random.rand(8) * 125
plt.scatter(x, y, label='散点分布', c=T, s=25, marker='o', alpha=0.5)
plt.xlabel('x')
plt.ylabel('y')
plt.title('散点图')
plt.legend()
plt.show()

参考

pandas

发表于 2018-10-03 | 分类于 ai

概述

Pandas的数据结构: Pandas主要有Series(一维数组), DataFrame(二维数组), Panel(三维数组), Panel4D(四维数组), PanelND(更多维数组)等数据结构. 其中Series和DataFrame应用的最为广泛。

Series是一维带标签的数组, 它可以包含任何数据类型. 包括整数, 字符串, 浮点数, Python对象等. Series可以通过标签来定位.
DataFrame是二维的带标签的数据结构. 我们可以通过标签来定位数据. 这是NumPy所没有的.

查看pandas版本

1
2
3
>>> print(pd.__version__)
0.24.2
>>> pd.show_versions()

Series

创建Series

Series可以看做由一列数据组成的数据集
Series语法如下

1
s = pd.Series(data, index=index)

常用的创建Series的方法有如下三种:

从列表创建Series

1
2
3
4
5
6
7
8
>>> arr = ['a', 'b', 'c', 'd']
>>> s1 = pd.Series(arr) # 如果不指定index, 则默认从0开始
>>> s1
0 a
1 b
2 c
3 d
dtype: object

从Ndarray创建Series

1
2
3
4
5
6
7
8
9
10
>>> n = np.random.randn(5)  # 几行几列
>>> index = ["a", "b", "c", "d", "e"]
>>> s2 = pd.Series(n, index)
>>> s2
a 0.077125
b -0.554191
c 0.167562
d -1.214207
e -1.038312
dtype: float64

从字典创建Series

1
2
3
4
5
6
7
8
>>> dict = {'a':1, 'b':2, 'c':3, 'd':4}
>>> s3 = pd.Series(d)
>>> s3
a 1
b 2
c 3
d 4
dtype: int64

Seires基本操作

修改Series索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> s1
0 a
1 b
2 c
3 d
dtype: object
>>> s1.index = ['a1','a2','a3','a4']
>>> s1
a1 a
a2 b
a3 c
a4 d
dtype: object

>>> s1.index[0] = '01'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/base.py", line 3938, in __setitem__
raise TypeError("Index does not support mutable operations")
TypeError: Index does not support mutable operations
# index不支持可变操作

Series纵向拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>>> s1
a a
b b
c c
d d
dtype: object
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s4 = s3.append(s1)
>>> s4
a 1
b 2
c 3
d 4
a a
b b
c c
d d
dtype: object

Series按照指定索引删除元素

1
2
3
4
5
6
7
8
>>> s4.drop('a')
b 2
c 3
d 4
b b
c c
d d
dtype: object

Series修改指定索引的元素

1
2
3
4
5
6
7
8
9
10
11
>>> s4['a'] = [11, 'a1']
>>> s4
a 11
b 2
c 3
d 4
a a1
b b
c c
d d
dtype: object

Series按照指定索引查找元素

1
2
3
>>> s4['a']      
a 1
a a

Series切片

1
2
3
4
5
6
7
8
9
10
>>> s1
0 a
1 b
2 c
3 d
dtype: object
>>> s1[1:3]
1 b
2 c
dtype: object

Series运算

Series加法运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> s1
0 a
1 b
2 c
3 d
dtype: object
>>> s2
0 e
1 f
2 g
3 h
dtype: object
>>> s1.add(s2)
0 ae
1 bf
2 cg
3 dh
dtype: object
>>> s2.add(s1)
0 ea
1 fb
2 gc
3 hd
dtype: object

Series减法运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s4
a 4
bb 3
c 2
d 1
dtype: int64
>>> s3.sub(s4)
a -3.0
b NaN
bb NaN
c 1.0
d 3.0
dtype: float64

Series乘法运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s4
a 4
bb 3
c 2
d 1
dtype: int64
>>> s3.mul(s4)
a 4.0
b NaN
bb NaN
c 6.0
d 4.0
dtype: float64

Series除法运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s4
a 4
bb 3
c 2
d 1
dtype: int64
>>> s3.div(s4)
a 0.25
b NaN
bb NaN
c 1.50
d 4.00
dtype: float64

Series求中位数

1
2
3
4
5
6
7
8
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s3.median()
2.5

Series求和

1
2
3
4
5
6
7
8
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s3.sum()
10

Series最大值

1
2
3
4
5
6
7
8
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s3.max()
4

Series最小值

1
2
3
4
5
6
7
8
>>> s3
a 1
b 2
c 3
d 4
dtype: int64
>>> s3.min()
1

Series缺失值的检测

1
2
3
4
5
6
7
8
9
10
11
>>> series_10 = pd.Series({'a':10, 'b':20, 'c':30, 'd':40})
>>> series_10.index
Index(['a', 'b', 'c', 'd'], dtype='object')
>>> series_20 = pd.Series(series_10,index=new_index)
>>> series_20
a 10.0
b 20.0
c 30.0
d 40.0
e NaN
dtype: float64

isnull和notnull检测Series中的缺失值, 返回bool类型的Series值

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
>>> pd.isnull(ser_10) 
a False
b False
c False
dtype: bool
>>> pd.isnull(ser_20)
a False
b False
c False
d True
dtype: bool

>>> pd.notnull(ser_10)
a True
b True
c True
dtype: bool
>>> pd.notnull(ser_20)
a True
b True
c True
d False
dtype: bool

>>> ser_20
a 10.0
b 20.0
c 30.0
d NaN
dtype: float64
>>> ser_20[pd.isnull(ser_20)] # 相当于过滤掉缺失值
d NaN
dtype: float64
>>> ser_20[pd.notnull(ser_20)]
a 10.0
b 20.0
c 30.0
dtype: float64

Series自动对齐

1
2
3
4
5
6
7
8
9
>>> series_1 = pd.Series([1,2,3,4], index=['a','b','c','d'])
>>> series_2 = pd.Series([4,3,2,1,5], index=['a','b','c','d','e'])
>>> series_1 + series_2
a 5.0
b 5.0
c 5.0
d 5.0
e NaN
dtype: float64

Series及其name属性

1
2
3
4
5
6
7
8
9
>>> series_1.name = "hello world"
>>> series_1.index.name = 'xxoo'
>>> series_1
xxoo
a 1
b 2
c 3
d 4
Name: hello world, dtype: int64

DataFrame

创建DataFrame

通过NumPy数组创建DataFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> dates = pd.date_range('today', periods=6)
>>> dates
DatetimeIndex(['2019-05-07 11:19:46.800556', '2019-05-08 11:19:46.800556',
'2019-05-09 11:19:46.800556', '2019-05-10 11:19:46.800556',
'2019-05-11 11:19:46.800556', '2019-05-12 11:19:46.800556'],
dtype='datetime64[ns]', freq='D')
>>> num_arr = np.random.randn(6,4)
>>> num_arr
array([[ 0.73018504, -0.92169922, -1.37867963, -1.40692501],
[ 1.61475442, 0.07078674, 0.59075899, -1.994313 ],
[ 0.00830036, 0.20939717, 0.50323969, 0.43514028],
[ 0.23984788, 0.15418066, -1.06420981, 0.58894686],
[ 1.30096803, 0.87426295, -0.56629328, -0.14877761],
[ 0.94481793, -1.04911144, -1.39403504, 0.77847438]])
>>> columns=['A','B','C','D']
>>> df1 = pd.DataFrame(num_arr, dates, columns)
>>> df1
A B C D
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474

通过dict创建DataFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
... 'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
... 'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
... 'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
>>>
>>> labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
>>> df2 = pd.DataFrame(data, index=labels)
>>> df2
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
c snake 0.5 2 no
d dog NaN 3 yes
e dog 5.0 2 no
f cat 2.0 3 no
g snake 4.5 1 no
h cat NaN 1 yes
i dog 7.0 2 no
j dog 3.0 1 no
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> data = {'成绩':[90, 90, 99], '姓名': ['Tony','Wayne','Moon'], '爱好':['篮球','排球','乒乓球']}  
>>> df_1 = pd.DataFrame(data)
>>> df_1
成绩 姓名 爱好
0 90 Tony 篮球
1 90 Wayne 排球
2 99 Moon 乒乓球

>>> df_1.index
RangeIndex(start=0, stop=3, step=1)
>>> df_1.index = ['xx','oo','xxoo']
>>> df_1
成绩 姓名 爱好
xx 90 Tony 篮球
oo 90 Wayne 排球
xxoo 99 Moon 乒乓球

DataFrame通过二维数组创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> df_1 = pd.DataFrame([['Wayne', 'Tony', 'Moon'],[90, 80, 70]])
>>> df_1
0 1 2
0 Wayne Tony Moon
1 90 80 70
>>> df_1 = pd.DataFrame([['Wayne', 'Tony', 'Moon'],[90, 80, 70]], index=['hello', 'world'])
>>> df_1
0 1 2
hello Wayne Tony Moon
world 90 80 70
>>> df_1 = pd.DataFrame([['Wayne', 'Tony', 'Moon'],[90, 80, 70]], index=['hello', 'world'], columns=['a','b','c'])
>>> df_1
a b c
hello Wayne Tony Moon
world 90 80 70

DataFrame获取数据

查看index, columns和values

1
2
3
4
5
6
7
>>> df_1.index
Index(['hello', 'world'], dtype='object')
>>> df_1.columns
Index(['a', 'b', 'c'], dtype='object')
>>> df_1.values
array([['Wayne', 'Tony', 'Moon'],
[90, 80, 70]], dtype=object)

查看前几行和后几行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> df2.head()
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
c snake 0.5 2 no
d dog NaN 3 yes
e dog 5.0 2 no
>>> df2.tail()
animal age visits priority
f cat 2.0 3 no
g snake 4.5 1 no
h cat NaN 1 yes
i dog 7.0 2 no
j dog 3.0 1 no

通过标签查询单列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> df1
A B C D
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474
>>> df1['A']
2019-05-07 11:19:46.800556 0.730185
2019-05-08 11:19:46.800556 1.614754
2019-05-09 11:19:46.800556 0.008300
2019-05-10 11:19:46.800556 0.239848
2019-05-11 11:19:46.800556 1.300968
2019-05-12 11:19:46.800556 0.944818
Freq: D, Name: A, dtype: float64

通过标签查询多列

1
2
3
4
5
6
7
8
>>> df1[['A','B']]
A B
2019-05-07 11:19:46.800556 0.730185 -0.921699
2019-05-08 11:19:46.800556 1.614754 0.070787
2019-05-09 11:19:46.800556 0.008300 0.209397
2019-05-10 11:19:46.800556 0.239848 0.154181
2019-05-11 11:19:46.800556 1.300968 0.874263
2019-05-12 11:19:46.800556 0.944818 -1.049111

通过位置查询

1
2
3
4
>>> df1.iloc[1:3]
A B C D
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140

查看DataFrame的统计数据

1
2
3
4
5
6
7
8
9
10
>>> df1.describe()
A B C D
count 6.000000 6.000000 6.000000 6.000000
mean 0.806479 -0.110364 -0.551537 -0.291242
std 0.613343 0.736756 0.902708 1.149970
min 0.008300 -1.049111 -1.394035 -1.994313
25% 0.362432 -0.673578 -1.300062 -1.092388
50% 0.837501 0.112484 -0.815252 0.143181
75% 1.211931 0.195593 0.235856 0.550495
max 1.614754 0.874263 0.590759 0.778474

DataFrame基本操作

DataFrame转置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> df1
A B C D
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474
>>> df1.T
2019-05-07 11:19:46.800556 2019-05-08 11:19:46.800556 ... 2019-05-11 11:19:46.800556 2019-05-12 11:19:46.800556
A 0.730185 1.614754 ... 1.300968 0.944818
B -0.921699 0.070787 ... 0.874263 -1.049111
C -1.378680 0.590759 ... -0.566293 -1.394035
D -1.406925 -1.994313 ... -0.148778 0.778474

[4 rows x 6 columns]

DataFrame按列排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> df1
A B C D
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474
>>> df1.sort_values(by='A')
A B C D
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313

DataFrame切片

1
2
3
4
5
6
7
8
9
10
11
12
>>> df1
A B C D
2019-05-07 11:19:46.800556 0.730185 -0.921699 -1.378680 -1.406925
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140
2019-05-10 11:19:46.800556 0.239848 0.154181 -1.064210 0.588947
2019-05-11 11:19:46.800556 1.300968 0.874263 -0.566293 -0.148778
2019-05-12 11:19:46.800556 0.944818 -1.049111 -1.394035 0.778474
>>> df1[1:3]
A B C D
2019-05-08 11:19:46.800556 1.614754 0.070787 0.590759 -1.994313
2019-05-09 11:19:46.800556 0.008300 0.209397 0.503240 0.435140

Dataframe副本copy

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> df3 = df2.copy()
>>> df3
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
c snake 0.5 2 no
d dog NaN 3 yes
e dog 5.0 2 no
f cat 2.0 3 no
g snake 4.5 1 no
h cat NaN 1 yes
i dog 7.0 2 no
j dog 3.0 1 no

列添加

1
2
3
4
5
6
>>> df_1['location'] = ['SH', 'BJ', 'GZ']
>>> df_1
成绩 姓名 爱好 location
xx 90 Tony 篮球 SH
oo 90 Wayne 排球 BJ
xxoo 99 Moon 乒乓球 GZ

列删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> df_1
成绩 姓名 爱好 location
xx 90 Tony 篮球 SH
oo 90 Wayne 排球 BJ
xxoo 99 Moon 乒乓球 GZ
>>> df_1.pop('爱好')
xx 篮球
oo 排球
xxoo 乒乓球
Name: 爱好, dtype: object
>>> df_1
成绩 姓名 location
xx 90 Tony SH
oo 90 Wayne BJ
xxoo 99 Moon GZ

列修改

1
2
3
4
5
6
>>> df_1['location'] = ['SJZ','TY','ZZ']
>>> df_1
成绩 姓名 location
xx 90 Tony SJZ
oo 90 Wayne TY
xxoo 99 Moon ZZ

行的获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> df_1
成绩 姓名 location
xx 90 Tony SJZ
oo 90 Wayne TY
xxoo 99 Moon ZZ
>>> df_1.ix['xx']
成绩 90
姓名 Tony
location SJZ
Name: xx, dtype: object
>>> df_1.loc['xx']
成绩 90
姓名 Tony
location SJZ
Name: xx, dtype: object

行增加

1
2
3
4
5
6
7
>>> df_1.ix['ooxx'] = [88, 'Bessie', 'QHD']
>>> df_1
成绩 姓名 location
xx 90 Tony SJZ
oo 90 Wayne TY
xxoo 99 Moon ZZ
ooxx 88 Bessie QHD

行修改

1
2
3
4
5
6
7
>>> df_1.ix['ooxx'] = [88, 'Bessie', 'SH'] 
>>> df_1
成绩 姓名 location
xx 90 Tony SJZ
oo 90 Wayne TY
xxoo 99 Moon ZZ
ooxx 88 Bessie SH

行删除

1
2
3
4
5
>>> df_1.drop('xxoo')  
成绩 姓名 location
xx 90 Tony SJZ
oo 90 Wayne TY
ooxx 88 Bessie SH

索引对象

pandas基本功能

数据文件读取和文本数据读取

通过pandas.read_xx相关函数可以读取文件中的数据, 并形成DataFrame, 常用的方法为read_csv, 主要读取文本类型的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cat data.csv
wayne,tony,bessie
19,20,21
1,1,0

>>> pd.read_csv('data.txt', sep=';', header=None)
0 1 2
0 wayne tony bessie
1 19 20 21
2 1 1 0

cat data.csv
name,age,sex
wayne,19,1
tony,20,1
bessie,21,0

>>> pd.read_csv('data.csv')
name age sex
0 wayne 19 1
1 tony 20 1
2 bessie 21 0

索引, 选取和数据过滤

1
2
3
4
5
6
7
>>> df01 = pd.read_csv('data.csv')
>>> df01[df01.columns[1:]]
age source
0 18 98.5
1 21 78.2
2 24 98.5
3 20 89.2

缺省值NaN的处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat data1.txt
name,age,salary,gender
Tom,NaN,456.7,M
Merry,34,345.6,NaN
Gerry,NaN,NaN,NaN
John,23,NaN,M
Joe ,18,385.6,F

>>> df2 = pd.read_csv('data1.csv', sep=',')

>>> df2.isnull()
name age salary gender
0 False True False False
1 False False False True
2 False True True True
3 False False True False
4 False False False False
>>> df2.notnull()
name age salary gender
0 True False True True
1 True True True False
2 True False False False
3 True True False True
4 True True True True
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
>>> df01 = pd.DataFrame(np.random.randint(1,9,size=(4,4)))
>>> df01
0 1 2 3
0 1 5 8 4
1 3 3 6 8
2 5 7 2 4
3 5 5 6 4


# >>> df01 = pd.DataFrame(np.random.randint(1,9,size=(4,4)), index=['a','b','c','d'])
# >>> df01
# 0 1 2 3
# a 4 2 6 7
# b 3 7 5 6
# c 8 5 3 2
# d 6 7 4 4

>>> df01.ix[1:3,1] = np.NaN # 将第一行到第三行的第一列修改为NaN
>>> df01
0 1 2 3
0 3 7.0 6 3
1 2 NaN 1 5
2 3 NaN 1 4
3 8 NaN 8 2

>>> df01.dropna() # 将NaN都删除掉, 默认只要包含NaN就删除掉
0 1 2 3
0 3 7.0 6 3

>>> df01.dropna(how='all')
0 1 2 3
0 3 7.0 6 3
1 2 NaN 1 5
2 3 NaN 1 4
3 8 NaN 8 2

>>> df01
0 1 2 3
0 3 7.0 6 3
1 2 NaN 1 5
2 3 NaN 1 4
3 8 NaN 8 2
>>> df01.dropna(axis=1)
0 2 3
0 3 6 3
1 2 1 5
2 3 1 4
3 8 8 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
>>> from pandas import DataFrame
>>> df = DataFrame(np.random.randn(7,3))
>>> df.ix[:4,1] = np.nan # 第0行到第4行的第1列全都置为NaN
>>> df.ix[:2,2] = np.nan # 第0行到第2行的第2列全都置为NaN
>>> df
0 1 2
0 -0.041760 NaN NaN
1 -0.005338 NaN NaN
2 -0.728414 NaN NaN
3 -1.836972 NaN 1.114158
4 1.737801 NaN -0.103160
5 -0.968829 -0.573951 0.503281
6 -0.565628 -0.889926 -1.307314
>>> df.fillna(0) # 将所有的NaN填充为0
0 1 2
0 -0.041760 0.000000 0.000000
1 -0.005338 0.000000 0.000000
2 -0.728414 0.000000 0.000000
3 -1.836972 0.000000 1.114158
4 1.737801 0.000000 -0.103160
5 -0.968829 -0.573951 0.503281
6 -0.565628 -0.889926 -1.307314
>>> df.fillna({1:0.5, 2:-1, 3:1}) # 将第1列的NaN填充为0.5, 将第2列的NaN填充为-1, 将第3列的NaN填充为1
0 1 2
0 -0.041760 0.500000 -1.000000
1 -0.005338 0.500000 -1.000000
2 -0.728414 0.500000 -1.000000
3 -1.836972 0.500000 1.114158
4 1.737801 0.500000 -0.103160
5 -0.968829 -0.573951 0.503281
6 -0.565628 -0.889926 -1.307314

常用的数学统计方法

方法 说明
count 计算非NA值的数量
describe 针对Series或各个DataFrame列计算总的统计值
min/max
argmin/argmax 计算能够获取到最小值和最大值的索引位置(整数)
idxmin/idxmax 算能够获取到最小值和最大值的索引值
quantile 计算样本的分位数(0或1)
sum 值的总和
mean 值的平均数
median 值的中位数
mad 根据平均值计算平均绝对距离差
var 样本值的方差
std 样本值的标准差
cumsum 样本值的累计和
cummin/cummax 样本的累计最小值和最大值
cumprod 样本值的累计积
pct_change 百分数的变化

相关系数与协方差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> df = DataFrame({'GDP':[12, 23, 34, 45, 56], 'air_temperature': [23, 25, 26, 27, 30], 'year':['2001','2002','2003','2004','2005']})
>>> df
GDP air_temperature year
0 12 23 2001
1 23 25 2002
2 34 26 2003
3 45 27 2004
4 56 30 2005
>>> df.corr()
GDP air_temperature
GDP 1.000000 0.977356
air_temperature 0.977356 1.000000
>>> df.cov()
GDP air_temperature
GDP 302.5 44.0
air_temperature 44.0 6.7

唯一值, 值计数以及成员资格

  • unique用于获取Series中的唯一值数组(去重后的数组)
  • value_counts用于计算一个Series中各值的出现的频率
  • isin用于判断矢量化集合中的成员资格, 可用于选取Series中或者DataFrame中列数据的子集
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
>>> from pandas import Series
>>> ser = Series(['a','b','c','b','c','a','d','e','b'])
>>> ser.unique()
array(['a', 'b', 'c', 'd', 'e'], dtype=object)
>>> ser.value_counts()
b 3
a 2
c 2
d 1
e 1
dtype: int64
>>> ser.value_counts(ascending=False) # 降序排列
b 3
a 2
c 2
d 1
e 1
dtype: int64
>>> ser.value_counts(ascending=True) # 升序排列
e 1
d 1
c 2
a 2
b 3
dtype: int64

# DataFrame去重
>>> df = DataFrame({'order_id':['1001','1002','1003','1004','1005'], 'member_id':['m01','m01','m02','m01','m02'], 'order_amt':[345, 312.2, 123, 250.2, 235]})
>>> df
order_id member_id order_amt
0 1001 m01 345.0
1 1002 m01 312.2
2 1003 m02 123.0
3 1004 m01 250.2
4 1005 m02 235.0
>>> df['member_id'].unique()
array(['m01', 'm02'], dtype=object)

# 成员资格判断
>>> ser
0 a
1 b
2 c
3 b
4 c
5 a
6 d
7 e
8 b
dtype: object
>>> mask = ser.isin(['b','c'])
>>> mask
0 False
1 True
2 True
3 True
4 True
5 False
6 False
7 False
8 True
dtype: bool
>>> ser[mask]
1 b
2 c
3 b
4 c
8 b
dtype: object

算法运算和数据对齐

函数的应用和映射

层次索引

  • 在某一个方向上拥有多个(两个或两个以上)索引级别
  • 通过层次化索引, pandas能够以较低维度的形式处理高维度的数据
  • 通过层次化索引, 可以按照层次统计数据
  • 层次所以包括Series层次索引和DataFrame层次索引
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
>>> data = Series([988.44, 95895, 3959, 32554, 1235], index=[['2001','2001','2001','2002','2002'],['苹果','香蕉','西瓜','苹果','西瓜']])
>>> data
2001 苹果 988.44
香蕉 95895.00
西瓜 3959.00
2002 苹果 32554.00
西瓜 1235.00
dtype: float64
>>> data01 = data.swaplevel().sort_index() # 交换分层索引
>>> data01
苹果 2001 988.44
2002 32554.00
西瓜 2001 3959.00
2002 1235.00
香蕉 2001 95895.00
dtype: float64

>>> df = DataFrame({'year':[2001, 2001, 2002, 2002, 2003], 'fruit':['apple','banana','apple','banana','apple'], 'production':[2345, 3124, 5668, 2532, 2135], 'profits':[233.44, 4452.2, 1225.2, 7845.2, 2352.2]})
>>> df
year fruit production profits
0 2001 apple 2345 233.44
1 2001 banana 3124 4452.20
2 2002 apple 5668 1225.20
3 2002 banana 2532 7845.20
4 2003 apple 2135 2352.20
>>> df = df.set_index(['year','fruit']) # 设置层次化索引
production profits
year fruit
2001 apple 2345 233.44
banana 3124 4452.20
2002 apple 5668 1225.20
banana 2532 7845.20
2003 apple 2135 2352.20

>>> df.ix[2002,'apple'] # 根据层次化索引进行取值
production 5668.0
profits 1225.2
Name: (2002, apple), dtype: float64

>>> df.sum(level='year') # 按照层次索引统计数据
production profits
year
2001 5469 4685.64
2002 8200 9070.40
2003 2135 2352.20
>>> df.min(level="fruit")
production profits
fruit
apple 2135 233.44
banana 2532 4452.20
>>> df.min(level=['year','fruit'])
production profits
year fruit
2001 apple 2345 233.44
banana 3124 4452.20
2002 apple 5668 1225.20
banana 2532 7845.20
2003 apple 2135 2352.20

参考文档

12

John Doe

18 日志
2 分类
64 标签
© 2020 John Doe
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4