《机器学习:公式推导与代码实践》鲁伟著读书笔记。
K近邻(K-nearest neighbor,K-NN)算法是一种经典的监督学习的分类方法。K近邻算法是依据新样本与k个与其相邻最近的样本的类别来进行分类的,所以K近邻算法不像前面所学习到的机器学习其他方法一样,有显式的学习训练过程,将有标签的样本用来训练模型,而是直接计算新样本与所有样本点的距离来确定分类情况的。K近邻算法的三要素为:k值的选择、距离的度量方式和分类决策规则。

距离度量方式

下面来介绍常用的距离度量方式:
闵氏距离,即闵可夫斯基距离(Minkowski distance),其具体定义如下。特征数为m维的向量样本集合X,对于任意的 x i , x j ∈ X x_{i},x_{j}\in X xi​,xj​∈X, x i = ( x 1 i , x 2 i , . . . , x m i ) T x_{i}=(x_{1i},x_{2i},...,x_{mi})^{T} xi​=(x1i​,x2i​,...,xmi​)T, x j = ( x 1 j , x 2 j , . . . , x m j ) T x_{j}=(x_{1j},x_{2j},...,x_{mj})^{T} xj​=(x1j​,x2j​,...,xmj​)T,样本 x i x_{i} xi​和样本 x j x_{j} xj​之间的闵氏距离可以定义为: d i j = ( ∑ k = 1 m ∣ x k i − x k j ∣ p ) 1 p , p ≥ 1 d_{ij}=\left(\sum_{k=1}^{m}\left|x_{ki}-x_{kj}\right|^{p}\right)^{\frac{1}{p}},p\geq1 dij​=(k=1∑m​∣xki​−xkj​∣p)p1​,p≥1当p=1时,闵氏距离称为曼哈顿距离(Manhatan distance): d i j = ∑ k = 1 m ∣ x k i − x k j ∣ d_{ij}=\sum_{k=1}^{m}\left|x_{ki}-x_{kj}\right| dij​=k=1∑m​∣xki​−xkj​∣当p=2时,闵氏距离称为欧氏距离(Euclidean distance): d i j = ( ∑ k = 1 m ∣ x k i − x k j ∣ 2 ) 1 2 d_{ij}=\left(\sum_{k=1}^{m}\left|x_{ki}-x_{kj}\right|^{2}\right)^{\frac{1}{2}} dij​=(k=1∑m​∣xki​−xkj​∣2)21​当p= ∞ \infty ∞时,闵氏距离称为切比雪夫距离(Chebyshev distance): d i j = max ∣ x k i − x k j ∣ d_{ij}=\text {max}\left|x_{ki}-x_{kj}\right| dij​=max∣xki​−xkj​∣
马氏距离,即马哈拉诺比斯距离(Mahalanobis distance),是一种衡量各个特征之间相关性的距离度量方式。给定一个样本集合 X = ( x ) m ∗ n X=(x)_{m*n} X=(x)m∗n​,其协方差矩阵为 S S S,那样本 x i x_{i} xi​和样本 x j x_{j} xj​之间的马氏距离可以定义为: d i j = [ ( x i − x j ) T S − 1 ( x i − x j ) ] 1 2 d_{ij}=[(x_{i}-x_{j})^{T}S^{-1}(x_{i}-x_{j})]^{\frac{1}{2}} dij​=[(xi​−xj​)TS−1(xi​−xj​)]21​当 S S S为单位矩阵时,即样本各个特征之间相互独立且方差为1时,马氏距离便为欧氏距离
通常情况下,K近邻算法使用欧氏距离作为实例之间的距离度量方法。

k值的选择

K近邻算法最直观的解释为:给定一个训练集,对于测试集的一个实例来说,在训练集中找出与该实例距离最近的K个训练集中的实例,这K个训练集中的实例的多数属于哪个类,则测试集中的实例就属于哪个类。
一般来说,K值的大小对分类结果有重大影响。

  1. 如果选择的K值较小,仅相当于用离新样本最近的训练集实例进行类别预测。但是由于K值较小,所以得到的预测结果会对最近的训练集实例非常敏感,分类器抗噪能力较差,容易造成过拟合。
  2. 如果选择的K值较大,就相当于运用较大邻域的训练集实例进行预测,相应的分类误差会增大,模型简单,导致模型欠拟合。

