[toc]
Machine Learning with Python
机器学习前期基础
监督/无监督学习算法
- 从输入/ 输出对中进行学习的机器学习算法叫作监督学习算法(supervised learning algorithm);
- 无监督学习算法(unsupervised learning algorithm):在无监督学习中,只有输入数据是已知的,没有为算法提供输出数据。虽然这种算法有许多成功的应用,但理解和评估这些算法往往更加困难。
- 无论是监督学习任务还是无监督学习任务,将输入数据表征为计算机可以理解的形式都是十分重要的。
- 每当想要根据给定输入预测某个结果,并且还有输入/ 输出对的示例时,都应该使用监督学习。
数据
- 将数据想象成表格:每一行被称为一个样本(sample)或数据点;而每一列(用来描述这些实体的属性)则被称为特征(feature)。
工具
- scikit-learn
- scikit-learn user_guide
- numpy; scipy; matplotlib; pandas
- Jupyter Notebook
机器学习步骤
构建一个机器学习模型
- 一部分数据用于构建机器学习模型,叫作训练数据(training data)或训练集(training set)
- 其余的数据用来评估模型性能,叫作测试数据(test data)、测试集(test set)或留出集(hold-out set)
一般将75%的行数据及对应标签作为训练集,剩下25%的数据及其标签作为测试集。
scikit-learn
中的train_test_split
函数1
2
3
4
5
6
7from sklearn.datasets import load_iris
iris_dataset = load_iris()
# 训练集、测试集划分函数
from sklearn.model_selection import train_test_split
# train_test_split 函数利用伪随机数生成器将数据集打乱,确保测试集中包含所有类别的数据。
X_train, X_test, y_train, y_test = train_test_split(
iris_dataset["data"],iris_dataset["target"],random_state=0)
观测数据
算法
- 分类算法:如,k近邻算法
1
2
3# 引入K近邻分类器,并实例化,给出近邻数目
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 1)
训练
1 | knn.fit(X_train,y_train) |
预测@评估
1 | y_pred = knn.predict(X_test) |
监督学习
- 监督机器学习问题主要有两种,分别叫作分类(classification)与回归(regression)。
如果在可能的结果之间具有连续性,那么它就是一个回归问题
graph LR A[监督学习]==>B(分类) A==>C(回归) B==>D(二分类/多分类:目标是预测类别标签) D==>E1(正类) D==>E2(反类) C==>F(回归任务的目标是预测一个连续值) style A fill:#ffff
过拟合/欠拟合
如果你在拟合模型时过分关注训练集的细节,得到了一个在训练集上表现很好、但不能泛化到新数据上的模型,那么就存在过拟合(overfitting)。
选择过于简单的模型被称为欠拟合(underfitting)。
我们的模型越复杂,在训练数据上的预测结果就越好。但是,如果我们的模型过于复杂,我们开始过多关注训练集中每个单独的数据点,模型就不能很好地泛化到新数据上。
正则化方法:在训练数据不够多时,或者overtraining时,常常会导致过拟合(overfitting)。正则化方法即为在此时向原始模型引入额外信息,以便防止过拟合和提高模型泛化性能的一类方法的统称。在实际的深度学习场景中我们几乎总是会发现,最好的拟合模型(从最小化泛化误差的意义上)是一个适当正则化的大型模型。
监督学习算法
KNN:KNeighbors
> KNeighbors 分类器有2 个重要参数:邻居个数与数据点之间距离的度量方法;
> 虽然k 近邻算法很容易理解,但由于预测速度慢且不能处理具有很多特征的数据集,所以
在实践中往往不会用到
- 以n_neighbors 为自变量,对比训练集精度和测试集精度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, stratify=cancer.target, random_state=66)
training_accuracy = []
test_accuracy = []
# n_neighbors取值从1到10
neighbors_settings = range(1, 11)
for n_neighbors in neighbors_settings:
# 构建模型
clf = KNeighborsClassifier(n_neighbors=n_neighbors)
clf.fit(X_train, y_train)
# 记录训练集精度
training_accuracy.append(clf.score(X_train, y_train))
# 记录泛化精度
test_accuracy.append(clf.score(X_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label="training accuracy")
plt.plot(neighbors_settings, test_accuracy, label="test accuracy")
plt.ylabel("Accuracy")
plt.xlabel("n_neighbors")
plt.legend()
plt.show()
线性模型
- 线性模型利用输入特征的线性函数(linear function)进行预测
用于回归的线性模型:
> ![](https://gitee.com/eastsheng/VnoteFigures/raw/master/worknotes/notes/coding/python/machinelearning/mlpython-1.md/331633410220872.png)
> 用于回归的线性模型可以表示为这样的回归模型:对单一特征的预测结果是一条直线,两
个特征时是一个平面,或者在更高维度(即更多特征)时是一个超平面。
> 有许多不同的线性回归模型。这些模型之间的区别在于如何从训练数据中学习参数w 和
b,以及如何控制模型复杂度
线性回归(普通最小二乘法)
> 线性回归,或者普通最小二乘法(ordinary least squares,OLS),是回归问题最简单也最经
典的线性方法。
> 线性回归没有参数,这是一个优点,但也因此无法控制模型的复杂度。
> 均方误差(mean squared error)是预测值与真实值之差的平方和除
以样本数
> 线性回归寻找参数w 和b,使得对训练集的预测值与真实的回归目标值y
之间的均方误差最小
> 训练集和测试集之间的性能差异是过拟合的明显标志
- 线性回归使用例子:
1 | from sklearn.model_selection import train_test_split |
岭回归(ridge regression)
岭回归也是一种用于回归的线性模型,因此它的预测公式与普通最小二乘法相同
但在岭回归中,对系数(w)的选择不仅要在训练数据上得到好的预测结果,而且还要拟合附加约束。我们还希望系数尽量小。换句话说,w 的所有元素都应接近于0。
这种约束是所谓正则化(regularization)的一个例子
岭回归用到的这种被称为L2 正则化
Ridge 是一种约束更强的模型,所以更不容易过拟合。岭回归使用例子:
1
2
3from sklearn.linear_model import Ridge
ridge = Ridge(alpha=1.0).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge.score(X_train, y_traiRidge 模型在模型的简单性(系数都接近于0)与训练集性能之间做出权衡。简单性和训练
集性能二者对于模型的重要程度可以由用户通过设置alpha 参数来指定
默认alpha=1.0
增大alpha 会使得系数更加趋向于0,从而降低训练集性能,但可能会提高泛化性能。如果数据点少,线性回归可能学不到任何内容。随着模型可用的数据越来越多,两个模型的性能都在提升,最终线性回归的性能追上了岭回归
如果有足够多的训练数据,正则化变得不那么重要,并且岭回归和线性回归将具有相同的性能.
lasso
除了Ridge,还有一种正则化的线性回归是Lasso。与岭回归相同,使用lasso 也是约束系数使其接近于0,但用到的方法不同,叫作L1 正则化。
L1 正则化的结果是,使用lasso 时某些系数刚好为0。这说明某些特征被模型完全忽略。
Lasso使用例子:
1
2
3
4
5from sklearn.linear_model import Lasso
lasso = Lasso().fit(X_train, y_train)
print("Training set score: {:.2f}".format(lasso.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso.score(X_test, y_test)))
print("Number of features used: {}".format(np.sum(lasso.coef_ != 0)))在两个模型中一般首选岭回归。但如果特征很多,你认为只有其中几个是重要的,那么选择Lasso 可能更好。
如果你想要一个容易解释的模型,Lasso 可以给出更容易理解的模型,因为它只选择了一部分输入特征
用于分类的线性模型
-
对于用于回归的线性模型,输出ŷ 是特征的线性函数,是直线、平面或超平面(对于更高维的数据集)。对于用于分类的线性模型,决策边界是输入的线性函数。换句话说,(二元)线性分类器是利用直线、平面或超平面来分开两个类别的分类器。
学习线性模型有很多种算法。这些算法的区别在于以下两点:
系数和截距的特定组合对训练数据拟合好坏的度量方法;
是否使用正则化,以及使用哪种正则化方法。最常见的两种线性分类算法:
Logistic 回归(logistic regression):
linear_model.LogisticRegression
中实现,虽然LogisticRegression
的名字中含有回归(regression
), 但它是一种分类算法, 并不是回归算法, 不应与LinearRegression
混淆。
线性支持向量机(linear support vector machine, 线性SVM)
用于多分类的线性模型
- 许多线性分类模型只适用于二分类问题,不能轻易推广到多类别问题(除了Logistic 回归)。将二分类算法推广到多分类算法的一种常见方法是“一对其余”(one-vs.-rest)方法。
优点、缺点和参数
线性模型的主要参数是正则化参数:
回归模型中叫作alpha
alpha,在LinearSVC 和Logistic-Regression 中叫作C。
alpha 值较大或C 值较小,说明模型比较简单
通常在对数尺度上对C 和alpha 进行搜索正则化选择:
如果你假定只有几个特征是真正重要的,那么你应该用L1 正则化,否则应默认使用L2 正则化
优点和缺点:
线性模型的训练速度非常快,预测速度也很快
这种模型可以推广到非常大的数据集,对稀疏数据也很有效。
如果你的数据包含数十万甚至上百万个样本,你可能需要研究如何使用LogisticRegression 和Ridge 模型的solver=’sag’ 选项,在处理大型数据时,这一选项比默认值要更快。
线性模型的另一个优点在于,利用我们之间见过的用于回归和分类的公式,理解如何进行预测是相对比较容易的。不幸的是,往往并不完全清楚系数为什么是这样的。
如果特征数量大于样本数量,线性模型的表现通常都很好
朴素贝叶斯分类器
sklearn
中一共三种朴素贝叶斯分类器:GaussianNB
、BernoulliNB
和MultinomialNB
GaussianNB
可应用于任意连续数据, 而BernoulliNB
假定输入数据为二分类数据,MultinomialNB
假定输入数据为计数数据(即每个特征代表某个对象的整数计数,比如一个单词在句子里出现的次数)。BernoulliNB
和MultinomialNB
主要用于文本数据分类。
优缺点
训练速度快;但是泛化能力差点儿
决策树
决策树是广泛用于分类和回归任务的模型,本质上,它从一层层的if/else 问题中进行学习,并得出结论。
- 使用乳腺癌数据集进行决策树学习
1
2
3
4
5
6
7
8
9
10from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, stratify=cancer.target, random_state=40)
tree = DecisionTreeClassifier(random_state=0)
tree.fit(X_train, y_train)
print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))未剪枝的树容易过拟合,对新数据的泛化性能不佳。
1
2
3
4
5
6
7
8
9
10
11
12from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, stratify=cancer.target, random_state=40)
# tree = DecisionTreeClassifier(random_state=0)
# tree.fit(X_train, y_train)
tree = DecisionTreeClassifier(max_depth=4,random_state=0)
tree.fit(X_train, y_train)
print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))设置max_depth=4,这意味着只可以连续问4 个问题;
限制树的深度可以减少过拟合;
会降低训练集的精度,但可以提高测试集的精度;
防止过拟合有两种常见的策略:一种是及早停止树的生长,也叫预剪枝(pre-pruning);另一种是先构造树,但随后删除或折叠信息量很少的结点,也叫后剪枝(post-pruning)或剪枝(pruning)。预剪枝的限制条件可能包括限制树的最大深度、限制叶结点的最大数目,或者规定一个结点中数据点的最小数目来防止继续划分。- scikit-learn 的决策树在DecisionTreeRegressor 类和DecisionTreeClassifier 类中实现。scikit-learn 只实现了预剪枝,没有实现后剪枝。
生成决策树png
1 | from sklearn.tree import DecisionTreeClassifier |
- 安装graphviz
- 转换dot to png~p53
1
dot -Tpng tree.dot -o tree.png
决策树集成
决策树的主要缺点在于,即使做了预剪枝,它也经常会过拟合,泛化性能很差。因此,在大多数应用中,往往使用集成方法来替代单棵决策树。
集成(ensemble)是合并多个机器学习模型来构建更强大模型的方法
有两种常用集成模型:分别是随机森林(random forest)和梯度提升决策树(gradient boosted decision tree)。
1 | from sklearn.ensemble import RandomForestClassifier |
- 梯度提升决策树是监督学习中最强大也最常用的模型之一,主要缺点是需要仔细调参,而且训练时间可能会比较长
- 梯度提升树模型的主要参数包括树的数量n_estimators 和学习率learning_rate,后者用于控制每棵树对前一棵树的错误的纠正强度。这两个参数高度相关,因为learning_rate 越低,就需要更多的树来构建具有相似复杂度的模型
- 随机森林的n_estimators 值总是越大越好,但梯度提升不同,增大n_estimators 会导致模型更加复杂,进而可能导致过拟合。通常的做法是根据时间和内存的预算选择合适的n_estimators,然后对不同的learning_rate 进行遍历。
- 另一个重要参数是max_depth(或max_leaf_nodes),用于降低每棵树的复杂度。梯度提升模型的max_depth 通常都设置得很小,一般不超过5。
核支持向量机(kernelized support vector machine)
- 这里需要记住的是,向数据表示中添加非线性特征,可以让线性模型变得更强大
- 核技巧(kernel trick),它的原理是直接计算扩展特征表示中数据点之间的距离(更准确地说是内积),而不用实际对扩展进行计算。
- 一种是多项式核,在一定阶数内计算原始特征所有可能的多项式(比如feature1 ** 2 * feature2 ** 5);另一种是径向基函数(radial basis function,RBF)核,也叫高斯核。高斯核有点难以解释,因为它对应无限维的特征空间。一种对高斯核的解释是它考虑所有阶数的所有可能的多项式,但阶数越高,特征的重要性越小。
神经网络(深度学习)
虽然深度学习在许多机器学习应用中都有巨大的潜力,但深度学习算法往往经过精确调整,只适用于特定的使用场景。
多层感知机(multilayer perceptron,MLP),它可以作为研究更复杂的深度学习方法的起点。MLP 也被称为(普通)前馈神经网络,有时也简称为神经网络。
MLP 可以被视为广义的线性模型,执行多层处理后得到结论。
$ŷ = w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b$
图中,左边的每个结点代表一个输入特征,连线代表学到的系数,右边的结点代表输出,是输入的加权求和。
在MLP 中,多次重复这个计算加权求和的过程,首先计算代表中间过程的隐单元(hiddenunit),然后再计算这些隐单元的加权求和并得到最终结果
这个模型需要学习更多的系数(也叫作权重):在每个输入与每个隐单元(隐单元组成了隐层)之间有一个系数,在每个隐单元与输出之间也有一个系数。
校正非线性(rectifying nonlinearity,也叫校正线性单元或relu)或正切双曲线(tangens hyperbolicus,tanh)有了这两种非线性函数,神经网络可以学习比线性模型复杂得多的函数。这些由许多计算层组成的大型神经网络,正是术语“深度学习”的灵感来源。
包含100 个隐单元的神经网络在two_moons 数据集上学到的决策边界
1
2
3
4
5
6
7
8
9
10
11
12
13
14from sklearn.neural_network import MLPClassifier
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
import mglearn
from sklearn.model_selection import train_test_split
X, y = make_moons(n_samples=100, noise=0.25, random_state=3)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y,
random_state=42)
mlp = MLPClassifier(solver='lbfgs', hidden_layer_sizes=[100],random_state=0).fit(X_train, y_train)
mglearn.plots.plot_2d_separator(mlp, X_train, fill=True, alpha=.3)
mglearn.discrete_scatter(X_train[:, 0], X_train[:, 1], y_train)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.show()控制神经网络复杂度的方法有很多种:隐层的个数、每个隐层中的单元个数与正则化(alpha)等。
总结
最近邻
适用于小型数据集,是很好的基准模型,很容易解释。
线性模型
非常可靠的首选算法,适用于非常大的数据集,也适用于高维数据。
朴素贝叶斯
只适用于分类问题。比线性模型速度还快,适用于非常大的数据集和高维数据。精度通常要低于线性模型。
决策树
速度很快,不需要数据缩放,可以可视化,很容易解释。
随机森林
几乎总是比单棵决策树的表现要好,鲁棒性很好,非常强大。不需要数据缩放。不适用于高维稀疏数据。
梯度提升决策树
精度通常比随机森林略高。与随机森林相比,训练速度更慢,但预测速度更快,需要的内存也更少。比随机森林需要更多的参数调节。
支持向量机
对于特征含义相似的中等大小的数据集很强大。需要数据缩放,对参数敏感。
神经网络
可以构建非常复杂的模型,特别是对于大型数据集而言。对数据缩放敏感,对参数选取敏感。大型网络需要很长的训练时间。
面对新数据集,通常最好先从简单模型开始,比如线性模型、朴素贝叶斯或最近邻分类器,看能得到什么样的结果。对数据有了进一步了解之后,你可以考虑用于构建更复杂模型的算法,比如随机森林、梯度提升决策树、SVM 或神经网络。
无监督学习
- 无监督学习的一个主要挑战就是评估算法是否学到了有用的东西
- 无监督算法的另一个常见应用是作为监督算法的预处理步骤
无监督学习类型
无监督变换(降维)
聚类算法