kNN算法應用於iris數據集
K最近鄰,顧名思義,就是K個最鄰近的樣本的意思。如果一個樣本的最接近的K個鄰居里,絕大多數屬於某個類別,則該樣本也屬於這個類別,並具有這個類別上樣本的特性。KNN算法有兩個關鍵點要注意。第一個關鍵點是K的確定,選擇一個最佳的K值取決於數據分布情況。總的來說,較小的K值能使模型更不容易受樣本不均衡的影響,而較大的K值能夠減小噪聲的影響。第二個關鍵點是最近鄰的定義,也就是距離定義,常用的有歐式距離、余弦距離等,具體采用哪種距離定義要根據實際的數據和業務確定。由於KNN 在確定分類決策上只依據最鄰近的幾個樣本的類別來決定待分樣本所屬的類別,它只與極少量的相鄰樣本有關,因此它是非線性的,對於類域的交叉或重疊較多的待分樣本集來說,KNN方法非常適用。
#選擇iris數據集為例,iris共有150條1數據
head(iris)

#對iris進行歸一化處理,scale歸一化的公式為(x-mean(x))/sqrt(var(x))
iris_s=data.frame(scale(iris[,1:4])) iris_s<-cbind(iris_s,iris[,5])
#對iris數據集隨機選擇其中的前100條數據作為已知分類的樣本集(訓練集)
sample.list<-sample(1:150,size=100) iris.known<-iris_s[sample.list,]
#剩余50條數據作為位置分類的樣本集(測試集)
iris.unknown<-iris_s[-sample.list,]
#對測試集中的每個樣本計算其與已知樣本的距離,因為已經歸一化,此處直接使用歐氏距離
length.known<-nrow(iris.known)
length.unknown<-nrow(iris.unknown)
for(i in 1:length.unknown){
#dis記錄每個已知類別樣本的距離及樣本的類別
dis_to_known<-data.frame(dis=rep(0,length.known))
for(j in 1:length.known){
#計算距離
dis_to_known[j,1]<-dist(rbind(iris.unknown[i,1:4],iris.known[j,1:4]),method = "euclidean")
#保存已知樣本的類別
dis_to_known[j,2]<-iris.known[j,5]
names(dis_to_known)[2]="Species"
}
#按距離從小到大排序
dis_to_known<-dis_to_known[order(dis_to_known$dis),]
#kNN算法中的k定義了最鄰近的k個已知數據的樣本
k<-5
#按因子進行計數
type_freq<-as.data.frame(table(dis_to_known[1:k,]$Species))
#按計數值進行排序
type_freq<-type_freq[order(-type_freq$Freq),]
#記錄頻數最大的類型
iris.unknown[i,6]<-type_freq[1,1]
}
names(iris.unknown)[6]="Species.pre"
#輸出分類結果
iris.unknown[,5:6]

案例1:股票市場數據的應用
library(ISLR) names(Smarket)

dim(Smarket)

summary(Smarket) pairs(Smarket) #pairs()函數用於返回一個繪圖矩陣,由每個 DataFrame 對應的散點圖組成。

cor(Smarket[,-9]) #cor ()函數可以計算所有預測變最兩兩之間相關系數的矩陣。

解釋:相關的是 Year和Volume ,通過畫圖可以觀察到 Volume 隨時間一直增長,也就是說從 2001 年至 2005 年平均每日股票成交盤在增長。
attach(Smarket) plot(Volume)

library(class) train.X=cbind(Lag1,Lag2)[train,] #包含與訓練數據相關的預測變量矩陣 test.X=cbind(Lag1,Lag2)[!train,] #包含與預測數據相關的預測變量矩陣 train.Direction=Direction[train] #包含訓練觀測類標簽的向量 set.seed(1) knn.pred=knn(train.X,test.X,train.Direction,k=1) table(knn.pred,Direction.2005)

(83+43)/252

#K=1時的結果不理想,只有 50% 的觀測得到正確的預測,這可能因為 K= 1的模型過於光滑,使用 K=3 重復上述實驗。
knn.pred=knn(train.X,test.X,train.Direction,k=3) table(knn.pred,Direction.2005)

mean(knn.pred==Direction.2005) #結果略有改觀

案例2:大篷車保險數據的一個應用
對 ISLR庫中的 Caravan (大篷車)數據集運用 KNN 方法。該數據集包括 85 個預測變量,測量了 5822 人的人口特征。響應變最為 Purchase (購買狀態) .表示一個人是否會購買大篷車保險險種。在該數據集中,只有 6% 的人購買了大篷車保險。
dim(Caravan)

attach(Caravan) summary(Purchase)

348/5822

standardized.X=scale(Caravan[,-86]) #標准化數據,第86列為Purchase狀態,不適合標准化 var(Caravan[,1])

var(Caravan[,2])

var(standardized.X[,1]) #命令standardized.X 將每列均值為0,標准差置為 1 。

var(standardized.X[,2])

test=1:1000 train.X=standardized.X[-test,] #訓練集 test.X=standardized.X[test,] #測試集,樣本量為1000 train.Y=Purchase[-test] #訓練集標簽 test.Y=Purchase[test] #測試集標簽 set.seed(1) knn.pred=knn(train.X,test.X,train.Y,k=1) mean(test.Y!=knn.pred) #KNN 錯誤率在 1000 個部試觀測下略低於 12%

mean(test.Y!="No")

table(knn.pred,test.Y)

9/(68+9)

結果分析:事實表明 K=1在被預測有購買傾向性的客戶上 KNN 模型比隨機預測效果好得多,77 名這樣的客戶,其中9名,也就是 1 1. 7% 事實上購買了保險。這個結果的概率是隨機猜測得到結果概率的兩倍。
knn.pred=knn(train.X,test.X,train.Y,k=3) table(knn.pred,test.Y)

5/26

knn.pred=knn(train.X,test.X,train.Y,k=5) table(knn.pred,test.Y)

4/15

結果分析:K=3 時,成功率增加至 19% ,而當 K=5 時,成功率變為 26.7% ,這比隨機猜想所得成功率的四倍還多。這似乎表明 KNN 在一個復雜數據集中可以發現一些真實的模式。
#案例3:鳶尾花數據集
library("class")
train.idx<-sample ( 1:nrow (iris) , 100)
iris.train <-iris[train.idx, ]
iris.test<- iris[-train.idx,]
resknn <- knn (train = subset (iris.train,select =-Species), test = subset(iris.test,select=-Species) , cl=iris.train$Species, k=2)
table(iris.test$Species, resknn,dnn=c("Actual","predicted"))