所以,K值的选择太大也不好,太小也不好。我们一般采用k折交叉验证(k-fold Cross Validation)的方法来选择合适的K值。k折交叉验证的具体步骤如下:

  1. 将所有的数据集划分为k份;
  2. 不重复地每次取其中一份做测试集,用其他k-1份做训练集训练模型,之后计算该模型在测试集上的误差 M S E i MSE_{i} MSEi​。

分类决策规则

通常为多数表决方法,K邻域内那个种类的训练样本数越多,则新样本的类别便为这个类别。

K近邻分类算法的NumPy手撕代码

导入iris数据集

# 导入相关模块
import numpy as np
from collections import Counter
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.utils import shuffle
# 导入sklearn iris数据集
iris = datasets.load_iris()
# 打乱数据后的数据与标签
X, y = shuffle(iris.data, iris.target, random_state=13)
# 数据转换为float32格式
X = X.astype(np.float32)
# 训练集与测试集的简单划分,训练-测试比例为7:3
offset = int(X.shape[0] * 0.7)
X_train, y_train = X[:offset], y[:offset]
X_test, y_test = X[offset:], y[offset:]
# 将标签转换为竖向量
y_train = y_train.reshape((-1,1))
y_test = y_test.reshape((-1,1))
# 打印训练集和测试集大小
print('X_train=', X_train.shape)
print('X_test=', X_test.shape)
print('y_train=', y_train.shape)
print('y_test=', y_test.shape)

X_train= (105, 4)
X_test= (45, 4)
y_train= (105, 1)
y_test= (45, 1)

距离度量方式

定义欧氏距离

def compute_distances(X, X_train):'''输入:X:测试样本实例矩阵X_train:训练样本实例矩阵输出:dists:欧式距离'''# 测试实例样本量num_test = X.shape[0]# 训练实例样本量num_train = X_train.shape[0]# 基于训练和测试维度的欧氏距离初始化dists = np.zeros((num_test, num_train)) # 测试样本与训练样本的矩阵点乘M = np.dot(X, X_train.T)# 测试样本矩阵平方te = np.square(X).sum(axis=1)# 训练样本矩阵平方tr = np.square(X_train).sum(axis=1)# 计算欧式距离dists = np.sqrt(-2 * M + tr + np.matrix(te).T)    return dists
dists = compute_distances(X_test, X_train)

依据K值的选择定义预测函数

def predict_labels(y_train, dists, k=1):'''输入:y_train:训练集标签dists:测试集与训练集之间的欧氏距离矩阵k:k值输出:y_pred:测试集预测结果'''# 测试样本量num_test = dists.shape[0]# 初始化测试集预测结果y_pred = np.zeros(num_test) # 遍历   for i in range(num_test):# 初始化最近邻列表closest_y = []# 按欧氏距离矩阵排序后取索引,并用训练集标签按排序后的索引取值# 最后拉平列表# 注意np.argsort函数的用法labels = y_train[np.argsort(dists[i, :])].flatten()# 取最近的k个值closest_y = labels[0:k]# 对最近的k个值进行计数统计# 这里注意collections模块中的计数器Counter的用法c = Counter(closest_y)# 取计数最多的那一个类别y_pred[i] = c.most_common(1)[0][0]    return y_pred

k折交叉验证模型

选取k=5.

