版权声明:苍生苦难,不知伊于胡底 https://blog.csdn.net/qq_40527086/article/details/85121724
思想简介
KNN(k-Nearest Neighbor)是一种懒惰机器学习算法(lazy learning)。所谓k最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。简而言之,它在拿到训练集数据时并不急着去建模,而是在拿到测试集数据后,再到训练集数据中去寻找该测试样本最近的“邻居”,即距离最近的K个训练样本,依照训练样本数据的所属类别,加权或不加权地得出测试数据的类别。
最近邻K的选取
K的选取 | 偏差 | 方差 |
---|---|---|
较小 | 减小 | 增大 |
较大 | 增大 | 减小 |
算法流程简述
- 数据预处理
- 划分训练集和测试集,训练集已知标签分类,测试集未知
- 设定参数,如k
- 维护一个大小为k的的按距离由大到小的优先级队列,用于存储最近邻训练元组。随机从训练元组中选取k个元组作为初始的最近邻元组,分别计算测试元组到这k个元组的距离,将训练元组标号和距离存入优先级队列
- 遍历训练元组集,计算当前训练元组与测试元组的距离,将所得距离L 与优先级队列中的最大距离Lmax
- 进行比较。若L>=Lmax,则舍弃该元组,遍历下一个元组。若L < Lmax,删除优先级队列中最大距离的元组,将当前训练元组存入优先级队列。
- 遍历完毕,计算优先级队列中k 个元组的多数类,并将其作为测试元组的类别。
- 测试元组集测试完毕后计算误差率,继续设定不同的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人被预测为购买的人真的进行了购买。