机器学习中KNN是个最基本的分类方法之一。KNN的全称是K Nearest Neighbor,意思很明显:求K个最近的样本。这里需要说明的有两点:1、这个近是通过距离来体现的,我们算距离的方法有很多,最常用的有:cos(余弦距离),曼哈顿(出租车)距离,以及欧几里得距离。一般来说我们可以使用任何一个求距离的公式去求距离;2、这个距离是求解待分类样本与已经标记好的已知样本集中的每个样本之间的距离。
从上面的分析中,我们可以知道,KNN分类是基于样本和标签的分类方法,即每一个样本必须要有一个明确的标签。所以我们待分类的样本通过该方法进行分类之后也必须也会得到唯一的一个标签与之对应。但是KNN求解的是与待分类样本距离最近的K个已经标记了的已知样本。所以我们得到这K个最近邻的样本后还必须要对这些样本进行按照它们所属的类别进行排序。比如我们的样本集只有6个样本,分别是 [A, B, C, D, E, F],对应的标签分别是[1, 2, 1, 2, 0, 1],待分类样本是G(其中G和样本集中的每个样本的维度应该要一致),通过计算我们发现G与这6个样本之间的欧式距离分别是[0.147, 0.239, 0.159, 0.289, 1.33, 0.247],K=3,那么我们会得到如下结果:[0.147, 0.159, 0.239],对应的标签分别为:[1, 1, 2]那么我们发现样本G可能属于类别1,也有可能属于类别2,但是我们发现G属于类别1的可能性要大些。至于这个可能性一方面是凭直觉,另方面是还是凭直觉([1, 1, 2]),所以我们凭直觉就可以将样本G归为类别1.
下面给出使用python编写的KNN代码,这个代码里我使用了lambda匿名函数以及python的其它几个内置函数,不熟悉这些东东的用法的盆友们可以翻看我之前写的博客。代码如下:
from math import sqrt def get_data(): data = {'data': [], 'label': []} group = [[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]] labels = ['A', 'A', 'B', 'B'] data['data'].append(group) data['label'].append(labels) return data def compute_distance(sample, data, k): assert isinstance(sample, list) and len(sample) > 0 assert isinstance(data, dict) and len(data) > 0 assert len(sample) == len(data['data'][0][0]) distance = [0] * len(data['data'][0]) for sample_index in range(0, len(distance), 1): distance[sample_index] = sqrt(sum(list(map(lambda x: pow(x[0] - x[1], 2), zip(data['data'][0][sample_index], sample))))) distance = sorted(zip(distance, data['label'][0]), reverse=False) predicted_label = list(map(lambda x: x[-1], distance[:k])) print(predicted_label) count_labels = sorted(list(map(lambda x: (x, predicted_label.count(x)), set(data['label'][0]))), reverse=True) return count_labels[0][0] label = compute_distance([0, 0], get_data(), 3) print('label:', label)
['A', 'B', 'B'] label: B