机器学习-有监督学习-分类算法-K最近邻法(KNN)-原理、Python和R应用

基本原理

首先放一张各大网站用烂的图

image.png

KNN的基本思想是比较简单的,就是假设我们有红色和蓝色得到数据点,然后我们新加入一个绿色点,根据绿色点最近的点是红色最多还是蓝色最多,这个用距离来衡量(常用的是欧式距离),来判断绿色的点属于哪个类别,而附近点的数目取多少(即k值大小)来判断,也是比较重要的,一般来说网上看到很多都是默认30或20以下,1~20左右,然后可以用k=1-20,分别拟合预测数据,来根据预测结果的好坏选择合适的k值。数据维度比较高的话,我们可以先用PCA降维,再用KNN分类预测。不过,如果你的训练集当中,某一类别的占比非常之高,这就可能造成很大的误差,这时候用KNN怎么优化预测结果大概率都是占比高的那个类别,因此在这种情况下,最好不要使用KNN。

R应用

R的话,做knn可以用class里面的knn函数,或者用caret里面的train函数,method设置成knn。因为caret可以直接进行交叉验证根据结果选择最佳k值,因此用其是比较方便的。

以下提供了两种包的实现方式,使用来自bioconductor的白血病基因表达数据集。

rm(list=ls())
library(leukemiasEset)  # 白血病数据集
library(class)  # 分类用的R包,包含一个简易的knn
library(caret)  # 同样包含knn,但功能更加全面强大,可以直接进行交叉验证
library(purrr)  # 方便手动写迭代函数,计算best k。


data("leukemiasEset")
exprdata <- exprs(leukemiasEset)
exprtrain <- as.data.frame(t(exprdata))
# PCA
pca.exprtrain <- prcomp(exprtrain, scale = TRUE)
cumvar <- round(cumsum(pca.exprtrain$sdev**2/sum(pca.exprtrain$sdev**2))*100, 2)
names(cumvar) <- paste("PC", 1:length(cumvar), sep="")
# Select the least number of principal components so that the sum of the cumulative proportion of variance is >95%
inputSet <- as.data.frame(pca.exprtrain$x[, 1:which(cumvar>95)[1]])
inputSet$type <- leukemiasEset$LeukemiaType
# KNN
# By manually dividing the data set into a training set and a test set by 7:3
train.ind <- sample(1:nrow(inputSet), 0.7*nrow(inputSet), replace = FALSE)
train <- inputSet[train.ind, ]
x.train <- train[, -ncol(train)]
y.train <- train$type
test <- inputSet[-train.ind, ]
x.test <- test[, -ncol(test)]
y.test <- test$type
bestknn <- function(kvalue){
    knn.predict <- knn(x.train, x.test, y.train, k=kvalue)
    confusion <- as.matrix(table(knn.predict, y.test))
    acc <- sum(diag(confusion))/sum(confusion)
}
knnacc <- map_dbl(1:20, bestknn)
# best k
which(knnacc == max(knnacc))[length(which(knnacc == max(knnacc)))]

# Run knn with caret and perform k-fold cross-validation
control <- trainControl(method="cv", number=5, savePredictions = TRUE, classProbs = TRUE)
set.seed(123)
knn.caret <- train(type~., data=train, method="knn", 
             metric="Accuracy", trControl=control, tuneGrid=expand.grid(k=seq(1, 20)))
knn.caret
knnPredict <- predict(knn.caret, newdata=test)
confusionMatrix(knnPredict, y.test)

Python应用

Python的话为了简便起见用了手写数字数据集来先降维后预测,同样也是分为7:3分割数据集的模式和交叉验证的模式,选取k=1-20,分别计算准确率,取使其最高的k。

from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score
import numpy as np


digits = datasets.load_digits()
# PCA
pca = PCA(digits.data.shape[1])
pca.fit(digits.data)
n_index = np.where(np.cumsum(pca.explained_variance_ratio_) > 0.95)[0][0]
digits_pca = pca.transform(digits.data)[:, 0:n_index+1]
x_train, x_test, y_train, y_test = train_test_split(
    digits_pca,
    digits.target,
    train_size=0.3,
    stratify=digits.target
)
# KNN with 7:3 training and test sets
acc1 = []
for k in range(1, 21):
    knn = KNeighborsClassifier(k)
    knn.fit(x_train, y_train)
    y_pred = knn.predict(x_test)
    acc1.append(accuracy_score(y_test, y_pred))
k_best1 = np.where(acc1==max(acc1))[0][0]+1
# KNN with cv
acc2 = []
for k in range(1, 21):
    knn = KNeighborsClassifier(k)
    scores = cross_val_score(knn, digits_pca, digits.target, cv=10, scoring="accuracy")
    acc2.append(scores.mean())
k_best2 = np.where(acc2==max(acc2))[0][0]+1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容