请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化平台 帖子:3364468 新帖:34

【机器学习】k近邻分类与回归实战

外汇老法师发表于:5 月 10 日 07:00回复(1)

在这一节中,可以了解到K近邻算法,并应用于分类与回归的例子。

k近邻又称作k-NN算法,是最简单的机器学习算法。非常的适合小白入门了解机器学习原理。k-NN会保存训练的数据,在面对新的数据时,算法会在训练数据集中找到最近的数据点,这也就是为什么被叫作“最近邻”的原因。

本节的数据将基于上一章节的数据,如有疑问,请查看上一章节。

备注:mgleran中的数据是用来展示的,不与机器学习的sklern模块相重叠。

*mgleran请使用pip install mglearn命令。

# 在学习之前,先导入这些常用的模块import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport mglearn

k近邻分类

k-NN 算法最简单的版本是只考虑一个最近邻,即被预测的新的数据点离训练的数据集中的哪个点最近,它将被归类为哪个类别。

在mglearn的forge中,内置了此种情况,如下图为单一最近邻模型对forge数据集的预测结果,五角星为被预测的数据点,根据其离得最近的训练数据集,通过设置参数n_nei*ors=1来设定“最近邻”的个数。

mglearn.plots.plot_knn_classification(n_nei*ors=1)

从上图我们就能明白,新数据离得谁最近,他就会被归类为哪一类。

左上角的五角星其实应该属于三角星一类,为了提高准确率,这里可以提高“最近邻”个数,即n_nei*ors值。再来看一下当n_nei*ors=3时的情况:

mglearn.plots.plot_knn_classification(n_nei*ors=3)

当提高“最近邻”的个数后,可以看到,对于新数据的预测更准确了,左上角的五角星近相近的是一个圆和两个三角星,因此它被归类于三角一类。

下面来看看如何通过 scikit-learn 来应用 k 近邻算法。

# 导入 train_test_splitfrom sklearn.model_selection import train_test_split# 导入二分类数据集X, y = mglearn.datasets.make_forge()# 将数据打乱,并分为训练集与测试集X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

上面的代码提供了数据集,接下来,需要实例化k-NN对象。

# 导入k-NN模型from sklearn.nei*ors import KNei*orsClassifier# 将k-NN模型实例为对象,并指定最近邻个数clf = KNei*orsClassifier(n_nei*ors=3)

现在,我们就有了最近邻算法模型实例化的对象了,该对象的引用被保存到了变量clf中。

接下来,我们使用该对象对训练集数据进行训练,以得出一个模型结果。

clf.fit(X_train, y_train)
KNei*orsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_nei*ors=3, p=2,
           weights='uniform')

对于训练集训练的结果,会被保存在k-NN对象中,所以,该对象会对新数据在此基础上进行预测。

接下来,对测试集进行预测,并查看预测结果。

# 预测测试集数据clf.predict(X_test)
array([1, 0, 1, 0, 1, 0, 0])
# 评估模型的泛化能力clf.score(X_test, y_test)
0.8571428571428571

可以看到,模型的精度为86%,也就是说,该模型对于测试数据的预测,有86%的结果是正确的。

接下来要做的,是在多张图表中展示不同“最近邻”参数下,模型对于数据的分类能力的体现。而这种分类,采用决策边界来展示。

接下来将分析“最近邻”分另为1、3、9的情况。

# 通过subplots创建一个幕布,在幕布上创建三个绘图区,幕布大小为10*3fig, axes = plt.subplots(1, 3, figsize=(10,3))# 通过zip函数,将两个集体打包并成对的返回for n_nei*ors, ax in zip([1, 3, 9], axes):# fit方法返回对象本身,所以我们可以将实例化和拟合放在一行代码中clf = KNei*orsClassifier(n_nei*ors=n_nei*ors).fit(X, y)# 展示模型的决策边界mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=.4)# 将原始数据的位置在图中展示 mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)# 设置标题ax.set_title('n_nei*ors{}'.format(n_nei*ors))# 设置横坐标标签ax.set_xlabel('feature 0')# 设置纵坐标标签ax.set_ylabel('feature 1')# 在第一张图上显示图例axes[0].legend(loc=3)
plt.show()

从上图可以发现,“最近邻”的个数变大后,决策边界将变得更加的平缓,曲线也变得更加的简单。这种更简单的情形,比较适合于大多数的数据。

这种结论也能说明,更简单的模型,泛化能力更好。

接下来认证一下模型复杂度与泛化能力之间的关系

这次将使用乳腺癌数据集,对该数据用不同的“最邻近”个数进行训练与测试,然后对于评估结果展示一个线性的结果。

