1. 程式人生 > >KNN最近鄰分類的R語言實現

KNN最近鄰分類的R語言實現

思想簡介

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人被預測為購買的人真的進行了購買。