简介
KNN(K-Nearest Neighbor)最近邻分类算法是数据挖掘中最简单而有效的分类技术之一。它的核心思想类似于“近朱者赤,近墨者黑”,通过依靠邻近样本的类别来判断未知样本的类别。
核心原理
为了对未知样本进行分类,首先将所有已知类别的样本作为参考,计算未知样本与每个已知样本的距离。然后,选取距离未知样本最近的K个已知样本,采用多数投票法则(majority-voting),将未知样本分配到K个最近样本中所占比例较多的类别中。
这就是KNN算法在分类任务中的基本思想,其中K表示选取的最近邻样本的个数。默认是5,一般不大于20。
需要注意的是,KNN算法是一种基于最近邻的分类方法,它不同于判别类域方法,特别适用于存在类域交叉或重叠的待分样本集。
KNN算法关键要点:
特征可比较的量化: 所有样本特征必须以可比较的数值形式表示。如果存在非数值特征,需通过量化方法将其转换为数值,例如将颜色转换为灰度值,以便进行距离计算。
样本特征归一化: 样本可能包含多个参数,具有不同的定义域和取值范围,对距离计算产生影响。因此,应对样本参数进行归一化处理,以避免某些参数的影响过大。常用的方法是对所有特征进行归一化处理。
距离函数选择: 需要选择适当的距离函数来计算样本之间的距离。常用的距离函数包括欧氏距离、余弦距离、汉明距离、曼哈顿距离等。通常情况下,欧氏距离适用于连续变量,而汉明距离适用于非连续变量,如文本分类。
确定K值: K值的选择很关键。选择过大的K值可能导致欠拟合,而过小的K值可能导致过拟合。应通过交叉验证等方法来确定合适的K值。
KNN算法优缺点总结:
优点:
- 简单易懂,易于实现,无需参数估计和训练。
- 适用于稀有事件分类。
- 特别适合多分类问题,性能比SVM更好。
缺点:
- 在样本不平衡时表现不佳。大样本类别可能占据邻居中的多数,导致预测偏向这些大样本类别。
- 计算量大,需要对每个待分类样本计算与所有已知样本的距离。
总结
KNN算法是一种简单有效的分类方法,通过选取最近邻样本来进行分类判定。优化KNN算法需要注意数据预处理、距离函数选择和K值确定等关键因素。虽然KNN在一些场景下存在不足,但其在多类别分类和稀有事件分类等方面的优点使其在实际应用中具有广泛价值。
代码
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
# 数据
# 样本
data_x = [
[1.3, 6],
[3.5, 5],
[4.2, 2],
[5, 3.3],
[2, 9],
[5, 7.5],
[7.2, 4 ],
[8.1, 8],
[9, 2.5]
]
# 分类
data_y = [0, 0, 0, 0,
1, 1, 1, 1, 1]
#训练集
x_train = np.array(data_x)
y_train = np.array(data_y)
x1 = x_train[y_train == 0,0]
y1 = x_train[y_train == 0,1]
x2 = x_train[y_train == 1,0]
y2 = x_train[y_train == 1,1]
# 画图
plt.title("KNN")
plt.scatter(x1, y1, color = "orange", marker = "o")
plt.scatter(x2, y2, color = "blue", marker = "x")
# 新的点
data_new = np.array([4, 5])
plt.scatter(data_new[0], data_new[1], color = "purple", marker = "^")
plt.show()
# 计算新的点到旧的点的距离
dist_array = np.array([])
for temp in x_train:
dist = temp - data_new
dist = np.sqrt(np.sum(dist * dist))
print(f'距离为:{dist}')
dist_array = np.append(dist_array, dist)
print(f"dist_array == {dist_array}")
# 排序距离
sort_array = np.sort(dist_array)
print(f"sort_array == {sort_array}")
sort_indext_array = np.argsort(dist_array)
print(f"sort_indext_array == {sort_indext_array}")
# 设定k值
k = 5
# 距离最近的k个点投票
first_k = [y_train[i] for i in sort_indext_array[:k]]
print(f"first_k == {first_k}")
# 列出n个最常见的元素及其从最常见元素开始的计数
c = Counter(first_k).most_common()
ans = c[0][0]
print(f"self ans == {ans}")
# scikit-learn中的KNN算法
from sklearn.neighbors import KNeighborsClassifier
# k的值
knn_obj = KNeighborsClassifier(n_neighbors=5)
# 样本集
knn_obj.fit(x_train, y_train)
# 预测
ans = knn_obj.predict([data_new])
print(f"cikit-learn ans == {ans[0]}")