# 导入乳腺癌数据集模块from sklearn.datasets import load_breast_cancer# 加载数据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_nei*ors 取值从1到10nei*ors_settings = range(1, 11)# 循环测试不同“最近邻”参数for n_nei*ors in nei*ors_settings:# 构建模型 clf = KNei*orsClassifier(n_nei*ors=n_nei*ors)# 训练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(nei*ors_settings, training_accuracy, label="training accuracy")# 画出测试集的曲线图plt.plot(nei*ors_settings, test_accuracy, label="test accuracy")# 设置x与y轴标签plt.xlabel('n_nei*ors')
plt.ylabel('Accuracy')# 展示图例plt.legend()
plt.show()

能过上图的展示发现,训练集的泛化精度随着“最近邻”个数的增加,精度越来越低。而测试集的泛化精度随着“最近邻”个数的增加,先上长后下降。两者的最佳取值大概在n_nei*ors=6这个位置。

也就是说,当“最近邻”个数过小的时候,模型过于复杂,不适用于新数据。而“最近邻”个数过大,则模型会变得过于简单,性能也会变差。

k近邻回归

k近邻算法还适用于回归。在mglearn的w*e中内置了一个回归数据集。现在,在该数据集上再添加三个测试点,利用单一“最近邻”参数来预测目标的结果值。如下:

mglearn.plots.plot_knn_regression(n_nei*ors=1)

再来看下“最近邻”个数为3时的预测值。

mglearn.plots.plot_knn_regression(n_nei*ors=3)

上面两个图例是现成的模型,在 scikit-learn 中的 KNei*orsRegressor 类用于回归算法的实现,它的用法与 KNei*orsClassifier 的用法相似。

# 导入 KNei*orsRegressor 模块from sklearn.nei*ors import KNei*orsRegressor# 加载40个回归数据集X, y = mglearn.datasets.make_w*e(n_samples=40)# 将w*e数据集分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)# 模型实例化,并将邻居个数设置为3reg = KNei*orsRegressor(n_nei*ors=3)# 利用训练数据和训练目标值为拟合模型reg.fit(X_train, y_train)
KNei*orsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
          metric_params=None, n_jobs=1, n_nei*ors=3, p=2,
          weights='uniform')

然后对测试集进行预测:

reg.predict(X_test)
array([-0.05396539,  0.35686046,  1.13671923, -1.89415682, -1.13881398,       -1.63113382,  0.35686046,  0.91241374, -0.44680446, -1.13881398])

评估一下模型的泛化精度:

reg.score(X_test, y_test)
0.8344172446249604

对于回归模型,scroe方法返回的是R的平方数,也叫做决定系统,是回归模型预测的优度度量,位于0到1之间。R的平方等于1对应完美预测,R的平方等于0对应常数模型,即总是预测训练集响应(y_train)的平均值。

分析 KNei*orsRegressor

同样,这里来展示“最近邻”个数分别为1、3、9下的泛化能力。

fig, axes = plt.subplots(1, 3, figsize=(15, 4))# 创建1000个数据点,在-3和3之间均匀分布line = np.linspace(-3, 3, 1000).reshape(-1, 1)for n_nei*ors, ax in zip([1, 3, 9], axes):# 利用1、3、9个邻居分别进行预测reg = KNei*orsRegressor(n_nei*ors=n_nei*ors)
    reg.fit(X_train, y_train)# 展示预测曲线与训练集和测试集的关系ax.plot(line, reg.predict(line))
    ax.plot(X_train, y_train, '^', c=mglearn.cm2(0), markersize=8)
    ax.plot(X_test, y_test, 'v', c=mglearn.cm2(1), markersize=8)

    ax.set_title('{} nei*or(s)\n train score: {:.2f} test score: {:.2f}'.format(n_nei*ors, reg.score(X_train, y_train), reg.score(X_test, y_test)))
    ax.set_xlabel('Feature')
    ax.set_ylabel('Target')
axes[0].legend(['Model predictions', 'Training data/target', 'Test data/target'], loc='best')
plt.show()

从图中可以看出,仅使用单一“最近邻”参数,训练集中的第个点都对预测结果有显著影响,非常不稳定。

而更大的“最近邻”个数所对应的预测结果也更平滑,但对训练数据的拟合不好。

总结:

一般来说,KNei*ors分类器有2个重要参数:邻居的个数与数据点之间距离的度量方法,在实践中,使用较小的邻居个数(比如3或5)往往可以得到比较好的结果。

k-NN的优点之一是比较容易理解,比较适合机器学习小白入门,但如果数据量特别大,该模型的表现就会很差。

在这一节中,可以了解到K近邻算法,并应用于分类与回归的例子。

