kNN - k Nearest Neighbors k近邻算法

欧拉距离

$$\sqrt{(x^{(a)} - x^{(b)})^2 + (y^{(a)} - y^{(b)})^2}$$

$$\sqrt{(x_1^{(a)} - x_1^{(b)})^2 + (x_2^{(a)} - x_2^{(b)})^2 + ... + (X_n^{(a)} - x_n^{(b)})^2}$$

$$\sqrt {\sum_{i=1}^n (X_i^{(a)} - X_i^{(b)})^2}$$ kNN算法是非常特殊的,可以被认为是没有模型的算法,为了和其他算法统一,可以认为训练数据集就是模型本身。

判断机器学习算法的性能

需要将数据集分成训练/测试数据集,通过测试数据直接判断模型的好坏!在模型进入真实环境前改进模型。 train test split

分类准确度 - accuracy

预测结果和样本结果一致的样本数占所有样本数的比例。

超参数和模型参数

超参数: 在机器学习算法运行前需要决定的参数, 比如k

模型参数: 算法在训练过程中学习到的参数

kNN算法没有模型参数,kNN算法中的k是典型的超参数。 寻找好的超参数依赖 - 领域知识(视觉搜索,自然语言处理) - 经验数值(kNN算法中k默认为5) - 实验搜索。

kNN算法中另一个超参数: 距离

为了让kNN预测结果更合理,需要考虑距离的权重,通常用距离的倒数作为权重。 距离还可以解决平票的问题: 比如和样本点相连的3个点是3中类别,如果不考虑距离权重,则只能从3个中随机选一个作为预测结果,不合理.

weights: - uniform - distance

距离有: - 欧拉距离 $\sqrt {\sum_{i=1}^n (X_i^{(a)} - X_i^{(b)})^2}$ - 曼哈顿距离 $\sum_{i=1}^n \left| X_i^{(a)} - X_i^{(b)} \right| $ 代表两个样本点在每个维度上的距离的和 - - 明可夫斯基距离 Minkowski Distance $(\sum_{i=1}^n {\left| X_i^{(a)} - X_i^{(b)} \right|}^p)^{\frac 1 p} $

更多距离定义, 可以用相似度来定义样本间的距离:

  • 向量空间余弦相似度 Cosine Similarity
  • 调整余弦相似度 Adjusted Cosine Similarity
  • 皮尔森相关系数 Pearson Correlation Coefficient
  • Jaccard 相似系数 Jaccard Coefficient

寻找超参数要用网格搜索:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split

digits = datasets.load_digits()
X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.2, random_state=600)

param_grid = [
    {
        'weights': ['uniform'], 
        'n_neighbors': [i for i in range(1, 11)]
    },
    {
        'weights': ['distance'],
        'n_neighbors': [i for i in range(1, 11)],
        'p': [p for p in range(1, 6)]
    }
]

knn_clf = KNeighborsClassifier()
grid_search = GridSearchCV(knn_clf, param_grid, n_jobs = -1, verbose = 2)
grid_search.fit(X_train, y_train)

# 根据用户传入参数计算得到的参数
grid_search.best_estimator_
grid_search.best_score_
grid_search.best_params_
knn_clf = grid_search.best_estimator_
knn_clf.score(X_test, y_test)
Fitting 5 folds for each of 60 candidates, totalling 300 fits
KNeighborsClassifier(n_neighbors=1, p=3, weights='distance')
0.990251161440186
{'n_neighbors': 1, 'p': 3, 'weights': 'distance'}
0.9805555555555555

提升计算性能: n_jobs = -1, 用所有的核来计算

verbose: 整数值越大,输出的信息越多

GridSearchCV(knn_clf, param_grid, n_jobs = -1, verbose = 2)