num_folds = 5
# 候选k值
k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]
X_train_folds = []
y_train_folds = []
# 训练数据划分
X_train_folds = np.array_split(X_train, num_folds)
# 训练标签划分
y_train_folds = np.array_split(y_train, num_folds)
k_to_accuracies = {}
# 遍历所有候选k值
for k in k_choices:# 五折遍历    for fold in range(num_folds): # 对传入的训练集单独划出一个验证集作为测试集validation_X_test = X_train_folds[fold]validation_y_test = y_train_folds[fold]temp_X_train = np.concatenate(X_train_folds[:fold] + X_train_folds[fold + 1:])temp_y_train = np.concatenate(y_train_folds[:fold] + y_train_folds[fold + 1:])       # 计算距离temp_dists = compute_distances(validation_X_test, temp_X_train)temp_y_test_pred = predict_labels(temp_y_train, temp_dists, k=k)temp_y_test_pred = temp_y_test_pred.reshape((-1, 1))       # 查看分类准确率num_correct = np.sum(temp_y_test_pred == validation_y_test)num_test = validation_X_test.shape[0]accuracy = float(num_correct) / num_testk_to_accuracies[k] = k_to_accuracies.get(k,[]) + [accuracy]# 打印不同 k 值不同折数下的分类准确率
for k in sorted(k_to_accuracies):    for accuracy in k_to_accuracies[k]:print('k = %d, accuracy = %f' % (k, accuracy))

k = 1, accuracy = 0.904762
k = 1, accuracy = 1.000000
k = 1, accuracy = 0.952381
k = 1, accuracy = 0.857143
k = 1, accuracy = 0.952381
k = 3, accuracy = 0.857143
k = 3, accuracy = 1.000000
k = 3, accuracy = 0.952381
k = 3, accuracy = 0.857143
k = 3, accuracy = 0.952381
k = 5, accuracy = 0.857143
k = 5, accuracy = 1.000000
k = 5, accuracy = 0.952381
k = 5, accuracy = 0.904762
k = 5, accuracy = 0.952381
k = 8, accuracy = 0.904762
k = 8, accuracy = 1.000000
k = 8, accuracy = 0.952381
k = 8, accuracy = 0.904762
k = 8, accuracy = 0.952381
k = 10, accuracy = 0.952381
k = 10, accuracy = 1.000000
k = 10, accuracy = 0.952381
k = 10, accuracy = 0.904762
k = 10, accuracy = 0.952381
k = 12, accuracy = 0.952381
k = 12, accuracy = 1.000000
k = 12, accuracy = 0.952381
k = 12, accuracy = 0.857143
k = 12, accuracy = 0.952381
k = 15, accuracy = 0.952381
k = 15, accuracy = 1.000000
k = 15, accuracy = 0.952381
k = 15, accuracy = 0.857143
k = 15, accuracy = 0.952381
k = 20, accuracy = 0.952381
k = 20, accuracy = 1.000000
k = 20, accuracy = 0.952381
k = 20, accuracy = 0.761905
k = 20, accuracy = 0.952381
k = 50, accuracy = 1.000000
k = 50, accuracy = 1.000000
k = 50, accuracy = 0.904762
k = 50, accuracy = 0.761905
k = 50, accuracy = 0.904762
k = 100, accuracy = 0.285714
k = 100, accuracy = 0.380952
k = 100, accuracy = 0.333333
k = 100, accuracy = 0.238095
k = 100, accuracy = 0.190476

