在十大經典數據挖掘算法中,KNN算法算得上是最為簡單的一種。該算法是一種惰性學習法(lazy learner),與決策樹、朴素貝葉斯這些急切學習法(eager learner)有所區別。惰性學習法僅僅只是簡單地存儲訓練元組,做一些少量工作,在真正進行分類或預測的時候才開始做更多的工作。有點像是平時不努力學習功課,到了考前才開始臨時抱佛腳的感覺。
KNN(k-nearest-neighbor)算法的思想是找到在輸入新數據時,找到與該數據最接近的k個鄰居,在這k個鄰居中,找到出現次數最多的類別,對其進行歸類。
距離的計算有很多種方式,最簡單的就是直接計算歐式距離,但是根據不同的問題,也可以考慮選用不同的距離計算方式,如余弦距離等等。
詳細內容參考:https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm
C#的代碼實現如下,代碼僅供演示,運行效率不高,在大數據集上需要進行更多的優化:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using MachineLearning.UtilityFunctions; 5 namespace MachineLearning.Classification 6 { 7 public class KNN 8 { 9 public List<int> Labels; 10 public List<double[]> Features; 11 public int K; 12 public KNN(int k, List<int> labels, List<double[]> features) 13 { 14 K = k; 15 Labels = labels; 16 Features = features; 17 } 18 public void Classify(IEnumerable<double[]> data) 19 { 20 int n = Labels.Count; 21 foreach (var line in data) 22 { 23 var dist = new Tuple<int, double>[n]; 24 for (int i = 0; i < n; i++) 25 dist[i] = Tuple.Create(Labels[i], Distance.Euclidean(line, Features[i])); 26 var maxLabel = dist 27 .OrderBy(i => i.Item2) 28 .Take(K).GroupBy(i => i.Item1) 29 .OrderByDescending(i => i.Count()) 30 .First().Key; 31 Labels.Add(maxLabel); 32 Features.Add(line); 33 n++; 34 } 35 } 36 public void Display() 37 { 38 for (int i = 0; i < Labels.Count; i++) 39 Console.WriteLine("{0}: {1}", Labels[i], string.Join(",", Features[i])); 40 } 41 } 42 }
以電影數據為例:
電影 | 打斗鏡頭 | 接吻鏡頭 | 電影類型 |
1 | 3 | 104 | 愛情片 |
2 | 2 | 100 | 愛情片 |
3 | 1 | 81 | 愛情片 |
4 | 101 | 10 | 動作片 |
5 | 99 | 5 | 動作片 |
6 | 98 | 2 | 動作片 |
7 | 18 | 90 | 未知 |
該數據有兩個維度,一個是打斗鏡頭的次數,另一個是接吻鏡頭的次數,我們需要根據前6條數據來給第7部電影進行分類,判斷它是愛情片還是動作片。利用KNN算法進行分類的代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using MachineLearning.Classification; 7 namespace MachineLearning 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 var data = new List<double[]>() { 14 new double[] {3,104}, 15 new double[] {2,100}, 16 new double[] {1,81}, 17 new double[] {101,10}, 18 new double[] {99,5}, 19 new double[] {98,2}, 20 }; 21 var labels = new List<int>() 22 { 23 0,0,0,1,1,1 24 }; 25 var knn = new KNN(k: 3, labels: labels, features: data); 26 knn.Display(); 27 Console.WriteLine("----------------------------------------"); 28 knn.Classify(new double[][] { new double[] { 18, 90 } }); 29 knn.Display(); 30 Console.ReadKey(); 31 } 32 } 33 }
其中類別0代表愛情片,類別1代表動作片。
運行結果如圖所示:
可以看到,KNN分類器將第7部電影正確地歸為了愛情片。
注:作者本人也在學習中,能力有限,如有錯漏還請不吝指正。轉載請注明作者。