偶然之間看到崎淳,很多R包中都有knn算法的應(yīng)用,他們有什么不同之處嗎巧勤?到底應(yīng)該選擇哪個包來實現(xiàn)knn呢?
為了解決這些疑惑旅挤,我對class包踢关、DMwR包和kknn包中的knn實現(xiàn)做了一個初步整理,結(jié)果如下(算法的原理粘茄、流程签舞、優(yōu)缺點(diǎn)就不寫了,很多現(xiàn)成的資料)柒瓣。
1.說明
以下涉及到的數(shù)據(jù)來自R中的鳶尾花數(shù)據(jù)集iris儒搭,根據(jù)花的種類平均分為訓(xùn)練集和測試集。
2.R包中的knn實現(xiàn)
R中有許多包都可以實現(xiàn)knn算法芙贫,以下以class包搂鲫、DMwR包和kknn包為例進(jìn)行說明。
2.1 class包中的knn
knn()函數(shù)的語法和參數(shù)如下:
knn(train, test, cl, k = 1, l = 0, prob = FALSE, use.all = TRUE)
train:指定訓(xùn)練樣本集
test :指定測試樣本集
cl :指定訓(xùn)練樣本集中的分類變量
k :指定最鄰近的k個已知分類樣本點(diǎn)磺平,默認(rèn)為1
l :指定待判樣本點(diǎn)屬于某類的最少已知分類樣本數(shù)魂仍,默認(rèn)為0
prob:設(shè)為TRUE時,可以得到待判樣本點(diǎn)屬于某類的概率拣挪,默認(rèn)為FALSE
use.all:控制節(jié)點(diǎn)的處理辦法擦酌,即如果有多個第K近的點(diǎn)與待判樣本點(diǎn)的距離相等,默認(rèn)情況下將這些點(diǎn)都納入判別樣本點(diǎn)菠劝,當(dāng)該參數(shù)設(shè)為FALSE時赊舶,則隨機(jī)挑選一個樣本點(diǎn)作為第K近的判別點(diǎn)
實現(xiàn)代碼:
> # z-score數(shù)據(jù)標(biāo)準(zhǔn)化
> iris_scale <- scale(iris[-5])
> train <- iris_scale[c(1:25,50:75,100:125),] #訓(xùn)練集
> test <- iris_scale[c(26:49,76:99,126:150),] #測試集
> train_lab <- iris[c(1:25,50:75,100:125),5]
> test_lab <- iris[c(26:49,76:99,126:150),5]
> pre <- knn(train=train,test=test,cl=train_lab,k=round(sqrt(dim(train)[1])),prob = F)
> table(pre,test_lab)
test_lab
pre setosa versicolor virginica
setosa 24 0 0
versicolor 0 24 3
virginica 0 0 22
2.2 DMwR包中的KNN
KNN()函數(shù)的語法和參數(shù)如下:
kNN(form, train, test, norm = T, norm.stats = NULL, ...)
form:分類模型
train:指定訓(xùn)練樣本集
test:指定測試樣本集
norm:布爾值,指示是否在KNN預(yù)測前將數(shù)據(jù)標(biāo)準(zhǔn)化赶诊,默認(rèn)為TRUE
norm.stats:默認(rèn)FALSE笼平,采用scale()進(jìn)行標(biāo)準(zhǔn)化,也可提供其他標(biāo)準(zhǔn)化方法(不太懂)
實現(xiàn)代碼:
> train<-iris[c(1:25,50:75,100:125),] #訓(xùn)練集
> test<-iris[c(26:49,76:99,126:150),] #測試集
> pre2 <- kNN(Species~.,train,test,norm=T,k=round(sqrt(dim(train)[1])))
> table(pre2,test$Species)
pre2 setosa versicolor virginica
setosa 24 0 0
versicolor 0 24 3
virginica 0 0 22
2.3 kknn包中的kknn
kknn()函數(shù)的語法和參數(shù)如下:
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一個回歸模型:分類變量~特征變量舔痪;
train指定訓(xùn)練樣本集寓调;
test指定測試樣本集;
na.action缺失值處理锄码,默認(rèn)為去掉缺失值捶牢;
k近鄰數(shù)值選擇,默認(rèn)為7巍耗;
distance閔可夫斯基距離參數(shù)秋麸,p=2時為歐氏距離;
其他參數(shù)略
實現(xiàn)代碼:
> train<-iris[c(1:25,50:75,100:125),] #訓(xùn)練集
> test<-iris[c(26:49,76:99,126:150),] #測試集
> # 調(diào)用kknn
> pre3 <- kknn(Species~., train, test, distance = 1, kernel = "triangular")
> # 獲取fitted.values
> fit <- fitted(pre3)
> table(fit,test$Species)
fit setosa versicolor virginica
setosa 24 0 0
versicolor 0 22 4
virginica 0 2 21
3.knn算法中K值的確定
參考分類算法之knn
knn為k近鄰算法炬太,需要解決的一個問題是選擇合適的k值灸蟆,k值過小或過大都會影響模型的準(zhǔn)確性,一般考慮將k值設(shè)為3~10,或是將k值設(shè)為訓(xùn)練集樣本數(shù)量的平方根炒考。還有一種選擇k值的方法是結(jié)合訓(xùn)練集和測試集可缚,循環(huán)k值,直到挑選出使測試集的誤差率最小的k值斋枢。
以class包knn舉例說明帘靡,尋找誤差率最低的K值:
> for(i in 1:round(sqrt(dim(train)[1]))) {
+ pre_result <- knn(train=train,test=test,cl=train_lab,k=i)
+ Freq <- table(pre_result,test_lab)
+ print(1-sum(diag(Freq))/sum(Freq)) #誤差率
+ }
[1] 0.08219178
[1] 0.06849315
[1] 0.08219178
[1] 0.06849315
[1] 0.05479452
[1] 0.06849315
[1] 0.05479452
[1] 0.09589041
[1] 0.04109589
根據(jù)結(jié)果,k=9時誤差率最低瓤帚,和訓(xùn)練集樣本數(shù)量的平方根一致描姚。但是如果樣本數(shù)量過大,以上的K值確定方法就比較困難了戈次,也正驗證了knn不適合大樣本數(shù)據(jù)的說法轩勘。
4.總結(jié)
總體來看,我認(rèn)為三種實現(xiàn)knn的函數(shù)區(qū)別不大怯邪,只在參數(shù)上有一些差別绊寻,可以根據(jù)個人喜好選擇實現(xiàn)knn的函數(shù)。
需要注意的點(diǎn):
數(shù)據(jù)標(biāo)準(zhǔn)化:knn()函數(shù)在調(diào)用前需標(biāo)準(zhǔn)化數(shù)據(jù)悬秉,其他2個函數(shù)默認(rèn)調(diào)用時進(jìn)行標(biāo)準(zhǔn)化澄步;
缺失值:k近鄰以距離為依據(jù),因此數(shù)據(jù)中不能含有缺失值和泌;
k值大写甯住:k過小,噪聲對分類的影響就會變得非常大允跑,K過大王凑,很容易誤分類搪柑;
距離計算:上面算法默認(rèn)歐式距離聋丝,如果有時間,可以看看不同距離計算方法的效果工碾。
補(bǔ)充的點(diǎn):
VIM包中也有KNN()函數(shù)弱睦,是用knn算法來填補(bǔ)缺失值;
DMwR包中的knnImputation也可以用來填補(bǔ)缺失值(均值渊额、均值權(quán)重)