机器学习——K近邻分类算法及python代码实现相关推荐

  1. 机器学习100天(三十):030 K近邻分类算法-K值的选择

    机器学习100天,今天讲的是:K近邻分类算法-K值的选择. <机器学习100天>完整目录:目录 上一节我们讲了 K 折交叉验证的理论,下面我们将 K 折交叉验证算法应用到 K 近邻分类算法 ...

  2. python 机器学习——K 近邻分类理论及鸢尾( Iris )数据集实例操作

    K 近邻分类理论及鸢尾( Iris )数据集实例操作 一.K 近邻分类理论 二.K 近邻分类实例操作 (1)导入数据 划分训练集测试集 (3)数据标准化 (4)用 K 近邻法建立模型 (5)性能评估 ...

  3. K近邻分类算法实战教程

    K近邻(K-Nearest Neighbor ,简称KNN ) 是有监督非线性.非参数分类算法,非参数表示对数据集及其分布没有任何假设.它是最简单.最常用的分类算法之一,广泛应用于金融.医疗等领域. ...

  4. 机器学习经典算法具体解释及Python实现--K近邻(KNN)算法

    (一)KNN依旧是一种监督学习算法 KNN(K Nearest Neighbors,K近邻 )算法是机器学习全部算法中理论最简单.最好理解的.KNN是一种基于实例的学习,通过计算新数据与训练数据特征值 ...

  5. 机器学习——K近邻算法(KNN)(K Nearest Neighbor)

    参考视频与文献: python与人工智能-KNN算法实现_哔哩哔哩_bilibili 机器学习--K近邻算法(KNN)及其python实现_清泉_流响的博客-CSDN博客_python实现knn 机器 ...

  6. Python KNN K近邻分类

    Python KNN K近邻分类 1 声明 本文的数据来自网络,部分代码也有所参照,这里做了注释和延伸,旨在技术交流,如有冒犯之处请联系博主及时处理. 2 KNN简介 相关概念见下: 对于给定的观测来 ...

  7. 机器学习常用的六种分类方法,Python代码详细都在这里!

    机器学习常用的六种分类方法,Python代码详细都在这里! 六种常用分类方法包括两种线性分类及四种非线性分类法,分别是: 一.线性判别分析 from sklearn.model_selection i ...

  8. python 分类算法_python机器学习之KNN分类算法

    本文为大家分享了python机器学习之KNN分类算法,供大家参考,具体内容如下 1.KNN分类算法 KNN分类算法(K-Nearest-Neighbors Classification),又叫K近邻算 ...

  9. Python+OpenCV:理解k近邻(kNN)算法(k-Nearest Neighbour (kNN) algorithm)

    Python+OpenCV:理解k近邻(kNN)算法(k-Nearest Neighbour (kNN) algorithm) 理论 kNN is one of the simplest classi ...

最新文章

  1. 图像金字塔(pyramid)与 SIFT 图像特征提取(feature extractor)
  2. 系统启动与内核管理 ;AWK部分 重要内容 (实验及awk的常见面试题)
  3. redis的redisvCommand的%b
  4. win10taskkill无法终止进程_Win10无法终止进程拒绝访问
  5. VM安装虚拟机不能全屏解决
  6. spring-注解实现入门
  7. 实录:有钱男性的真实私生活
  8. Google 工作 4 年,我最终还是选择了离开
  9. OpenCV人工智能图像处理学习笔记 第6章 计算机视觉加强之机器学习下 Hog_SVM小狮子识别
  10. 企业安全:业务的安全韧性
  11. 智能辅助系统在配电站所内的建设及应用
  12. NPDP产品经理认证考试培训资料--XISAI
  13. Java将汉字数字日期转换为数字日期(例如: 二〇二〇年十一月二十一日 → 2020年11月21日)
  14. android 最好的gtd软件,Windows 上的高颜值 GTD 应用,这可能是最棒的一款了:MyerList...
  15. Linux系列讲解 —— SSH登录
  16. 元宇宙+DAO=ZOO-Crypto World
  17. c/c++中sizeof()、strlen()、length()、size()详解和区别
  18. 20060707-Spatial transformations: Translation confusion
  19. 将英文kali改成中文kali
  20. Android 锁屏后Service服务保活(支持9.0)

热门文章

  1. 唱一曲归来未晚,歌一调湖海茫茫
  2. Ubuntu下微信(wechat)经常无故卡死解决方法 百度输入法
  3. 【python数据分析】数据如何进行合并
  4. Aes加/解密工具类 --Java
  5. 2021,你还在写“赤裸裸”的API吗?来试试这个方法吧!
  6. 超级实用的五款黑科技APP,让你舍不得分享
  7. .NET Core Polly 重试 熔断 降级
  8. 【数据可视化】基于Dash制作的疫情数据可视化APP(Dash入门必读,附可运行源码)
  9. Linux配置gdal变量环境,基于GDAL库的LINUX环境下的FY-3D和FY-4A遥感数据处理
  10. 2021-05-20 DNS服务器