1. 程式人生 > >《機器學習實戰》學習筆記——kNN演算法

《機器學習實戰》學習筆記——kNN演算法

《機器學習實戰》(MLiA)是一本介紹機器學習的書(的確是廢話),和其他書不同的地方在於它給出了python的實現程式碼,而其他的書籍重在解釋理論。我作為一名渣渣,理論就先放一放了。
MLiA的第一章主要介紹了一些概念、常識性的東西,所以不做介紹,這篇文章主要介紹k-近鄰演算法(kNN)。

kNN演算法的優點是精度高,對異常值(離群點)不敏感且不需要訓練;缺點是計算複雜度、空間複雜度高
kNN演算法的適用範圍是數值型和標稱型資料

kNN工作原理是:

存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每一資料與所屬分類的對應關係。輸人沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較,然後演算法提取樣本集中特徵最相似資料(最近鄰)的分類標籤。一般來說,我們只選擇樣本資料集中前k個最相似的資料,這就是k-近鄰演算法中k的出處,通常k是不大於20的整數。最後,選擇k個最相似資料中出現次數最多的分類,作為新資料的分類。

kNN演算法的演算法流程為:

(1).計算已知類別資料集中的點與當前點之間的距離;
(2).按照距離遞增次序排序;
(3).選取與當前點距離最小的k個點;
(4).確定前k個點所在類別的出現頻率;
(5).返回前k個點出現頻率最高的類別作為當前點的預測分類。

既然演算法流程已經明確,現在開始構造自己的演算法。《MLiA》中採用的是python來構造的演算法,原因是機器學習的演算法大都需要處理複雜的矩陣運算。鑑於自己的演算法處理的資料特徵維數並不多,矩陣運算較少,故寫了一個簡單的c++版本

/*  kNN.cpp
*   @author: Toroto
*/
#include <iostream> #include <math.h> using namespace std; #define DSSIZE 8 //訓練集大小 /* * 資料結構: * 包含兩個特徵:x, y * 及標記:label */ struct data{ float x, y; char label; }; data D[DSSIZE]; //訓練集 float dis[DSSIZE]; //距離陣列 //設定訓練集: //{(0,0),(0,0.1),(0,0.2)(0,0.3),(1,1.4),(1,1.5),(1,1.6),(1,1.7)}
void init(int x){ for (int i = 0; i < x; i++){ if (i < 4){ D[i].x = 0; D[i].label = 'A'; } else { D[i].x = 1; D[i].label = 'B'; } D[i].y = D[i].x + 0.1 * i; } }; /* * kNN演算法實現: * 引數: * x, y: 目標向量 k:最近鄰居的數目 * 返回值:待分類向量的標籤 */ char kNN(float x, float y, int k){ float temp; data tem; for (int i = 0; i < DSSIZE; i++){ //計算目標向量到各訓練資料的距離 dis[i] = pow(pow(x - D[i].x, 2) + pow(y - D[i].y, 2), 0.5); // cout << "i = " << i << "; distance = " << dis[i] << endl; } //排序 for (int i = 0; i < DSSIZE; i++){ for (int j = i; j < DSSIZE; j++){ if (dis[i] > dis[j]){ temp = dis[i]; dis[i] = dis[j]; dis[j] = temp; tem = D[i]; D[i] = D[j]; D[j] = tem; } } } /* for (int i = 0; i < DSSIZE; i++){ cout << D[i].x << " " << D[i].y << " " << D[i].label << " " << dis[i] << endl; } //*/ int label_A = 0, label_B = 0; //在給定數目的最近鄰居中選擇出現次數最多的鄰居 for (int i = 0; i < k; i++){ if (D[i].label == 'A') label_A++; else label_B++; } return label_A > label_B ? 'A' : 'B'; } int main(){ init(DSSIZE); int k; float x, y; char label; cout << "輸入x, y: "; cin >> x >> y; cout << "輸入k :"; cin >> k; label = kNN(x * 1.0, y * 1.0, k); cout << label << endl; return 0; };

這樣就完成了一個簡單版的kNN。

測試:
輸入0.1 ,0.2, k = 5,結果如下:
這裡寫圖片描述

輸入0.8, 1.2, k = 5, 結果如下:
這裡寫圖片描述