KNN最近邻分类的R语言实现

版权声明:苍生苦难,不知伊于胡底 https://blog.csdn.net/qq_40527086/article/details/85121724

思想简介

KNN(k-Nearest Neighbor)是一种懒惰机器学习算法(lazy learning)。所谓k最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。简而言之,它在拿到训练集数据时并不急着去建模,而是在拿到测试集数据后,再到训练集数据中去寻找该测试样本最近的“邻居”,即距离最近的K个训练样本,依照训练样本数据的所属类别,加权或不加权地得出测试数据的类别。

最近邻K的选取

K的选取 偏差 方差
较小 减小 增大
较大 增大 减小

算法流程简述

  1. 数据预处理
  2. 划分训练集和测试集,训练集已知标签分类,测试集未知
  3. 设定参数,如k
  4. 维护一个大小为k的的按距离由大到小的优先级队列,用于存储最近邻训练元组。随机从训练元组中选取k个元组作为初始的最近邻元组,分别计算测试元组到这k个元组的距离,将训练元组标号和距离存入优先级队列
  5. 遍历训练元组集,计算当前训练元组与测试元组的距离,将所得距离L 与优先级队列中的最大距离Lmax
  6. 进行比较。若L>=Lmax,则舍弃该元组,遍历下一个元组。若L < Lmax,删除优先级队列中最大距离的元组,将当前训练元组存入优先级队列。
  7. 遍历完毕,计算优先级队列中k 个元组的多数类,并将其作为测试元组的类别。
  8. 测试元组集测试完毕后计算误差率,继续设定不同的k值重新进行训练,最后取误差率最小的k 值。

算法优缺点

优点:

  • 简单,易于理解,易于实现,无需估计参数,无需训练
  • 适合对稀有事件进行分类
  • 特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好

缺点:

  • 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。 该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果
  • 计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点
  • 可理解性差,无法给出像决策树那样的规则

R语言中的运用

函数参数及其解释

使用包(kknn)

kknn(formula = formula(train), 
train, 
test, 
na.action = na.omit(),
k = 7, 
distance = 2,
kernel = "optimal", 
ykernel = NULL, 
scale=TRUE, 
contrasts = c('unordered' = "contr.dummy", 
ordered = "contr.ordinal"))

参数解释

参数名 解释 举例 例子含义
formula A formula object.(一种Y~X)即因变量和自变量对应 formula=Purchase~. 以购买与否为响应变量,数据集中其他所有变量为因变量进行预测分类
train Matrix or data frame of training set cases.(训练集) train=Caravan.train 选定训练集为Caravan.train,当然需要提前划分训练集和测试集
test Matrix or data frame of test set cases.(测试集) 同上 同上
na.action A function which indicates what should happen when the data contain ’NA’s.(对缺失值的处理)
k Number of neighbors considered.(K近邻个数的选取) k=1 每次只选最近的一个邻居
distance Parameter of Minkowski distance.名科夫斯基距离参数的设定 distance=1
kernel Kernel to use. Possible choices are “rectangular” (which is standard unweighted knn), “triangular”, “epanechnikov” (or beta(2,2)), “biweight” (or beta(3,3)), “triweight” (orbeta(4,4)), “cos”, “inv”, “gaussian”, “rank” and “optimal”. kernel = “triangular” 使用 beta(2,2)核
ykernel Window width of an y-kernel, especially for prediction of ordinal classes. y核的窗口宽度,尤其用于预测序数类。
scale Logical, scale variable to have equal sd. 逻辑上,尺度变量具有相等的sd
contrasts A vector containing the ’unordered’ and ’ordered’ contrasts to use 一个包含“无序”和“有序”对比度的向量

实例

使用Caraven(大篷车)数据集。
(a)建立一个由1000个观测值构成的训练集,用余下的观测值构建测试集。
(b)将变量Purchase(购买量)作为响应变量,其余变量作为预测变量,建立KNN模型进行预测。如果估计出的购买可能大于20%,则预测为购买。建立一个混淆矩阵。有多少被预测为购买的人真的进行了购买?
代码如下:

rm(list=ls()) # 移除工作区变量
library(kknn) # kknn包中含有knn算法
library(ISLR) # 含有Caravan数据集
#attach(Caravan) 
var0 = c('PVRAAUT','PZEILPL','AVRAAUT','AZEILPL')
Caravan = Caravan[,!names(Caravan) %in% var0] # 去除无用变量
purchase = ifelse(Purchase=="No",0,1) # 将响应变量置为0/1
Caravan = data.frame(Caravan,purchase)
# 划分训练集测试集
set.seed(1)
train.index = sample(1:nrow(Caravan),1000)
Caravan.train = Caravan[train.index,]
Caravan.test = Caravan[-train.index,]
# 执行算法
Caravan.kknn = kknn(purchase~.,train=Caravan.train,test=Caravan.test,
                    distance = 1, kernel = "triangular")
# 得到测试集的预测值
fit = fitted(Caravan.kknn)
fit = ifelse(fit>=0.2,1,0)
# 打印混淆矩阵
print(table(fit,purchase[-train.index]))

得到混淆矩阵如下:

fit    0    1
  0 4319  183
  1  208  112

预测准确率:(4319+112)/(4319+112+183+208)= 0.9189133
其中有112人被预测为购买的人真的进行了购买。

猜你喜欢

转载自blog.csdn.net/qq_40527086/article/details/85121724