k近邻又称作k-NN算法,是最简单的机器学习算法。非常的适合小白入门了解机器学习原理。k-NN会保存训练的数据,在面对新的数据时,算法会在训练数据集中找到最近的数据点,这也就是为什么被叫作“最近邻”的原因。

本节的数据将基于上一章节的数据,如有疑问,请查看上一章节。

备注:mgleran中的数据是用来展示的,不与机器学习的sklern模块相重叠。

*mgleran请使用pip install mglearn命令。

# 在学习之前,先导入这些常用的模块import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport mglearn

k近邻分类¶

k-NN 算法最简单的版本是只考虑一个最近邻,即被预测的新的数据点离训练的数据集中的哪个点最近,它将被归类为哪个类别。

在mglearn的forge中,内置了此种情况,如下图为单一最近邻模型对forge数据集的预测结果,五角星为被预测的数据点,根据其离得最近的训练数据集,通过设置参数n_nei*ors=1来设定“最近邻”的个数。

mglearn.plots.plot_knn_classification(n_nei*ors=1)
C:\Users\Administrator\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
  warnings.warn(msg, category=DeprecationWarning)

从上图我们就能明白,新数据离得谁最近,他就会被归类为哪一类。

左上角的五角星其实应该属于三角星一类,为了提高准确率,这里可以提高“最近邻”个数,即n_nei*ors值。再来看一下当n_nei*ors=3时的情况:

mglearn.plots.plot_knn_classification(n_nei*ors=3)
C:\Users\Administrator\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
  warnings.warn(msg, category=DeprecationWarning)

当提高“最近邻”的个数后,可以看到,对于新数据的预测更准确了,左上角的五角星近相近的是一个圆和两个三角星,因此它被归类于三角一类。

下面来看看如何通过 scikit-learn 来应用 k 近邻算法。

# 导入 train_test_splitfrom sklearn.model_selection import train_test_split# 导入二分类数据集X, y = mglearn.datasets.make_forge()# 将数据打乱,并分为训练集与测试集X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
C:\Users\Administrator\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
  warnings.warn(msg, category=DeprecationWarning)

上面的代码提供了数据集,接下来,需要实例化k-NN对象。

# 导入k-NN模型from sklearn.nei*ors import KNei*orsClassifier# 将k-NN模型实例为对象,并指定最近邻个数clf = KNei*orsClassifier(n_nei*ors=3)

现在,我们就有了最近邻算法模型实例化的对象了,该对象的引用被保存到了变量clf中。

接下来,我们使用该对象对训练集数据进行训练,以得出一个模型结果。

clf.fit(X_train, y_train)
KNei*orsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_nei*ors=3, p=2,
           weights='uniform')

对于训练集训练的结果,会被保存在k-NN对象中,所以,该对象会对新数据在此基础上进行预测。

接下来,对测试集进行预测,并查看预测结果。

# 预测测试集数据clf.predict(X_test)
array([1, 0, 1, 0, 1, 0, 0])
# 评估模型的泛化能力clf.score(X_test, y_test)
0.8571428571428571

可以看到,模型的精度为86%,也就是说,该模型对于测试数据的预测,有86%的结果是正确的。

接下来要做的,是在多张图表中展示不同“最近邻”参数下,模型对于数据的分类能力的体现。而这种分类,采用决策边界来展示。

接下来将分析“最近邻”分另为1、3、9的情况。

# 通过subplots创建一个幕布,在幕布上创建三个绘图区,幕布大小为10*3fig, axes = plt.subplots(1, 3, figsize=(10,3))# 通过zip函数,将两个集体打包并成对的返回for n_nei*ors, ax in zip([1, 3, 9], axes):# fit方法返回对象本身,所以我们可以将实例化和拟合放在一行代码中clf = KNei*orsClassifier(n_nei*ors=n_nei*ors).fit(X, y)# 展示模型的决策边界mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=.4)# 将原始数据的位置在图中展示 mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)# 设置标题ax.set_title('n_nei*ors{}'.format(n_nei*ors))# 设置横坐标标签ax.set_xlabel('feature 0')# 设置纵坐标标签ax.set_ylabel('feature 1')# 在第一张图上显示图例axes[0].legend(loc=3)plt.show()

从上图可以发现,“最近邻”的个数变大后,决策边界将变得更加的平缓,曲线也变得更加的简单。这种更简单的情形,比较适合于大多数的数据。

这种结论也能说明,更简单的模型,泛化能力更好。

接下来认证一下模型复杂度与泛化能力之间的关系¶

这次将使用乳腺癌数据集,对该数据用不同的“最邻近”个数进行训练与测试,然后对于评估结果展示一个线性的结果。

