K近邻算法
原理:通过计算新数据和训练数据特征值之间的距离,然后选取K个距离最近的邻居进行分类判断(投票法)或者回归。
特点:不具有显示的学习过程,直接预测。实际上式利用训练数据集对特征向量空间进行划分,并且作为其分类的“模型”。
k值选择:
- k=1,称为最近邻算法。此时将训练集中与测试样本最近的点类别作为测试样本的分类。
- k较小,用较小的邻域中的训练实例进行预测。偏差较小,方差较大,对近邻的实例点较为敏感,易受噪声影响,导致过拟合。
- k较大,用较大的邻域中的训练实例进行预测。偏差较大,方差较小。
- 一般k选取较小的数值,采用交叉验证法来选取最优的k值。
距离度量:
- 非数值型数据需转换成数值型,便于计算距离;
- 避免不同特征的取值范围影响距离计算,需对特征数据采取归一化处理;
- 不同的距离度量所确定的最近林点不同,一般情况下,选欧式距离作为距离度量。
分类决策规则:
多数表决。也可基于距离的远近进行加权投票。
PYTHON实战
导入包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import neighbors, datasets,cross_validation
加载数据
def load_classification_data():
''' 加载分类模型使用的数据集。 :return: 一个元组,依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记 '''
digits=datasets.load_digits() # 使用 scikit-learn 自带的手写识别数据集 Digit Dataset
X_train=digits.data
y_train=digits.target
return cross_validation.train_test_split(X_train, y_train,test_size=0.25,random_state=0,stratify=y_train) # 进行分层采样拆分,测试集大小占 1/4
定义knn分类器
def test_KNeighborsClassifier(*data):
''' 测试 KNeighborsClassifier 的用法 :param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记 :return: None '''
X_train,X_test,y_train,y_test=data
clf=neighbors.KNeighborsClassifier()
clf.fit(X_train,y_train)
print("Training Score:%f"%clf.score(X_train,y_train))
print("Testing Score:%f"%clf.score(X_test,y_test))
参数优化
def test_KNeighborsClassifier_k_w(*data):
''' 测试 KNeighborsClassifier 中 n_neighbors 和 weights 参数的影响 :param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记 :return: None '''
X_train,X_test,y_train,y_test=data
Ks=np.linspace(1,y_train.size,num=100,endpoint=False,dtype='int')
weights=['uniform','distance']
fig=plt.figure()
ax=fig.add_subplot(1,1,1) ### 绘制不同 weights 下, 预测得分随 n_neighbors 的曲线
for weight in weights:
training_scores=[]
testing_scores=[]
for K in Ks:
clf=neighbors.KNeighborsClassifier(weights=weight,n_neighbors=K)
clf.fit(X_train,y_train)
testing_scores.append(clf.score(X_test,y_test))
training_scores.append(clf.score(X_train,y_train))
ax.plot(Ks,testing_scores,label="testing score:weight=%s"%weight)
ax.plot(Ks,training_scores,label="training score:weight=%s"%weight)
ax.legend(loc='best')
ax.set_xlabel("K")
ax.set_ylabel("score")
ax.set_ylim(0,1.05)
ax.set_title("KNeighborsClassifier")
plt.show()
def test_KNeighborsClassifier_k_p(*data):
''' 测试 KNeighborsClassifier 中 n_neighbors 和 p 参数的影响 :param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记 :return: None '''
X_train,X_test,y_train,y_test=data
Ks=np.linspace(1,y_train.size,endpoint=False,dtype='int')
Ps=[1,2,10]
fig=plt.figure()
ax=fig.add_subplot(1,1,1) ### 绘制不同 p 下, 预测得分随 n_neighbors 的曲线
for P in Ps:
training_scores=[]
testing_scores=[]
for K in Ks:
clf=neighbors.KNeighborsClassifier(p=P,n_neighbors=K)
clf.fit(X_train,y_train)
testing_scores.append(clf.score(X_test,y_test))
training_scores.append(clf.score(X_train,y_train))
ax.plot(Ks,testing_scores,label="testing score:p=%d"%P)
ax.plot(Ks,training_scores,label="training score:p=%d"%P)
ax.legend(loc='best')
ax.set_xlabel("K")
ax.set_ylabel("score")
ax.set_ylim(0,1.05)
ax.set_title("KNeighborsClassifier")
plt.show()
运行代码
if __name__=='__main__':
X_train,X_test,y_train,y_test=load_classification_data() # 获取分类模型的数据集
test_KNeighborsClassifier(X_train,X_test,y_train,y_test) # 调用 test_KNeighborsClassifier
test_KNeighborsClassifier_k_w(X_train,X_test,y_train,y_test)# 调用 test_KNeighborsClassifier_k_w
test_KNeighborsClassifier_k_p(X_train,X_test,y_train,y_test)# 调用 test_KNeighborsClassifier_k_p
R实战
目标:采用rpart包中的car.test.frame数据,取最后10个观测值为测试集,其余为训练集。以Mileage(定量变量)为因变量,以定量变量Price、Weight、Disp. 、HP为自变量,在训练集中找出最优的参数设置值(采用留一交叉验证,邻居个数在48个及以内),并采用最优的参数值在测试集中预测,给出预测的效果评价。
代码:
library(rpart)
data(car.test.frame)
head(car.test.frame)
alldata<-cbind(car.test.frame[,4],car.test.frame[,c(1,6:8)])
names(alldata)[1] <- "y"
dim(alldata)
str(alldata)
library(VIM)
aggr(alldata)
train<-alldata[1:50,]
test<-alldata[51:60,]
(car_fit.knn<- train.kknn(y~ .,train,scale=T, kmax =48, kernel =
c("rectangular","triangular","epanechnikov","biweight",
"triweight","cos","inv","gaussi","rank","optimal"),distance = 2))
plot(car_fit.knn,main="最优参数选择")
test.fit.knn<- kknn(y~.,train,test[,-1],k=2,scale=T,distance=2,kernel= "inv")
a<-test.fit.knn$fitted.values
b<-test$y
c<-mean(test$y)
(test.knn.RMSE<-sqrt(mean((a-b)^2)))
(test.knn.RRSE<-1-sum((a-b)^2)/sum((b-c)^2))
(test.knn.MAE<-mean(abs(a-b)))
(test.knn.RAE<-sum(abs(a-b))/sum(abs(b-c)))