正在学习书上的内容,书上有部分代码没有给全,注解不详细,且随着版本原因出现的问题有所调整,所以写下学习笔记供大家参考。
K-NN
1.环境搭建
python版本最好是3.6.x及以上,我这里用的是3.7.1版本
安装有机器学习库sklearn、mglearn、matplotlib、numpy,若没有用pip安装
pip install sklearn
pip install mglearn
pip install matplotlib
pip install numpy
2.目前会出现的问题
因为是否维护和函数迭代的原因,会出现下面情况:
D:\Python37\lib\site-packages\sklearn\externals\six.py:31: FutureWarning: The module is deprecated in version 0.21 and will be removed in version 0.23 since we’ve dropped support for Python 2.7. Please rely on the official version of six (https://pypi.org/project/six/).
“(https://pypi.org/project/six/).”, FutureWarning)
D:\Python37\lib\site-packages\sklearn\externals\joblib_init_.py:15: FutureWarning: sklearn.externals.joblib is deprecated in 0.21 and will be removed in 0.23. Please import this functionality directly from joblib, which can be installed with: pip install joblib. If this warning is raised when loading pickled models, you may need to re-serialize those models with scikit-learn 0.21+.
warnings.warn(msg, category=FutureWarning)
D:\Python37\lib\site-packages\sklearn\utils\deprecation.py:87: FutureWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
warnings.warn(msg, category=FutureWarning)
- 目前不用理会,因为这里提示的是未来错误提示,也就是有的函数未来不会再使用或者维护,会出现进阶版的函数替换,到时候根据说明文档更改,或者直接pip install --upgrade XXX 下载最新版就可以了,现在不用处理。
我们再来理解一下几个基本概念:
- 泛化:一个模型能够对没见过的数据做出准确预测,就说模型能够从训练集泛化(generalize)到测试集
- 过拟合:模型过于复杂.过分关注训练集的细节,得到在训练集上表现过好,但不能泛化到新数据上.
- 欠拟合:模型过于简单,在训练集上的表现就很差
3.可视化将要处理的样本数据集
3.1 forge数据集
一个模拟的二分类数据集示例是forge数据集,它本身有两个特征。
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
#生成数据集
X,y=mglearn.datasets.make_forge()
#数据集绘图
#将输入X的第一列作为x轴,第二列作为y轴,输出y的作用是根据x轴与y轴坐标区别类别
mglearn.discrete_scatter(X[:,0],X[:,1],y)
#给图像加上图例,传入参数loc的值从0开始,设置图例的位置,感兴趣的可以自己试试
plt.legend(["Class 0","Class 1"],loc=0)
#定义x轴与y轴标签,这里分别对应两个特征
plt.xlabel("First feature")
plt.ylabel("Secong feature")
plt.show()
效果图:
3.2 wave数据集
wave数据集用来说明回归算法。它本身只有一个输入特征和一个连续的目标变量(或响应),后者是模型想要预测的对象。
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
#生成数据集
X,y=mglearn.datasets.make_wave(n_samples=40)#生成点的数
plt.plot(X,y,'o')
plt.ylim(-3,3)
plt.xlabel("Feature")
plt.ylabel("Target")
plt.show()
其中
plt.plot(X,y,‘o’)——>plt.plot(x,y,format_string,**kwargs)
传入参数format_string具体用法加下表:
字符 | 作用 | 字符 | 作用 |
---|---|---|---|
r | 红色 | ‘^’ | 上三角标记 |
g | 绿色 | ‘>’ | 右三角标记 |
b | 蓝色 | ‘<’ | 左三角标记 |
y | 黄色 | ‘1’ | 下花三角标记 |
k | 黑色 | ‘2’ | 上花三角标记 |
w | 白色 | ‘3’ | 左花三角标记 |
#000000 | RGB颜色 | ‘4’ | 右花三角标记 |
‘0.8’ | 灰度值字符串 | ‘s’ | 实心方形标记 |
‘_’ | 实线 | ‘p’ | 实心五角标记 |
‘_ _’ | 破折线 | ‘*’ | 星型标记 |
‘_.’ | 点画线 | ‘h’ | 竖六边形标记 |
‘:’ | 虚线 | ‘H’ | 横六边形标记 |
‘’ ‘’ | 无线条 | ‘+’ | 十字标记 |
‘.’ | 点标记 | ‘x’ | x标记 |
‘,’ | 像素标记 | ‘D’ | 菱形标记 |
‘o’ | 是实心圈标记 | ‘d’ | 瘦菱形标记 |
‘v’ | 倒三角标记 | ‘!’ | 垂直线标记 |
效果图:
4.k近邻
K-NN算法可以说是最简单的机器学习算法,构建模型只需要保存训练集就行。
想要对新数据做出预测,算法会在训练集中找到最近的数据点,也就是”最近邻“。
4.1 k近邻分类
这种分类方法应用在forge数据集上。
- 单一最近邻模型对forge数据集的预测结果
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
mglearn.plots.plot_knn_classification(n_neighbors=1)
plt.show()
效果图:
这里我们新加了3个五角星数据点,对于每个数据点,我们标记了训练集中与他最近的点。单一最近邻的预测算法就是那个点的标签。
- 3近邻模型对forge数据集的预测结果
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
mglearn.plots.plot_knn_classification(n_neighbors=3)
plt.show()
效果图:
我们将3个近邻中占多数的类别作为预测结果。
下面让我们看一下用scikit-learn来应用k近邻算法,运行代码如下:
import mglearn
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
X,y=mglearn.datasets.make_forge()#加载数据
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0)#分离数据
clf = KNeighborsClassifier(n_neighbors=3)#设置近邻数
clf.fit(X_train,y_train)#构建模型
print("Test set accuracy : {:.2f}".format(clf.score(X_test,y_test)))#评估模型
输出:
Test set accuracy : 0.86
4.2 分析k近邻分类(KNeighborsClassifier)
怎么分析呢,就是在xy平面上画出所有可能的测试点的预测结果,然后根据平面中的每一个点的所属类别对平面进行着色。这样可以查看决策边界,即算法对类别0和类别1的分界线。
运行代码如下:
import mglearn
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
#参数1和3分别代表子图的行数和列数,1行3个15x7大小的子图
fig,axes=plt.subplots(1,3,figsize=(10,3))#函数返回一个figure图像和子图ax的array列表。
#加载数据
X,y=mglearn.datasets.make_forge()
for n_neighbors,ax in zip([1,3,9],axes):
clf=KNeighborsClassifier(n_neighbors=n_neighbors).fit(X,y)#构建模型
#第一个参数为模型,第二个参数X为训练数据,fill参数设置为填充可见,eps参数决定图像的填充度,
#初始值为X的标准差/2,这里我们经过实验设置为0.4,ax参数为选择哪一个子图,
#alpha参数决定透明度,初始值为1
mglearn.plots.plot_2d_separator(clf,X,fill=True,eps=0.5,ax=ax,alpha=0.4)
mglearn.discrete_scatter(X[:,0],X[:,1],y,ax=ax)#ax参数就是选择哪个子图
ax.set_title("{} neighbor(s)".format(n_neighbors))
ax.set_xlabel("feature 0")
ax.set_ylabel("feature 1")
axes[0].legend(loc=3)#设置第一张子图的图例位置
plt.show()
效果图:
从图中我们可以看出,邻居的个数越多,决策边界越平滑。也就是说,更少的邻居对应更高的模型复杂度,更多的邻居对应更少的模型复杂度。
下面我们来研究一下模型复杂度与模型的泛化能力之间的关系。
我们在现实中的乳腺癌数据集上进行研究。
运行代码如下:
from 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()
#传入参数stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致,
#默认值为None,例如:cancer.target分两类:0和1,其中0有400个,1有600个,即数据分类的比例为4:6。
#则训练集和测试集中的数据分类比例将与cancer.target一致,也是4:6,
#结果就是在训练集中有300个0和450个1;测试集中有100个0和150个1
X_train,X_test,y_train,y_test=train_test_split(
cancer.data,cancer.target,stratify=cancer.target,random_state=0)#分离数据
training_accuracy=[]
test_accuracy=[]
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="trianing accuracy")
plt.plot(neighbors_settings,test_accuracy,'--',label="test accuracy")
plt.xlabel("n_neighbors")
plt.ylabel("Accuracy")
plt.legend()
plt.show()
效果图:
图像的x轴为邻居个数,y轴为精度。从图中可以发现,最佳性能在7到8的某处,邻居个数大约为7;最差性能约为88%的精度,这个结果也可以接受。
4.3 k近邻回归
k近邻算法还可以用于回归,这种回归算法应用在wave数据集上。
- 单一近邻回归对wave数据集的预测结果
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
mglearn.plots.plot_knn_regression(n_neighbors=1)
plt.show()
效果图:
同样,也可以用多个近邻进行回归,预测结果为这些邻居的平均值。
- 3个近邻回归对wave数据集的预测结果
运行代码如下:
import mglearn
import matplotlib.pyplot as plt
mglearn.plots.plot_knn_regression(n_neighbors=3)
plt.show()
效果图:
下面让我们看一下用于回归的k近邻算法在scikit-learn中的实现,运行代码如下:
import mglearn
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
X,y=mglearn.datasets.make_wave(n_samples=40)
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0)
reg=KNeighborsRegressor(n_neighbors=3)
reg.fit(X_train,y_train)
print("Test seet R^2: {:.2f}".format(reg.score(X_test,y_test)))
输出:
Test seet R^2: 0.83
对于回归问题,score方法返回的是R²分数,也叫决定系数,是回归模型预测的优度度量,位于0和1之间。R²等于0对应完美预测,R²等于0对应常数模型。
4.4 分析k近邻回归(KNeighborsRegressor)
对于我们的一位数据集,可以查看所有特征取值对应的预测结果。为了方便绘图,我们创建一个有许多点组成的测试数据集。运行代码如下:
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsRegressor
import matplotlib.pyplot as plt
import numpy as np
import mglearn
#读取数据
X,y=mglearn.datasets.make_wave(n_samples=40)
#分离数据
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0)
#创建图形
fig,axes=plt.subplots(1,3,figsize=(15,4))
#创建1000个数据点,在-3和3之间均匀分布
#构造等差数列 开始值,结束值,共几个数字,包含终止值,可以通过endpoint=False设置不包含终止值
#reshape(-1,1)将生成的等差数列列表转化为任意行一列的二维数组
#例如:line=np.arange(1,10).reshape((3,3)) 将1到9的列表,转化为3行3列的二维数组
line =np.linspace(-3,3,1000).reshape(-1,1)
for n_neighbors,ax in zip([1,3,9],axes):
reg = KNeighborsRegressor(n_neighbors=n_neighbors)
reg.fit(X_train,y_train)
#以line为x轴,以line预测的结果为y轴
ax.plot(line,reg.predict(line))
#参数c作用是改变标记颜色,为0.0~1.0,转化为RGB形式,为非必要传入参数,可不写
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("{} neighbor(s)\n train score:{:.2f} test score: {:.2f}".format(
n_neighbors,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")
效果图:
从图中可以看出,若是仅考虑一个邻居,则训练集中的每个点都对预测结果有显著影响,预测结果的图像经过所有数据点。这就导致了预测结果非常的不稳定。但是若考虑更多的邻居之后,预测结果变得更加平滑,但是对训练数据的拟合不是很好。
- k-NN的优点:模型容易理解,构建模型速度快
- k-NN的缺点:预测速度慢,不能处理具有许多特征的数据集
到这里k–NN算法就学完了。
- 完整代码都在文章里面全部可以运行
- 有不懂得地方和问题请留言
- 大家可以收藏一下以后学习可能用得到