机器学习笔记
一些基础内容参见 人工智能导论 。
绪论
一些机器学习的框架:
可以在 github 上搜索它们。
框架 | 机构 | 支持语言 | Stars | Forks | Contributors |
---|---|---|---|---|---|
TensorFlow | Python/C++/Go/… | 41628 | 19339 | 568 | |
Caffe | BVLC | C++/Python | 14956 | 9282 | 221 |
Keras | fchollet | Python | 10727 | 3575 | 322 |
CNTK | Microsoft | C++ | 9063 | 2144 | 100 |
MXNet | DMLC | Python/C++/R/… | 7393 | 2745 | 241 |
Torch7 | Lua | 6111 | 1784 | 113 | |
Theano | U. Montreal | Python | 5352 | 1868 | 271 |
Deeplearning4J | DeepLearning4J | Java/Scala | 5053 | 1927 | 101 |
Leaf | AutumnAI | Rust | 4562 | 216 | 14 |
Lasagne | Lasagne | Python | 2749 | 761 | 55 |
Neon | NervanaSystems | Python | 2633 | 573 | 52 |
上面表格内容可能有些过时。
常见的流程:
- 预处理
- 特征工程
- 机器学习(选择合适的算法、调参)
- 评估
- 若评估通过,则上线
数据来源:
- 企业日益积累的大量数据(互联网公司更为显著)
- 政府掌握的各种数据
- 科研机构的实验数据
- …
数据类型:
- 离散型数据
- 连续型数据
可用数据集:
- https://www.kaggle.com/datasets
- https://archive.ics.uci.edu/datasets/
- https://scikit-learn.org/stable/datasets
预测问题分为两大类:
- 分类:顾名思义。例如人脸识别就是分类,每个人都是其中的一类。
- 回归:预测结果是一个值。
机器学习的算法分类:
- 监督学习:
- 分类
- k-近邻算法、贝叶斯分类、决策树与随机森林、逻辑回归、神经网络
- 回归
- 线性回归、岭回归
- 标注
- 隐马尔可夫模型
- 分类
- 无监督学习:
- 聚类, k-means
监督学习: 特征值 + 目标值
非监督学习: 特征值 1000 个样本(例子)
特征工程
常用数据集的数据可能有这样的结构:特征值+目标值 。
比如说要预测房价,可能 (房子面积, 房子位置, 房子楼层, 房子朝向)
是影响目标值的因素,那么这个“房子面积”等就是特征。
特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,从而提高了模型对未知数据预测的准确性。
一个形象的理解:
在新的虚拟环境中:
1 | pip install scikit-learn |
scikit-learn 官网的介绍:
下面的 ipynb 文件包含以下内容:
- 字典特征抽取
- 文本特征抽取
- 特征处理(归一化、标准化)
- 缺失值处理(删除、插补)
- 特征选择(Filter 例如 VarianceThreshold, Embedded, Wrapper)
- 降维(PCA 主成分分析)
本小节的剩余部分是 PCA 主成分分析的数学推导。
截图来自视频 BV1E5411E71z 。
拓展资料:
- https://gitee.com/ni1o1/pygeo-tutorial/blob/master/12-.ipynb (github 备份)
- https://www.cnblogs.com/pinard/p/6239403.html(archive 备份)
- https://zhuanlan.zhihu.com/p/55297233 (github 备份)
数据集举例、分类估计器、knn、网格搜索、ROC AUC、朴素贝叶斯
sklearn.datasets
加载获取流行数据集。
datasets.load_*()
- 获取小规模数据集,数据包含在 datasets 里,直接加载到内存中。
datasets.fetch_*(data_home=None)
- 获取大规模数据集,需要从网络上下载,函数的第一个参数是 data_home,表示数据集下载的目录。
下面的 ipynb 文件包含以下内容:
- 鸢尾花数据集
- 20 类新闻数据集
- boston 房价数据集
- 分类估计器
- knn
- 网格搜索
- 分类模型的评估
- 基础知识
- ROC 曲线与 AUC 值概述
- ROC 的动机
- ROC 的定义
- ROC 的图形化表示
- AUC 值
- 朴素贝叶斯进行文本分类
决策树、随机森林
下面的 ipynb 文件包含以下内容:
- 原理部分
- sklearn 决策树 API
- 决策树实例
- 剪枝
- 集成学习方法-随机森林
模型选择、线性回归、加载保存的模型、梯度下降、过拟合欠拟合、岭回归、逻辑回归
下面的 ipynb 文件包含以下内容:
- 模型选择
- 线性回归
- 加载保存的模型
- 梯度下降
- 过拟合欠拟合
- 岭回归
- 逻辑回归
kmeans、异常值
下面的 ipynb 文件包含以下内容:
- k-means
- 找异常值的方法
偏差与方差
在有监督学习中,模型的泛化误差来源于两个方面,偏差和方差。
偏差指的是由所有采样得到的大小为 m 的训练数据集训练出的所有模型的输出的平均值和真实模型输出之间的差距。偏差通常是由于我们对学习算法做了错误的假设所导致的,比如真实模型是某个二次函数,但我们假设模型是一次函数。由偏差带来的误差通常在训练误差上就能体现出来。
方差指的是由所有采样得到的大小为 m 的训练数据集训练出的所有模型的输出的方差。方差通常是由于模型的复杂度相对于训练样本数 m 过高导致的,比如一共有 100 个训练样本,而我们假设模型是阶数不大于 200 的多项式函数。由方差带来的误差通常体现在测试误差相对于训练误差的增量上。
集成学习
面对一个机器学习问题,通常有两种策略:
- 尝试各种模型,选择其中表现最好的模型做重点调参优化
- 将多个分类器的结果统一成一个最终的决策
- 使用这类策略的机器学习方法统称为集成学习,其中的每个单独的分类器称为基分类器。
集成学习不仅在学界的研究热度不减,在业界和众多机器学习竞赛中也有非常成功的应用。例如在 Kaggle 竞赛中所向披靡的 XGBoost,就是成功应用集成学习思想的一个例子。
Boosting(串行):
Boosting 方法训练基分类器时采用串行的方式,各个基分类器之间有依赖。它的基本思路是将基分类器层层叠加,每一层在训练的时候,对前一层基分类器分错的样本,给予更高的权重。测试时,根据各层分类器的结果的加权得到最终结果。
Bagging(并行):
Bagging 与 Boosting 的串行训练方式不同,Bagging 方法在训练过程中,各基分类器之间无强依赖,可以进行并行训练。其中很著名的算法之一是基于决策树基分类器的随机森林(Random Forest)。为了让基分类器之间互相独立,将训练集分为若干子集(当训练样本数量较少时,子集之间可能有交叠)。Bagging 方法更像是一个集体决策的过程,每个个体都进行单独学习,学习的内容可以相同,也可以不同,也可以部分重叠。但由于个体之间存在差异性,最终做出的判断不会完全一致。在最终做决策时,每个个体单独作出判断,再通过投票的方式做出最后的集体决策。
从消除基分类器的偏差和方差的角度来理解 Boosting 和 Bagging 方法的差异。基分类器,有时又被称为弱分类器,因为基分类器的错误率要大于集成分类器。基分类器的错误,是偏差和方差两种错误之和。偏差主要是由于分类器的表达能力有限导致的系统性错误,表现在训练误差不收敛。方差是由于分类器对于样本分布过于敏感,导致在训练样本数较少时,产生过拟合。
Boosting 方法是通过逐步聚焦于基分类器分错的样本,减小集成分类器的偏差。Bagging 方法则是采取分而治之的策略,通过对训练样本多次采样,并分别训练出多个不同模型,然后做综合,来减小集成分类器的方差。假设所有基分类器出错的概率是独立的,在某个测试样本上,用简单多数投票方法来集成结果,超过半数基分类器出错的概率会随着基分类器的数量增加而下降。
集成学习一般可分为以下 3 个步骤:
- 找到误差互相独立的基分类器
- 训练基分类器
- 合并基分类器的结果
合并基分类器的方法有 voting 和 stacking 两种。前者是用投票的方式,将获得最多选票的结果作为最终的结果。后者是用串行的方式,把前一个基分类器的结果输出到下一个分类器,将所有基分类器的输出结果相加(或者用更复杂的算法融合,比如把各基分类器的输出作为特征,使用逻辑回归作为融合模型进行最后的结果预测)作为最终的输出。
基分类器
常用的基分类器是决策树,主要有以下 3 个方面的原因:
- 决策树可以较为方便地将样本的权重整合到训练过程中,而不需要使用过采样的方法来调整样本权重。
- 决策树的表达能力和泛化能力,可以通过调节树的层数来做折中。
- 数据样本的扰动对于决策树的影响较大,因此不同子样本集合生成的决策树基分类器随机性较大,这样的“不稳定学习器”更适合作为基分类器。此外,在决策树节点分裂的时候,随机地选择一个特征子集,从中找出最优分裂属性,很好地引入了随机性。
除决策树外,神经网络模型也适合作为基分类器,主要由于神经网络模型也比较“不稳定”,而且还可以通过调整神经元数量、连接方式、网络层数、初始权值等方式引入随机性。
可否将随机森林中的基分类器,由决策树替换为线性分类器或 K-近邻?
随机森林属于 Bagging 类的集成学习。Bagging 的主要好处是集成后的分类器的方差,比基分类器的方差小。Bagging 所采用的基分类器,最好是本身对样本分布较为敏感的(即所谓不稳定的分类器),这样 Bagging 才能有用武之地。线性分类器或者 K-近邻都是较为稳定的分类器,本身方差就不大,所以以它们为基分类器使用 Bagging 并不能在原有基分类器的基础上获得更好的表现,甚至可能因为 Bagging 的采样,导致他们在训练中更难收敛,从而增大集成分类器的偏差。
AdaBoost
简要的介绍:
- https://www.bilibili.com/video/BV1qQkgYTEN4
- https://www.youtube.com/watch?v=AtYN8QP-U6w&ab_channel=Serrano.Academy
下面是 AdaBoost 相关的 pdf 存档。
上面的两个视频链接,有一个配套的 notebook:
或者也可以看李航的《统计学习方法》,不过那个写的比较学院派。
从 Adaboost 的例子中可以明显地看到 Boosting 的思想,对分类正确的样本降低了权重,对分类错误的样本升高或者保持权重不变。在最后进行模型融合的过程中,也根据错误率对基分类器进行加权融合。错误率低的分类器拥有更大的“话语权”。
预测器的准确率越高,其权重就越高。如果它只是随机猜测,则其权重接近于零。但是,如果大部分情况下它都是错的(也就是准确率比随机猜测还低),那么它的权重为负。
样本权重:
- Bagging 使用的是均匀取样,每个样本权重相等;
- Boosting 根据错误率调整样本权重,错误率越大的样本权重越大。错误率大的样本被取样的概率越高。
从减小方差和偏差的角度解释 Boosting 和 Bagging
Bagging 能提高弱分类器的性能是因为降低了方差,Boosting 则降低了偏差。
Bagging 是 Bootstrap Aggregating 的简称,即再抽样,然后在每个样本上训练出来的模型取平均。
现尝试计算样本均值
的方差。设每个 $X_i$ 都有相同方差 $\mathrm{D}(X_i)=\sigma^2$,并且任意两两之间协方差 $\mathrm{Cov}(X_i,X_j)=\rho\,\sigma^2$($i\neq j$)。
写出方差的展开:
利用方差和协方差的线性性质有:
代回并化简:
又因为:
即:
当 $\rho=0$(完全独立)时,上式退化为:
也就是方差缩小到原来的 $1/n$ 。
粗糙地从模型的角度理解这个问题,即,对 n 个独立不相关的模型的预测结果取平均,方差是原来单个模型的 1/n。当然,模型之间不可能完全独立。为追求独立性,许多 Bagging 方法做了不同改进。比如在随机森林算法中,每次选取节点分裂属性时,会随机抽取一个属性子集,而不是从所有属性中选取最优属性,这就是为了避免弱分类器之间过强的相关性。通过训练集的重采样也能够带来弱分类器之间的一定独立性,从而降低 Bagging 后模型的方差。
对于 Boosting,训练完一个弱分类器后,需要计算弱分类器的错误或残差,作为下一个分类器的输入。这个过程本身就是在不断减小损失函数,来使模型不断逼近“靶心”,使得模型偏差不断降低。但 Boosting 的过程并不会显著降低方差。这是因为 Boosting 的训练过程使得各弱分类器之间是强相关的,缺乏独立性,所以并不会对降低方差有作用。
梯度提升决策树 GBDT
GBDT
梯度提升决策树(Gradient Boosting Decision Tree,GBDT),GBDT 体现了“从错误中学习”的理念,基于决策树预测的残差进行迭代学习。GBDT 中使用的决策树通常为 CART 。
下面举一个简单的例子。
以一个视频网站的用户画像为例,为了将广告定向投放给指定年龄的用户,视频网站需要对每个用户的年龄做出预测。在这个问题中,每个样本是一个已知性别/年龄的用户,而特征则包括这个人访问的时长、时段、观看的视频的类型等。
例如用户 A 的真实年龄是 25 岁,但第一棵决策树的预测年龄是 22 岁,差了 3 岁,即残差为 3。那么在第二棵树里我们把 A 的年龄设为 3 岁去学习,如果第二棵树能把 A 分到 3 岁的叶子节点,那两棵树的结果相加就可以得到 A 的真实年龄;如果第二棵树的结论是 5 岁,则 A 仍然存在 −2 岁的残差,第三棵树里 A 的年龄就变成−2 岁,继续学。这里使用残差继续学习,就是 GBDT 中 Gradient Boosted 所表达的意思。
一个更形象的例子:
模型的任务是预测一个人的年龄,训练集只有 A、B、C、D 四个人,他们的年龄分别是 14、16、24、26,特征包括了“月购物金额”“上网时长”“上网历史”等。下面开始训练第一棵树,训练的过程跟传统决策树相同,简单起见,我们只进行一次分枝。训练好第一棵树后,求得每个样本预测值与真实值之间的残差。可以看到,A、B、C、D 的残差分别是−1、1、−1、1。这时我们就用每个样本的残差训练下一棵树,直到残差收敛到某个阈值以下,或者树的总数达到某个上限为止。
由于 GBDT 是利用残差训练的,在预测的过程中,我们也需要把所有树的预测值加起来,得到最终的预测结果。
伪代码示意:
另一个图示:
梯度提升、梯度下降
ref: https://zh.wikipedia.org/wiki/%E6%A2%AF%E5%BA%A6%E6%8F%90%E5%8D%87%E6%8A%80%E6%9C%AF
与其他增强方法一样,梯度增强以迭代方式将弱的“学习器”组合为一个强学习器。最简单的解释是在最小二乘回归中,通过最小化均方误差 $\frac{1}{n} \sum_{i}(\hat{y_i} - y_i)^2$,“教”模型 $F$ 预测实数值 $\hat{y} = F(x)$。
在梯度提升的每个阶段 $m, 1 \leq m \leq M$,假设已经有一个不太完美的模型 $F_m$(最开始时只是一个预测输出变量 $y$ 均值的模型)。梯度提升算法通过在当前模型 $F_m$ 增加一个新的估计量 $h$ 得到一个更好的模型:
为了求得 $h$,梯度提升基于以下观察:一个完美的 $h$ 可以完美预测当前不完美模型 $F_m$ 的残差,即满足,
或者,等效地有,
因此,梯度提升通过拟合残差 $y - F_m(x)$ 得到 $h$。和其他提升方法的变体一样,$F_{m+1}$ 通过纠正 $F_m$ 的误差变得更完美。这个想法可以扩展到均方误差损失之外的任意损失函数,甚至扩展到分类与排序问题,只要观察到以下一点:模型的残差 $y - F_m(x)$ 就是均方损失函数 $\frac{1}{2}(y - F(x))^2$ 关于 $F(x)$ 的负梯度。 因此,梯度提升其实是一种梯度下降算法 (这里有一个翻译问题造成了可能的困惑,“提升方法”英文为 Boosting),可以代入除了均方损失之外的不同的损失函数,得到不同的梯度。
梯度提升和梯度下降的区别和联系是什么?
两者都是在每一轮迭代中,利用损失函数相对于模型的负梯度方向的信息来对当前模型进行更新,只不过在梯度下降中,模型是以参数化形式表示,从而模型的更新等价于参数的更新。而在梯度提升中,模型并不需要进行参数化表示,而是直接定义在函数空间中,从而大大扩展了可以使用的模型种类。
额外补充,ref: https://zhuanlan.zhihu.com/p/86354141
GBDT 的优点和局限性
优点:
- 预测阶段的计算速度快,树与树之间可“并行”化计算。(前一个有结果可以给下一个,类似于流水线,所有人都在干活,看起来好像是并行的)
- 在分布稠密的数据集上,泛化能力和表达能力都很好,这使得 GBDT 在 Kaggle 的众多竞赛中,经常名列榜首。
- 采用决策树作为弱分类器使得 GBDT 模型具有较好的解释性和鲁棒性,能够自动发现特征间的高阶关系,并且也不需要对数据进行特殊的预处理如归一化等。
局限性:
- GBDT 在高维稀疏的数据集上,表现不如支持向量机或神经网络。
- GBDT 在处理文本分类特征问题上,相对其他模型的优势不如它在处理数值特征时明显。
- 训练过程需要串行训练,只能在决策树内部采用一些局部并行的手段提高训练速度。
XGBoost
XGBoost 是陈天奇等人开发的一个开源机器学习项目,高效地实现了 GBDT 算法并进行了算法和工程上的许多改进,被广泛应用在 Kaggle 竞赛及其他许多机器学习竞赛中并取得了不错的成绩。