KNN近邻原理
分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。
kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 kNN(k-NearestNeighbor)方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。
KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成反比。
KNN的特性分析
1.1影响KNN的两个参数因素
K值的选取
K值的选取。一般来讲k值越大,则模型越简单,泛化能力越好,但容易欠拟合;k值越小,模型越复杂,拟合效果好,但是泛化能力不够。一般的,我们可以通过交叉验证的方法选取合适的k值。
距离度量方案的选择
欧式距离:够体现个体数值特征的绝对差异,所以更多的用于需要从维度的数值大小中体现差异的分析,如使用用户行为指标分析用户价值的相似度与差异
余弦相似度:更多的是从方向上区分差异,而绝对的数值不敏感,更多的用于使用用户对内容评分来区分用户兴趣的相似度和差异,同时修正了用户间可能存在的度量标准不统一的问题
KNN的优缺点
优点
- 简单,易于理解,易于实现,无需参数估计,无需训练;
- 对异常值不敏感(个别噪音数据对结果的影响不是很大);
- KNN要比SVM表现要好.
缺点
- 需要大量空间存储所有已知实例 算法复杂度高
- 当样本分布不平衡时,新的样本会归类为主导样本,
- 从而不能更好的接近实际分类结果
- 考虑距离,根据距离加上权重 比如:1/d(d:距离)
- 维数灾难
KNN的python实现以及数据结构
有以下先验数据,使用knn算法对未知类别数据分类
属性1 | 属性2 | 类别 |
---|---|---|
1.0 | 0.9 | A |
1.0 | 1.0 | A |
0.1 | 0.2 | B |
0.0 | 0.1 | B |
待测类别数据
属性1 | 属性2 | 类别 |
---|---|---|
1.2 | 1.0 | ? |
0.4 | 0.3 | ? |
Python KNN 算法的伪代码
输入:所有训练样本、待测样本
输出:待测样本的类别
Step 1、计算已知类别数据集中的点与当前之间的距离
Step 2、按照距离递增次序排序
Step 3、选取与当前点距离最小的K个点
Step 4、确定前K个点所在的类别的出现频率
Step 5、返回前K个点出现频率最高的类别作为当前点的预测分类
Python 代码块实现思路及代码
Step 1:完成待测的样本与所有训练样本的矩阵的距离计算
[1,0,1] [1,0,2]
[2,1,3] - [1,0,2]
[1,0,2] [1,0,2]
求和开方
diff = tile(newInput, (numSamples, 1)) - dataSet
squaredDiff = diff ** 2 # 将差值平方
Step 2: 排序
sortedDistIndices = argsort(distance)
Step 3: 遍历得到前K个数值
classCount = {}#创建一个空的Dictionary 数据格式
for i in xrange(k):
voteLabel = labels[sortedDistIndices[i]]
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
#取Dictionary Key位置上的元素个数不缺加1
Step 4:比较前K个标签的大小输出最大者
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
实际代码如下:
def kNNClassify(newInput, dataSet, labels, k):
27 numSamples = dataSet.shape[0] # shape[0]表示行数
28
29 # # Step 1: 计算距离[
30 # 假如:
31 # Newinput:[1,0,2]
32 # Dataset:
33 # [1,0,1]
34 # [2,1,3]
35 # [1,0,2]
36 # 计算过程即为:
37 # 1、求差
38 # [1,0,1] [1,0,2]
39 # [2,1,3] -- [1,0,2]
40 # [1,0,2] [1,0,2]
41 # =
42 # [0,0,-1]
43 # [1,1,1]
44 # [0,0,-1]
45 # 2、对差值平方
46 # [0,0,1]
47 # [1,1,1]
48 # [0,0,1]
49 # 3、将平方后的差值累加
50 # [1]
51 # [3]
52 # [1]
53 # 4、将上一步骤的值求开方,即得距离
54 # [1]
55 # [1.73]
56 # [1]
57 #
58 # ]
59 # tile(A, reps): 构造一个矩阵,通过A重复reps次得到
60 # the following copy numSamples rows for dataSet
61 diff = tile(newInput, (numSamples, 1)) - dataSet # 按元素求差值
62 squaredDiff = diff ** 2 # 将差值平方
63 squaredDist = sum(squaredDiff, axis = 1) # 按行累加
64 distance = squaredDist ** 0.5 # 将差值平方和求开方,即得距离
65
66 # # step 2: 对距离排序
67 # argsort() 返回排序后的索引值
68 sortedDistIndices = argsort(distance)
69 classCount = {} # define a dictionary (can be append element)
70 for i in xrange(k):
71 # # step 3: 选择k个最近邻
72 voteLabel = labels[sortedDistIndices[i]]
73
74 # # step 4: 计算k个最近邻中各类别出现的次数
75 # when the key voteLabel is not in dictionary classCount, get()
76 # will return 0
77 classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
78
79 # # step 5: 返回出现次数最多的类别标签
80 maxCount = 0
81 for key, value in classCount.items():
82 if value > maxCount:
83 maxCount = value
84 maxIndex = key
85
86 return maxIndex