1.KNN原理
KNN的算法原理,可以简单如下描述:一个数据集中存在多个已有标签的样本值,这些样本值共有的n个特征构成了一个多维空间N。当有一个需要预测/分类的样本x出现,我们把这个x放到多维空间n中,找到离其距离最近的k个样本,并将这些样本称为最近邻(nearest
neighbour)。对这k个最近邻,查看他们的标签都属于何种类别,根据”少数服从多数,一点算一票”的原则进行判断,数量最多标签类别就是x的标签类别。其中涉及到的原理是“越相近越相似”,这也是KNN的基本假设。
若数据集只有两个特征,则针对于数据集的描述可用二维平面空间图来表示。如下图,二位平面空间的横坐标是特征1,纵坐标是特征2,每个样本点的分类(正或负)是该组样本的标签。图中给出了位于平面中心的,需要分类的数据点x,并用绿色分别标注了k为1,2,3时的最近邻状况。在图a中,x的1-最近邻是一个负例,因此x被指派到负类。图c中,3-最近邻中包括两个正例和一个负例,根据“少数服从多数原则”,点x被指派到正类。在最近邻中正例和负例个数相同的情况下(图b),算法将随机选择一个类标号来分类该点。
由上可知,KNN算法的实现步骤其实非常简单,假设现在我们有一个预测样本X,则判断X的分类的方法为:
- 计算X到所有训练集上的点的距离
- 按照距离递增次序对样本点进行排序
- 取前K个离X最近的点,查看他们的标签
- 对这K个点的标签加和,采取少数服从多数策略,占多数的标签则为点X的预测标签。
2. KNN在sklearn中的实现
- 导入需要的包
import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier #KNN分类器
from sklearn.datasets import load_breast_cancer #导入乳腺癌数据集
from sklearn.model_selection import train_test_split#切分训练集和测试集的包
import matplotlib.pyplot as plt
data = load_breast_cancer()#给数据赋名
X = data.data#特征
Y = data.target#标签(好瓜、坏瓜)
- 分测试集、训练集
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y #特征和标签
,test_size=0.3 #测试集所占的比例,默认是0.25
)#给特征和标签分训练集和测试集
- 建模
# 建立模型并评估模型
score = []
krange = range(1,20)#k取值
for i in krange:
clf = KNeighborsClassifier(n_neighbors=i)#对每一个不同的K取值建模
clf = clf.fit(Xtrain,Ytrain)#训练
score.append(clf.score(Xtest,Ytest))#记录每个模型的分数
plt.plot(krange,score);#绘制学习曲线
bestindex = krange[score.index(max(score))]-1#得到最优K
得到的学习曲线如下。
注意!这里该模型为惰性学习模型,其实不产生模型。
- 数据归一化
即将数据归一到[0,1],一般按列
from sklearn.preprocessing import MinMaxScaler as mms
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X_,y,test_size=0.3,random_state=420) #切分训练集和测试集
#random_state=420代表着一种随机方式
MMS = mms().fit(Xtrain) #这一步是在学习训练集,生成训练集上的极小值和极差
Xtest_ = MMS.transform(Xtest) #用训练集上的极小值和极差归一化测试集
Xtrain_ = MMS.transform(Xtrain) #用训练集上的极小值和极差归一化训练集
5.真的建模
#带交叉验证的学习曲线
score = []
var_ = []
krange = range(1,20)
for i in krange:
clf = KNeighborsClassifier(n_neighbors=i) #实例化KNN模型
cvresult = CVS(clf,X,y,cv=5) #把全部数据放入,进行5折交叉验证
score.append(cvresult.mean()) #把交叉验证的均值放入score
var_.append(cvresult.var()) #把交叉验证的方差放入var_
plt.plot(krange,score,color="k")
plt.plot(krange,np.array(score)+np.array(var_)*2,c="red",linestyle="--")
plt.plot(krange,np.array(score)-np.array(var_)*2,c="red",linestyle="--");#作图
bestindex = krange[score.index(max(score))]-1#得到最优K k=8
6.验证模型效果
#测试模型效果
clf = KNeighborsClassifier(n_neighbors=8).fit(Xtrain_,Ytrain) #实例化模型并进行训练
score = clf.score(Xtest_,Ytest) #对测试集进行训练并返回结果
score
#加上参数weights,改变一点一票原则为距离
score = []
var_ = []
krange = range(1,20)
for i in krange:
clf = KNeighborsClassifier(n_neighbors=i,weights="distance")#改变一点一票制规则,以距离作为惩罚因子
cvresult = CVS(clf,Xtrain_,Ytrain,cv=5)
score.append(cvresult.mean())
var_.append(cvresult.var())
plt.plot(krange,score,color="k")
plt.plot(krange,np.array(score)+np.array(var_)*2,c="red",linestyle="--")
plt.plot(krange,np.array(score)-np.array(var_)*2,c="red",linestyle="--")
bestindex = krange[score.index(max(score))]-1
print(bestindex)#k=8
print(score[bestindex])
#测试模型效果
clf = KNeighborsClassifier(n_neighbors=8
,weights="distance"
).fit(Xtrain_,Ytrain)
score = clf.score(Xtest_,Ytest)
score