K-近邻 kNN, k-NearestNeighbor

Posted by Wenjing Liu on 2019-08-08

概念

给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的 k 个实例,这 k 个实例的多数属于某个类,就把该输入实例分为这个类。

  • 优点:
    • 算法简单
    • 训练简单
    • 适用于任意数量的分类
    • 容易添加更多数据
    • 精度高
    • 对异常值不敏感
    • 无数据输入假定
    • 参数少:
      • K
      • distance metric
  • 缺点:
    • 高预测成本(大的数据集更糟)
    • 高维数据不太好
    • 计算复杂度高
    • 空间复杂度高

原理

1
2
3
4
5
6
1. 假设有一个带有标签的样本数据集(训练样本集),其中包含每条数据与所属分类的对应关系;
2. 输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较。
- 计算新数据与样本数据集中每条数据的距离。
- 对求得的所有距离进行排序(从小到大,越小表示越相似)。
3. 取前 k (k 一般小于等于 20 )个样本数据对应的分类标签。
4. 求 k 个数据中出现次数最多的分类标签作为新数据的分类。

归一化

  • 定义

归一化就是要把你需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。首先归一化是为了后面数据处理的方便,其次是保正程序运行时收敛加快。

  • 方法
    • 线性函数转换,表达式如下:

      $$y=\frac{x-MinValue}{MaxValue-MinValue}$$
       
      说明:x、y分别为转换前、后的值,MaxValue、MinValue分别为样本的最大值和最小值。

    • 对数函数转换,表达式如下:
      $$\frac{\partial u}{\partial t} = h^2 \left( \frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2} + \frac{\partial^2 u}{\partial z^2}\right)$$

评估指标

ScikitLearn 中的kNN

  • 归一化数值
1
2
3
4
5
6
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(df.drop('TARGET CLASS', axis=1))
scaled_features = scaler.transform(df.drop('TARGET CLASS', axis=1))
df_feat = pd.DataFrame(scaled_features, columns=df.columns[:-1])
  • 使用算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix

X = df_feat
y = df['TARGET CLASS']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train, y_train)
pred = knn.predict(X_test)
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred))
  • 比较K值对算法的影响
1
2
3
4
5
6
7
8
9
10
11
12
13
error_rate = []

for i in range(1, 40):
knn = KNeighborsClassifier(n_neighbors=i)
knn.fit(X_train, y_train)
pred_i = knn.predict(X_test)
error_rate.append(np.mean(pred_i != y_test))

plt.Figure(figsize=(10, 6))
plt.plot(range(1, 40), error_rate, color='blue', ls='dashed', marker='o', markerfacecolor='red', markersize=10)
plt.title('Error Rate with K Value')
plt.xlabel('K')
plt.ylabel('Error Rate')

参考