在十大经典数据挖掘算法中,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部电影正确地归为了爱情片。
注:作者本人也在学习中,能力有限,如有错漏还请不吝指正。转载请注明作者。