# 导入乳腺癌数据集模块from sklearn.datasets import load_breast_cancer# 加载数据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_nei*ors 取值从1到10nei*ors_settings = range(1, 11)# 循环测试不同“最近邻”参数for n_nei*ors in nei*ors_settings:# 构建模型 clf = KNei*orsClassifier(n_nei*ors=n_nei*ors)# 训练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(nei*ors_settings, training_accuracy, label="training accuracy")# 画出测试集的曲线图plt.plot(nei*ors_settings, test_accuracy, label="test accuracy")# 设置x与y轴标签plt.xlabel('n_nei*ors')plt.ylabel('Accuracy')# 展示图例plt.legend()plt.show()

能过上图的展示发现,训练集的泛化精度随着“最近邻”个数的增加,精度越来越低。而测试集的泛化精度随着“最近邻”个数的增加,先上长后下降。两者的最佳取值大概在n_nei*ors=6这个位置。

也就是说,当“最近邻”个数过小的时候,模型过于复杂,不适用于新数据。而“最近邻”个数过大,则模型会变得过于简单,性能也会变差。

k近邻回归¶

k近邻算法还适用于回归。在mglearn的w*e中内置了一个回归数据集。现在,在该数据集上再添加三个测试点,利用单一“最近邻”参数来预测目标的结果值。如下:

mglearn.plots.plot_knn_regression(n_nei*ors=1)

再来看下“最近邻”个数为3时的预测值。

mglearn.plots.plot_knn_regression(n_nei*ors=3)

上面两个图例是现成的模型,在 scikit-learn 中的 KNei*orsRegressor 类用于回归算法的实现,它的用法与 KNei*orsClassifier 的用法相似。

# 导入 KNei*orsRegressor 模块from sklearn.nei*ors import KNei*orsRegressor# 加载40个回归数据集X, y = mglearn.datasets.make_w*e(n_samples=40)# 将w*e数据集分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)# 模型实例化,并将邻居个数设置为3reg = KNei*orsRegressor(n_nei*ors=3)# 利用训练数据和训练目标值为拟合模型reg.fit(X_train, y_train)
KNei*orsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
          metric_params=None, n_jobs=1, n_nei*ors=3, p=2,
          weights='uniform')

然后对测试集进行预测:

reg.predict(X_test)
array([-0.05396539,  0.35686046,  1.13671923, -1.89415682, -1.13881398,
       -1.63113382,  0.35686046,  0.91241374, -0.44680446, -1.13881398])

评估一下模型的泛化精度:

reg.score(X_test, y_test)
0.8344172446249604

对于回归模型,scroe方法返回的是R的平方数,也叫做决定系统,是回归模型预测的优度度量,位于0到1之间。R的平方等于1对应完美预测,R的平方等于0对应常数模型,即总是预测训练集响应(y_train)的平均值。

分析 KNei*orsRegressor¶

同样,这里来展示“最近邻”个数分别为1、3、9下的泛化能力。

fig, axes = plt.subplots(1, 3, figsize=(15, 4))# 创建1000个数据点,在-3和3之间均匀分布line = np.linspace(-3, 3, 1000).reshape(-1, 1)for n_nei*ors, ax in zip([1, 3, 9], axes):# 利用1、3、9个邻居分别进行预测reg = KNei*orsRegressor(n_nei*ors=n_nei*ors)reg.fit(X_train, y_train)# 展示预测曲线与训练集和测试集的关系ax.plot(line, reg.predict(line))ax.plot(X_train, y_train, '^', c=mglearn.cm2(0), markersize=8)ax.plot(X_test, y_test, 'v', c=mglearn.cm2(1), markersize=8)ax.set_title('{} nei*or(s)\n train score: {:.2f} test score: {:.2f}'.format(n_nei*ors, reg.score(X_train, y_train), reg.score(X_test, y_test)))ax.set_xlabel('Feature')ax.set_ylabel('Target')axes[0].legend(['Model predictions', 'Training data/target', 'Test data/target'], loc='best')plt.show()

从图中可以看出,仅使用单一“最近邻”参数,训练集中的第个点都对预测结果有显著影响,非常不稳定。

而更大的“最近邻”个数所对应的预测结果也更平滑,但对训练数据的拟合不好。

总结:¶

一般来说,KNei*ors分类器有2个重要参数:邻居的个数与数据点之间距离的度量方法,在实践中,使用较小的邻居个数(比如3或5)往往可以得到比较好的结果。

k-NN的优点之一是比较容易理解,比较适合机器学习小白入门,但如果数据量特别大,该模型的表现就会很差。

 

全部回复

0/140

量化课程

    移动端课程