整体计划:时间不多的情况下需要快速构建机器学习系统,先有个整体框架,再慢慢学习。争取未来能够从企业级应用老旧领域转到数据分析和机器学习(人工智能)新兴领域,布局未来。
第1章 引言
人工智能、机器学习和深度学习的区别?机器学习是一种实现人工智能的方法,深度学习是一种实现机器学习的技术。我们就用最简单的方法——同心圆,可视化地展现出它们三者的关系:
机器学习介绍:机器学习(machine learning)是从数据中提取知识。 它是统计学、人工智能和计算机 科学交叉的研究领域, 也被称为预测分析(predictive analytics)或统计学习(statistical learning) 。
监督学习:从输入/输出对中进行学习的机器学习算法叫作监督学习算法
识别信封上手写的邮政编码
基于医学影像判断肿瘤是否为良性
检测信用卡交易中的诈骗行为
无监督学习:只有输入数据是已知的,没有为算法提供输出数据
确定一系列博客文章的主题
将客户分成具有相似偏好的群组
检测网站的异常访问模式
1.7 第一个应用:鸢尾花分类(使用k-NN)
一、kNN算法介绍
# kNN:k-Nearest Neighboors
# 多用于解决分类问题
1)特点:
1. 是机器学习中唯一一个不需要训练过程的算法,可以别认为是没有模型的算法,也可以认为训练数据集就是模型本身;
2. 思想极度简单;
3. 应用数学知识少(近乎为零);
4. 效果少;
5. 可以解释机械学习算法使用过程中的很多细节问题
6. 更完整的刻画机械学习应用的流程;
2)思想:
* 根本思想:两个样本,如果它们的特征足够相似,它们就有更高的概率属于同一个类别;
* 问题:根据现有训练数据集,判断新的样本属于哪种类型;
* 方法/思路:
1. 求新样本点在样本空间内与所有训练样本的欧拉距离;
2. 对欧拉距离排序,找出最近的k个点;
3. 对k个点分类统计,看哪种类型的点数量最多,此类型即为对新样本的预测类型;
二、代码实现(这个代码片段包含了应用 scikit-learn 中任何机器学习算法的核心代码。fit、predict 和 score 方法是 scikit-learn 监督学习模型中最常用的接口):
In[]:
# 打乱数据集,区分训练集和测试集
# scikit-learn 中的数据通常用大写的 X 表示, 而标签用小写的 y 表示。 这是受到了数学 标准公式 f ( x )= y 的启发,其中 x 是函数的输入, y 是输出。我们用大写的 X 是因为数据是 一个二维数组(矩阵), 用小写的 y 是因为目标是一个一维数组(向量), 这也是数学中 的约定
X_train, X_test, y_train, y_test = train_test_split( iris_dataset['data'], iris_dataset['target'], random_state=0)
# 实例化k近邻分类算法模型
knn = KNeighborsClassifier(n_neighbors=1)
# 基于训练集来构建模型
knn.fit(X_train, y_train)
# 做出预测
X_new = np.array([[5, 2.9, 1, 0.2]])
prediction = knn.predict(X_new)
print("Prediction: {}".format(prediction))
print("Predicted target name: {}".format(iris_dataset['target_names'][prediction]))
Out[]:
Prediction: [0]
Predicted target name: ['setosa’]
In[]:
# 计算测试集的精度
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Out[]:
# 测试集精度为0.97
Test set score: 0.97
第2章 监督学习
记住,每当想要根据给定输入预测某个结果,并且还有输入 / 输出对的示例时,都应该使 用监督学习。
2.1 分类与回归
监督机器学习问题主要有两种,分别叫作 分类 (classification)与 回归 (regression)。
区分分类任务和回归任务有一个简单方法,就是问一个问题:输出是否具有某种连续性。 如果在可能的结果之间具有连续性,那么它就是一个回归问题。
2.2 泛化 、 过拟合与欠拟合
2.3 监督学习算法
介绍最常用的机器学习算法
2.3.2 k 近邻
KNeighborsClassifier
分析KNeighborsClassifier
KNeighborsRegressor
分析KNeighborsRegressor
2.3.3 线性模型
线性模型利用输入特征的 线性函数 (linear function)进行预测
1. 用于回归的线性模型
# 下列代码可以在一维 wave 数据集上学习参数w [0]和 b :
In[25]:
mglearn.plots.plot_linear_regression_wave()
Out[25]:
# 从 w[0] 可以看出,斜率应该在 0.4 左 右,在图像中也可以直观地确认这一点。截距是指预测直线与 y 轴的交点:比 0 略小,也 可以在图像中确认。
w[0]: 0.393906
b: -0.031804
对单一特征的预测结果是一条直线(如上图)。
有许多不同的线性回归模型。 这些模型之间的区别在于如何从训练数据中学习参数w和 b ,以及如何控制模型复杂度。
2.线性回归
线性回归,或者 普通最小二乘法 (ordinary least squares,OLS) ,是回归问题最简单也最经 典的线性方法。线性回归寻找参数 w 和 b ,使得对训练集的预测值与真实的回归目标值 y 之间的 均方误差 最小。均方误差(mean squared error)是预测值与真实值之差的平方和除 以样本数。
In[26]:
from sklearn.linear_model import LinearRegression
X, y = mglearn.datasets.make_wave(n_samples=60)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
lr = LinearRegression().fit(X_train, y_train)
print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
Out[27]:
# “斜率”参数( w ,也叫作权重或 系数 )被保存在 coef_ 属性中, 而偏移或 截距 ( b )被保 存在 intercept_ 属性中
lr.coef_: [ 0.394]
lr.intercept_: -0.031804343026759746
In[28]:
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Out[28]:
# 训练集和测试集的性能
Training set score: 0.67
# R 2 约为 0.66, 这个结果不是很好,但我们可以看到,训练集和测试集上的分数非常接近。 这说明可能存在欠拟合,而不是过拟合
Test set score: 0.66
In[29]:
X, y = mglearn.datasets.load_extended_boston()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
lr = LinearRegression().fit(X_train, y_train)
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Out[30]:
# 比较一下训练集和测试集的分数就可以发现,我们在训练集上的预测非常准确,但测试集 上的 R 2 要低很多:
# 训练集和测试集之间的性能差异是过拟合的明显标志,因此我们应该试图找到一个可以控 制复杂度的模型。标准线性回归最常用的替代方法之一就是 岭回归
Training set score: 0.95
Test set score: 0.61
3. 岭回归
In[31]:
from sklearn.linear_model import Ridge
ridge = Ridge().fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge.score(X_test, y_test)))
Out[31]:
# 可以看出,Ridge 在训练集上的分数要 低 于 LinearRegression,但在测试集上的分数 更高 。 这和我们的预期一致。线性回归对数据存在过拟合。Ridge 是一种约束更强的模型,所以 更不容易过拟合。
Training set score: 0.89
Test set score: 0.75
在实践中,在两个模型中一般首选岭回归。但如果特征很多,你认为只有其中几个是重要 的, 那么选择 Lasso 可能更好。 同样, 如果你想要一个容易解释的模型,Lasso 可以给出 更容易理解的模型,因为它只选择了一部分输入特征。scikit-learn 还提供了 ElasticNet 类,结合了 Lasso 和 Ridge 的惩罚项。在实践中,这种结合的效果最好,不过代价是要调 节两个参数:一个用于 L1 正则化,一个用于 L2 正则化。
2.3.4 朴素贝叶斯分类器
朴素贝叶斯分类器是与上一节介绍的线性模型非常相似的一种分类器,但它的训练速度往 往更快。
2.3.5 决策树
决策树是广泛用于分类和回归任务的模型。 本质上, 它从一层层的if/else问题中进行学 习,并得出结论。
1. 构造决策树(我们可以利用监督 学习从数据中学习模型,而无需人为构建模型。)
想要对新数据点进行预测,首先要查看这个点位于特征空间划分的哪个区域,然后将该区 域的多数目标值(如果是纯的叶结点,就是单一目标值)作为预测结果。从根结点开始对 树进行遍历就可以找到这一区域,每一步向左还是向右取决于是否满足相应的测试。
2. 控制决策树的复杂度
In[58]:
from sklearn.tree import DecisionTreeClassifier
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split( cancer.data, cancer.target, stratify=cancer.target, random_state=42)
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)))
Out[58]:
# 未剪枝的树 容易过拟合,对新数据的泛化性能不佳
Accuracy on training set: 1.000
Accuracy on test set: 0.937
In[59]:
# 设置 max_depth=4,这意味着只可以连续问 4 个问题
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)))
Out[59]:
# 限制树的 深度可以减少过拟合。这会降低训练集的精度,但可以提高测试集的精度:
Accuracy on training set: 0.988
Accuracy on test set: 0.951
4.树的特征重要性
它为每个特征对树的决策的重要性 进行排序。对于每个特征来说,它都是一个介于 0 和 1 之间的数字,其中 0 表示“根本没 用到”, 1 表示“完美预测目标值”。特征重要性的求和始终为 1:
In[62]:
print("Feature importances:\n{}".format(tree.feature_importances_))
这里我们看到,顶部划分用到的特征(“worst radius” )是最重要的特征。这也证实了我们 在分析树时的观察结论,即第一层划分已经将两个类别区分得很好。
5. 优点 、 缺点和参数
如前所述,控制决策树模型复杂度的参数是预剪枝参数,它在树完全展开之前停止树的构 造。 通常来说, 选择一种预剪枝策略(设置 max_depth、max_leaf_nodes 或 min_samples_ leaf)足以防止过拟合。
2.3.7 核支持向量机
2.3.8 神经网络 ( 深度学习 )
用于分类和回归的多层感知机 (multilayer perceptron,MLP)简称为神经网络(深度学习) 。
1.神经网络模型
MLP可以被视为广义的线性模型,执行多层处理后得到结论。
2. 神经网络调参
控制神经网络复杂度的方法有很多种:隐层的个数、每个隐层 中的单元个数(隐单元)与正则化(alpha)。
将 MLPClassifier 应用在乳腺癌数据集上。首先使用默认参数:
In[99]:
print("Cancer data per-feature maxima:\n{}".format(cancer.data.max(axis=0)))
Out[99]:
Cancer data per-feature maxima: [ 28.110 39.280 188.500 … 0.664 0.207]
In[100]:
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
mlp = MLPClassifier(random_state=42)
mlp.fit(X_train, y_train)
print("Accuracy on training set: {:.2f}".format(mlp.score(X_train, y_train)))
print("Accuracy on test set: {:.2f}".format(mlp.score(X_test, y_test)))
Out[100]:
# MLP 的精度相当好,但没有其他模型好。原因可能在于数据的 缩放。神经网络也要求所有输入特征的变化范围相似,最理想的情况是均值为 0、方差为 1。 我们必须对数据进行缩放以满足这些要求。
Accuracy on training set: 0.92
Accuracy on test set: 0.90
3. 优点 、 缺点和参数
虽然 MLPClassifier 和 MLPRegressor 为最常见的神经网络架构提供了易于使用的接口,但 它们只包含神经网络潜在应用的一部分。如果你有兴趣使用更灵活或更大的模型,我们建议你看一下除了 scikit-learn 之外的很棒的深度学习库。对于 Python 用户来说, 最为完 善的是 keras、lasagna 和 tensor-flow。这些库提供了更为灵活的接口,可以用来构建神经网 络并跟踪深度学习研究的快速发展。所有流行的深度学习库也都允许使用高性能的图形处 理单元(GPU), 而 scikit-learn 不支持 GPU。 使用 GPU 可以将计算速度加快 10 到 100 倍, GPU 对于将深度学习方法应用到大型数据集上至关重要。
在机器学习的许多应用中,神经网络再次成为最先进的模型。它的主要优点之一是能够获 取大量数据中包含的信息,并构建无比复杂的模型。给定足够的计算时间和数据,并且仔 细调节参数,神经网络通常可以打败其他机器学习算法(无论是分类任务还是回归任务)。
2.4 分类器的不确定度估计
一般来说,你感兴趣的不仅是分类器会预测一个测试点属于哪个类别,还包括 它对这个预测的置信程度。(注意这个跟模型的精度也就是泛化能力的区别,泛化是模型的精度,不确定度是新数据预测的置信程度)
scikit-learn 中有两个函数可用于获取分类器的不确定度估计:decision_function(决策函数) 和 predict_proba(预测概率)。
In[105]:
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import make_circles
X, y = make_circles(noise=0.25, factor=0.5, random_state=1)
# 为了便于说明,我们将两个类别重命名为"blue"和"red”
y_named = np.array(["blue", "red"])[y]
# 我们可以对任意个数组调用train_test_split
# 所有数组的划分方式都是一致的
X_train, X_test, y_train_named, y_test_named, y_train, y_test = train_test_split(X, y_named, y, random_state=0)
# 构建梯度提升模型
gbrt = GradientBoostingClassifier(random_state=0)
gbrt.fit(X_train, y_train_named)
2.4.1 决策函数
In[107]:
# 显示decision_function的前几个元素
print(“Decision function:\n{}".format(gbrt.decision_function(X_test)[:6]))
Out[107]:
Decision function:
[ 4.136 -1.683 -3.951 -3.626 4.29 3.662]
In[108]:
print("Thresholded decision function:\n{}".format( gbrt.decision_function(X_test) > 0)) print("Predictions:\n{}".format(gbrt.predict(X_test)))
Out[108]:
# 对于二分类问题,“反”类始终是 classes_ 属性的第一个元素,“正”类是 classes_ 的第 二个元素。
Thresholded decision function:
[ True False False False True True False
True False True False False False True
False]
Predictions:
['red' 'blue' 'blue' 'blue' 'red' 'red' ‘blue'
'blue' 'red' 'blue' 'blue' 'blue' 'red' 'red' 'red' 'red' 'red' 'blue’
'blue']
2.4.2 预测概率
predict_proba 的输出是每个类别的概率, 通常比 decision_function 的输出更容易理解。
In[112]:
print("Shape of probabilities: {}".format(gbrt.predict_proba(X_test).shape))
Out[112]:
# 每行的第一个元素是第一个类别的估计概率,第二个元素是第二个类别的估计概率。由于 predict_proba 的输出是一个概率,因此总是在 0 和 1 之间,两个类别的元素之和始终为 1:
Shape of probabilities: (25, 2)
In[113]:
# 显示predict_proba的前几个元素
print("Predicted probabilities:\n{}".format( gbrt.predict_proba(X_test[:6])))
Out[113]:
# 由于两个类别的概率之和为 1,因此只有一个类别的概率超过 50%。 这个类别就是模型的预测结果。
Predicted probabilities: [[ 0.016 0.984]
[ 0.843 0.157] [ 0.981 0.019] [ 0.974 0.026] [ 0.014 0.986] [ 0.025 0.975]]