《深入浅出Python机器学习》读书笔记,第三章 K近邻算法
如果一个样本周围最近的K个样本都属于某一个类别,那么这个样本也属于这个类别。
生成一些数据,一类是紫色,一类是黄色
案例:
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
# 为聚类生成数据集,n_samples指定生成数据集的长度,centers是聚类中心点的个数(聚类后类别的个数),random_state设置种子,让数据可重现
data = make_blobs(n_samples=200, centers=2, random_state=8)
X,y = data
# 输出生成的数据
plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.spring, edgecolor='k')
plt.show()
打开Jupyter Notebook输入案例代码,点击运行,输出如下
这两类点数据可以看做是已知的两种类别,这里的输出结果是训练数据的一个可视化结果,接下来用生成的数据训练一个模型
案例:
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
data = make_blobs(n_samples=200, centers=2, random_state=8)
X,y = data
#创建一个K近邻分类器对象
clf = KNeighborsClassifier()
# 使用X作为训练数据,y作为目标值(类似于标签)来拟合模型
clf.fit(X,y)
# 取第1个维度组成的列表里的最小值加-1和第1个维度组成的列表里的最大值加+1
x_min, x_max = X[:,0].min() - 1, X[:,0].max() + 1
# 取第2个维度组成的列表里的最小值加-1和第2个维度组成的列表里的最大值加+1
y_min, y_max = X[:,1].min() - 1, X[:,1].max() + 1
# 生成一个足以覆盖所有点的坐标矩阵
xx,yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))
# 用训练好的模型预测;ravel()方法作用是将多维数组转化为1维数组
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
# reshape()方法作用是重新组织数据
Z = Z.reshape(xx.shape)
# 绘制分类图
plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Pastel1)
plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.spring, edgecolor='k')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier : KNN")
plt.show()
输入案例代码,点击运行,输出如下
这里基于训练集训练出一个分类模型,粉色部分是一个类别,灰色部分是一个类别。如果有新的数据输入,模型会自动将数据分到对应的分类。
测试集两个特征分别是6.75,和4.82,测试一下模型能否正确分类
在plt.show()
前加入如下代码
plt.scatter(6.75,4.82,marker='*',c='red',s=200)
e:\soft\py3\lib\site-packages\ipykernel_launcher.py:19: MatplotlibDeprecationWarning:
shading='flat' when X and Y have the same dimensions as C is deprecated since 3.3.
Either specify the corners of the quadrilaterals with X and Y, or pass shading='auto',
'nearest' or 'gouraud', or set rcParams['pcolor.shading']. This will become an error
two minor releases later.
报警告的原因是:
当X和Y的维度与C相同时,shading='flat'从3.3开始就不推荐使用。
使用X和Y指定四边形的角点,或传递shading='auto'、'nearest'或'gouraud',
或设置rcParams['pcolor.着色'].
根据提示,修改案例代码为如下警告消失:
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
data = make_blobs(n_samples=200, centers=2, random_state=8)
X,y = data
clf = KNeighborsClassifier()
clf.fit(X,y)
x_min, x_max = X[:,0].min() - 1, X[:,0].max() + 1
y_min, y_max = X[:,1].min() - 1, X[:,1].max() + 1
xx,yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.pcolormesh(xx, yy, Z, shading='auto', cmap=plt.cm.Pastel1)
plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.spring, edgecolor='k')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier : KNN")
plt.scatter(6.75,4.82,marker='*',c='red',s=200)
plt.show()
再次验证预测结果
案例:
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
data = make_blobs(n_samples=200, centers=2, random_state=8)
X,y = data
clf = KNeighborsClassifier()
clf.fit(X,y)
x_min, x_max = X[:,0].min() - 1, X[:,0].max() + 1
y_min, y_max = X[:,1].min() - 1, X[:,1].max() + 1
xx,yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.pcolormesh(xx, yy, Z, shading='auto', cmap=plt.cm.Pastel1)
plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.spring, edgecolor='k')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier : KNN")
plt.scatter(6.75,4.82,marker='*',c='red',s=200)
# plt.show()
print('代码运行结果:')
print('新数据点的分类是:',clf.predict([[6.75, 4.82]]))
输入案例代码,点击运行,输出如下
可以看到模型把测试点分类到1类(位于灰色区域,和黄色点为同一类。0代表粉色分类,1 代表灰色分类),预测结果正确
生成用于多远分类任务所用的训练集,把数据类型增加到5个,把样本量增加到500个
案例:
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
# 生成测试数据,n_samples指定总样本数为500,centers指定类别个数,random_state保证数据可重现
data2 = make_blobs(n_samples=500, centers=5, random_state=8)
X2,y2 = data2
plt.scatter(X2[:,0], X2[:,1], c=y2, cmap=plt.cm.spring, edgecolor='k')
plt.show()
输入案例代码,点击运行,输出如下
可以看到生成了5种类别的训练数据集,值得注意的是有两类数据重叠,难度会大一些
用训练数据集训练模型
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
data2 = make_blobs(n_samples=500, centers=5, random_state=8)
X2,y2 = data2
clf = KNeighborsClassifier()
clf.fit(X2, y2)
x_min, x_max = X2[:,0].min()-1, X2[:,0].max()+1
y_min, y_max = X2[:,1].min()-1, X2[:,1].max()+1
xx, yy = np.meshgrid(np.arange(x_min, x_max,.02),np.arange(y_min, y_max,.02))
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.pcolormesh(xx, yy, Z, shading='auto', cmap=plt.cm.Pastel1)
plt.scatter(X2[:,0],X2[:,1], c=y2, cmap=plt.cm.spring, edgecolor='k')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier:KNN")
plt.show()
可以看到,大部分已经分到正确的区域,少部分重合部分的数据未分到正确的类别
案例:
print('模型正确率:{:.2f}'.format(clf.score(X2,y2)))
输入案例代码,点击运行,输出如下
可以看到模型的正确率为0.96
案例
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
X, y = make_regression(n_features=1, n_informative=1, noise=50, random_state=8)
plt.scatter(X, y, c='orange', edgecolor='k')
plt.show()
使用上面生成的数据训练一个模型
案例:
from sklearn.neighbors import KNeighborsRegressor
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
X, y = make_regression(n_features=1, n_informative=1, noise=50, random_state=8)
reg = KNeighborsRegressor()
reg.fit(X, y)
z = np.linspace(-3, 3, 200).reshape(-1, 1)
plt.scatter(X, y, c='orange', edgecolor='k')
plt.plot(z, reg.predict(z), c='k', linewidth=3)
plt.title('KNN Regressor')
plt.show()
案例:
print('模型评分:{:.2f}'.format(reg.score(X, y)))
输入案例代码,点击运行,输出如下
评分只有0.77,默认情况下k=5,尝试减少k的数量到2
案例:
from sklearn.neighbors import KNeighborsRegressor
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
X, y = make_regression(n_features=1, n_informative=1, noise=50, random_state=8)
reg = KNeighborsRegressor(n_neighbors=2)
reg.fit(X, y)
z = np.linspace(-3, 3, 200).reshape(-1, 1)
plt.scatter(X, y, c='orange', edgecolor='k')
plt.plot(z, reg.predict(z), c='k', linewidth=3)
plt.title('KNN Regressor')
plt.show()
输入案例代码,点击运行,输出如下
对比之前的曲线,发现稍微好一些了
案例:
print('模型评分:{:.2f}'.format(reg.score(X, y)))
输入案例代码,点击运行,输出如下
看结果,调整k=2后拟合结果比之前高了一些
使用scikit-learn内置的酒数据集来进行学习,在Jupyter Notebook中新建一个Python3
案例:
from sklearn.datasets import load_wine
wine_dataset = load_wine()
print("红酒数据集中的键:{}".format(wine_dataset.keys()))
输入案例代码,点击运行,输出如下
数据集包括数据、目标分类、目标分类名称、数据描述、特征名称
案例:
print('数据概况:{}'.format(wine_dataset['data'].shape))
输入案例代码,点击运行,输出如下
共有178个样本,每个样本有13个特征
案例:
print('数据描述:{}'.format(wine_dataset['DESCR']))
输入案例代码,点击运行,输出如下
178份数据分为3类,从1~3类分别有59、71、48份数据
13个特征分别是酒精含量、苹果酸、灰烬含量、碱含量、镁含量、总酚含量、黄酮素含量、非黄酮酚含量、原花青素含量、色彩强度、色调、稀释葡萄酒的OD280/OD315、脯氨酸
使用scikit-learn的train_test_split函数,将数据集75%作为训练集25%作为测试集
案例:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(wine_dataset['data'], wine_dataset['target'], random_state=0)
print('X_train : {}'.format(X_train.shape))
print('X_test : {}'.format(X_test.shape))
print('y_train : {}'.format(y_train.shape))
print('y_test : {}'.format(y_test.shape))
输入案例代码,点击运行,输出如下
数据已经分为训练集和测试集。训练集样本数和标签的数量为133,测试集样本数和标签的数量为45
案例:
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 1)
knn.fit(X_train, y_train)
print('测试数据集得分:{:.2f}'.format(knn.score(X_test, y_test)))
输入案例代码,点击运行,输出如下
这里看到训练出的模型得分为0.76
import numpy as np
X_new = np.array([[13.2, 2.77, 2.51, 18.5, 96.6, 1.04, 2.55, 0.57, 1.47, 6.2, 1.05, 3.33, 820]])
prediction = knn.predict(X_new)
print('预测红酒的分类为:{}'.format(wine_dataset['target_names'][prediction]))
K近邻算法的劣势:
当前的应用场景中,K近邻算法很少使用,用的较多的是广义线性模型。