【机器学习】K-近邻算法(KNN)

作者:田志晨

来源:小田学Python

机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。它是人工智能的核心,是使计算机具有智能的根本途径。

那么多余的内容就不说了,想必大家都明白,网上内容实在太多了。接下来进入正题,第一个机器学习算法——KNN。

01

原理透析 

KNN算法即K-近邻算法,是机器学习算法当中相对较为简单的一个分类算法,它属于上图分类中的监督学习算法,监督学习是指利用一组已知类别的样本进行训练,来推断新的数据,也就是用打过标签的数据来训练。

它的判决是通过特征值的欧几里得距离:

欧式距离是最常见的距离量度,衡量的是多维空间中各个点之间的绝对距离。

具体判别方法是:一个样本在其特征空间里的K个最邻近的样本中进行投票,该样本属于投票数量较多的那个类别,K的取值要结合具体内容来调节。单凭文字看的很懵,那就上图吧:

上图描述的就是一个KNN算法的过程(数据位置随机,仅为介绍原理),其中五角星是待测数据,三角形和正方形分别是两个类别,K-近邻算法是在K个最近的样本中进行投票。例如,设置K=3,那么就计算得所有样本的欧氏距离,进行排序,取最近的3个,那么也就是其中的蓝色圈范围。其中包括两个三角形,一个正方形,其概率也就是:三角形 2/3,正方形 1/3,因此可以判别出该五角星属于三角形一类。

下面通过一个例子告诉你,KNN算法该如何实现:

# 导入包:KNN方法在sklearn下neighbors中
import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier

补充:KNN可以做分类问题,以及回归问题

分类问题:from sklearn.neighbors import KNeighborsClassifier
回归问题:from sklearn.neighbors import KNeighborsRegressor

为了容易理解,编造少量数据进行演示:

data = pd.DataFrame([['大话西游',45,1,'动作片'],['杀破狼',33,3,'动作片'],['前任3',0,10,'爱情片'],['战狼',59,1,'动作片'],['泰坦尼克号',1,15,'爱情片'],['纯真漫画',2,19,'爱情片']], columns=['电影名称','武打镜头','接吻镜头','分类情况'])

那么接下来就可以通过特征值来训练模型,当然电影名称不能用来判断,就选用“武打镜头”和“接吻镜头”来分析,“分类情况”是已经打好的标签。

X = data[['武打镜头','接吻镜头']]
y = data['分类情况']

接下来开始训练模型,至于参数问题,我使用的jupyter,通过shift+tab可以显示需要传的参数,其他环境也有自己的方式,可以试着摸索一下。

# 创建对象并训练模型
knn = KNeighborsClassifier(n_neighbors=5) # 参数为K值
knn.fit(X, y) # 参数为特征和标签

训练好模型就可以测试一下了,看看到底准确与否。

# 武打镜头:100,接吻镜头:3 显然我们自己可以判断出这是个动作片
X_test = pd.DataFrame({'武打镜头':[100], '接吻镜头':[3]})
knn.predict(X_test) # 进行预测

[out] array(['动作片'], dtype=object) # 结果正确

下面可以解析一下它是怎么做到的。已知KNN是利用欧式距离判别,那么就手动的计算下。

# 欧式距离公式
s = ((data['武打镜头']-100)**2 + (data['接吻镜头']-3)**2)**0.5
index = s.sort_values().index
data['分类情况'][index[:5]] # 前面设置的n_neighbors为5,取前5个进行投票,动作片有三票,则是动作片

[out]
3 动作片
0 动作片
1 动作片
5 爱情片
4 爱情片
Name: 分类情况, dtype: object

可以看到动作片的投票占到了0.6,爱情片占0.4,knn的预测还有一个函数predict_proba,即为预测概率值。

# 上述可以计算得,该片为动作片的概率为0.6,爱情片的概率为0.4
knn.predict_proba(X_test)

[out] array([[0.6, 0.4]]) # 概率吻合
上述内容已经完整的走了一遍KNN算法的过程。但是其中有一些缺陷,再拿回来前面的一幅图看一下。

可以看到,我还画了一个红色的圈,也就是选取K=7的时候,所取到的最近邻样本,这时候再看投票比例:正方形 4/7,三角形 3/7,五角星判决为正方形,不再是K取3时的三角形。这就是它的一个缺陷:不稳定,而且KNN的时间复杂度和空间复杂度都很高,因为它要遍历所有的样本,计算欧氏距离。那么它解决不了的问题还有其他算法来解决,所以也不用担心啦。

02

实战演练 

实战演练选取的是一个十分经典的案例——手写数字识别(MNIST)。不出意外,后续讲解其他算法同样会用到这个例子。

数据集包括训练集 6w 条数据,测试集 1w 条数据。(需要数据可以公众号后台添加小田微信)

import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
# pandas读取训练数据,并查看其内容
data = pd.read_csv('mnist_dataset/mnist_train.csv', header=None)
data.head()

查看数据,可以观察到,表中第一列是对应数字的标签,后面的就是该数字图像的像素点(因为照片四周是空白的,也即是0)。

数据共 6w 条,第一列是标签,那么后面784列便是数字的特征值(即28X28的图片展开为一维)。接下来就是拆分成上面所提到的特征值和标签:

# 拆分为第一列的标签值和后面784列的特征值
X_train = data.iloc[:,1:]
y_train = data[0]

下面开始训练数据:

%%time
knn = KNeighborsClassifier(n_neighbors=10) # 数据量较大,适当放大K值
knn.fit(X_train, y_train)

高估了我电脑的性能,尽然用了一分钟。后面进行预测的时候耗时将更多,大家想测试的话可以截取其中部分数据进行建模。下面开始检验模型:

test_data = pd.read_csv('mnist_dataset/mnist_test.csv', header=None)
X_test = test_data.iloc[:,1:]
y_test = test_data[0]
%%time
y_predict = knn.predict(X_test)
Wall time: 20min 42s(不出意外,尽然二十分钟,同时也可以看到该算法的复杂度,曾经用神经网络跑这个数据集用了近十分钟)。
# 计算一下上述模型的准确率
(y_test == y_predict).mean()

[out] 0.9665 # 结果并不算差
还有一个命令knn.scorere(X_test, y_test),它既进行了预测,同时计算出准确率。上述就是一个完整的过程。不过其中还有可以优化的地方,毕竟上面的耗时、准确度还有待提高。

jupyter中shift+tab,查看其中的参数,包括例如投票的权重(weights)、算法(algorithm)、多进程(n_jobs)等,以上参数需要自己协调,找到最合适的,可以降低计算时间,提高准确率。

◆ ◆ ◆  ◆ ◆

长按二维码关注我们


数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以扫描下方管理员二维码,进群前一定要关注公众号奥,关注后让管理员帮忙拉进群,期待大家的加入。

管理员二维码:

猜你喜欢

● 笑死人不偿命的知乎沙雕问题排行榜

● 用Python扒出B站那些“惊为天人”的阿婆主!

● 全球股市跳水大战,谁最坑爹!

● 华农兄弟、徐大Sao&李子柒?谁才是B站美食区的最强王者?

● 你相信逛B站也能学编程吗

你可能感兴趣的:(【机器学习】K-近邻算法(KNN))