第一周:用代码打开AI的大门

本文深入解析KNN算法的原理,包括其思想、优点与局限性,同时提供了手动实现KNN算法的Python代码示例,并展示了如何使用sklearn库进行KNN算法的调用。此外,还探讨了KD-树在优化KNN算法中的应用。

目录

1. 学习目标

2. KNN算法

3. 实现KNN算法

3.1 手动实现KNN算法

3.2 通过sklearn调用KNN算法

4. 参考文献


1. 学习目标

1. 了解KNN算法的思想及原理

2. 用Python手动实现KNN算法并在sklearn中调用封装好的KNN算法

3. 了解监督学习和无监督学习的概念

2. KNN算法

KNN算法的核心思想就是:样本可以用离他最距离近的k个邻居样本来代表。因此,该算法主要用于解决分类问题。一个生动的实例见[3]

KNN之所以被称作“敲门砖”,主要原因在于它不需要使用高深的数学模型。其他的机器学习算法都需要进行训练,而KNN算法的“训练”只是把训练集中的样本投射到样本空间当中,故训练成本极低。另外,该算法只通过欧式距离就可以很好地判断样本之间的相似度,从而得出预测结果。具体来说:当规定好K的值后,算法会根据欧式距离选出距离样本最近的K个其他样本点,然后采用投票的方式来决定该样本属于哪一个类别。

当然,KNN算法也可以根据其他需求设计的更加复杂。首先,KNN算法也可以用来解决回归问题,由于此时不能通过投票方式来进行预测,因此可以考虑通过取平均值的方式来进行预测;还有,如果我们把邻居的距离也考虑在内的话,可以根据样本到邻居的距离来设置权重,用加权平均的方式来取代投票的方式来进行预测。

3. 实现KNN算法

3.1 手动实现KNN算法

import numpy as np
from collections import Counter
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, \
                                                    test_size = 0.2, \
                                                    random_state = 2020)

def euc_dis(x1, x2):
    '''
    计算欧氏距离
    '''
    # 这里使用的是范数计算
    # 等价于return np.sqrt(np.sum((x1 - x2) ** 2))
    return np.linalg.norm(x1 - x2, ord = 2)

def knn_classfier(X, y, test_sample, k):
    '''
    X, y:训练数据的特征和标签
    test_sample:待预测的样本
    k:邻居选取个数
    '''
    # 计算待测样本与训练集中样本的欧氏距离
    dis_list = [euc_dis(test_sample, x) for x in X]
    # 从得到的欧式距离中选择前k个距离最小的训练数据在训练集中对应的索引
    # np.sort()返回数据由小到大的排列
    # np.argsort()返回数据由小到大排列后对应的索引排列
    # np.lexsort()返回数据按照字典序由小到大排列后对应的索引排列
    kneighbors = np.argsort(dis_list)[:k]
    # 统计参与投票的各个数据所属的类型
    # Counter()会返回一个类似字典结构,键是元素类别,值是该元素出现次数
    count = Counter(y[kneighbors])
    # count.most_common()会返回一个列表,列表里面是若干二元组
    # 元组中第一个元素代表元素类别,第二个代表元素出现次数
    # 因此count.most_common(1)[0][0]将会返回出现次数最多的那个类别的名字
    return count.most_common(1)[0][0]

predictions = [knn_classfier(X_train, y_train, x, 5) for x in X_test]
print(classification_report(y_test, predictions))
correct = np.count_nonzero(y_test == predictions)
print('accuracy is %.2f' % (correct / len(y_test)))

3.2 通过sklearn调用KNN算法

from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report

iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, \
                                                    test_size = 0.2, \
                                                    random_state = 2020)

knn_clf = KNeighborsClassifier(n_neighbors = 5)
knn_clf.fit(X_train, y_train)
predictions = knn_clf.predict(X_test)
print(classification_report(y_test, predictions))
correct = np.count_nonzero(y_test == predictions)
print('accuracy is %.2f' % (correct / len(y_test)))

KNeighborsClassifier()的具体参数含义及方法参见[1]

4. KNN的优缺点

4.1 优点

1. 理论成熟,思想简单,既可以用来做分类也可以用来做回归;

2. 天然解决多分类问题,也可用于回归问题;

3. 和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感;

4. 由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合[4]

4.2 缺点

1. 计算量大,效率低。即使优化算法,效率也不高;

2. 高度数据相关,样本不平衡的时候,对稀有类别的预测准确率低;

3. 相比决策树模型,KNN模型可解释性不强;

4. 维度灾难:随着维度的增加,“看似相近”的两个点之间的距离越来越大,而knn非常依赖距离[4]

5. 用KD-树优化KNN

KNN的重要步骤是对所有的实例点进行快速k近邻搜索。如果采用线性扫描,则要计算输入点与每一个点的距离,时间复杂度非常高。因此在查询操作时,使用KD-树来减少距离计算的次数从而节约时间。

5.1 什么是KD-树

KD-树是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构,且KD-树是一种二叉树,表示对k维空间的一个划分。

KD-树是每个节点均为k维样本点的二叉树,其上的每个样本点代表一个超平面,该超平面垂直于当前划分维度的坐标轴,并在该维度上将空间划分为两部分,一部分在其左子树,另一部分在其右子树。即若当前节点的划分维度为d,其左子树上所有点在d维的坐标值均小于当前值,右子树上所有点在d维的坐标值均大于等于当前值,本定义对其任意子节点均成立[4]

5.2 如何构建KD-树

1. 循环依序取数据点的各维度来作为切分维度;

2. 取数据点在该维度的中值作为切分超平面;

3. 将中值左侧的数据点挂在其左子树,将中值右侧的数据点挂在其右子树;

4. 递归处理其子树,直至所有数据点挂载完毕。

具体实例参考[4]

5.3 如何在KD-树上搜索最邻近的点

整个过程从KD-树的根节点开始进行递归操作。其中需要维护以下几个变量:

1. 当前最邻近点的坐标p,初始化为根节点坐标;

2. 输入点与当前最邻近点的距离d,初始化为到根节点的距离;

3. 当前最邻近点p在KD-树上的两个子节点lp和rp的坐标;

4. 输入点与lp和rp的距离ld和rd。

算法流程如下:

1. 如果当前节点为叶节点或者d < min(ld, rd),则返回p和d。否则进入2;

2. 令p = arg min(ld, rd),d = min(ld, rd),进入1。

如此就可以找到与输入点距离最邻近的点的坐标及距离了。

6. 参考文献

1. https://mp.weixin.qq.com/s?__biz=MzI4MjkzNTUxMw==&mid=2247483857&idx=1&sn=c888f2c4d40fb64eec5f5e78a3467b1a&chksm=eb932867dce4a171e5e9dba9f46a4e46127f063d1f9e817d250c5a5c18c1dd55f2acfa3c2662&token=2129819246&lang=zh_CN#rd

2. 《机器学习》(周志华)225页

3. https://www.cnblogs.com/gemine/p/11130032.html

4. https://mp.weixin.qq.com/s/RkenakI_DSXoMLwNNvUAAw

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值