用Python手撸一个KNN算法(思想及代码)
今天小编给大家写一个机器学习的算法——KNN算法。
首先介绍一下KNN的思想:
如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上的样本特性。该方法在确定分类决策上只一句最邻近的一个或者几个样本的类别来决定待分样本所属的类别。总而言之呢,就是那之前的数据来做个比较,看哪个最相似,那么它的值就是什么,思路简单明了,代码也不算复杂,适和小白
接着再介绍一下KNN的代码实现步骤:
对未知类别属性的数据集中的每个点依次执行以下操作:
1、计算已知类别数据集中的点与当前点之间的距离
2、按照距离递增次序排序
3、选取与当前点距离最小的K个点
4、确定前K个点所在类别出现的频率
5、返回前k个点出现频率最高的类别作为当前点的预测分类
KNN的实际应用场景:
其实呢,对于机器学习算法的应用,分为两大类:分类与预测,然而KNN这里是可以说是分类,也说成预测 ,因为是对未知数据的一个分类,固然也可以理解为预测;在实际应用场景中呢,可以用在用户的商品智能推荐上,根据用户(A)的特征找出与其最相似的用户(B),紧接着在A身上投入一些A没有而B喜欢的一些商品,进而达到一个利润最大化的效果
废话不多说,小编来撸一手代码吧:
###先附上所需要的库
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import os
相信大家对这些库也都是十分熟悉了,这里小编就不详细介绍,实在有需要可以私聊小编,或者觉得小编文化程度低可以选择度娘。
###接下来就是整篇文章的重头戏,KNN算法
#此处的unknow_data就是待预测,know_data为已知数据,k为选择邻近的个数
def knn(unknow_data,know_data,k):
number_unknow=len(unknow_data)
number_know=len(know_data)
for num in range(number_unknow):
category_dict={}
diffMat=(np.tile(np.array(data_unknow.loc[num]),(number_know,1))-np.array(data_know.iloc[:,:-1]))
sqDiffMat=diffMat**2
sqDistance=sqDiffMat.sum(axis=1)
Distance=sqDistance**0.5
Distance_sort=Distance.argsort()
for i in range(k):
row=Distance_sort[i]
category=know_data.iloc[row,-1]
if category not in category_dict:
category_dict.setdefault(category,1)
else:
category_dict[category]+=1
best_category=sorted(category_dict.items(),key=lambda item:item[1],reverse=True)[0][0]
unknow_data.iloc[num,-1]=best_category
print('此时第%s行数据的预测结果为%s' % (num+1,best_category))
return unknow_data
这部分就是利用了欧式距离算法,再加上一点点的数据处理技巧,这里的欧式距离是怎样的呢?这里小编给你介绍以下
Lr范数就是x,y每个维度差距上取r次方加和后再开r次方根。Lr norm: what you get by taking the rth power of the differences, summing and taking the rth root.
给定向量x=(x1,x2,...xn)
L2范数:向量各个元素的平方求和然后求平方根,也叫欧式范数、欧氏距离。
实在不懂也没关系,懂得KNN的思想和它得出的结果代表也是ok的,理论上的东西非专业的可以慢慢来。
总而言之呢,原理就是这样,接下来小编给大家送上一个完整的代码吧!!
完整代码如下:
"""
算法思路:
对未知类别属性的数据集中的每个点依次执行以下操作:
1、计算已知类别数据集中的点与当前点之间的距离
2、按照距离递增次序排序
3、选取与当前点距离最小的K个点
4、确定前K个点所在类别出现的频率
5、返回前k个点出现频率最高的类别作为当前点的预测分类
"""
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import os
os.chdir(r'/Users/kihaikuma/Desktop/file/练习')
def knn(unknow_data,know_data,k):
number_unknow=len(unknow_data)
number_know=len(know_data)
for num in range(number_unknow):
category_dict={}
diffMat=(np.tile(np.array(data_unknow.loc[num]),(number_know,1))-np.array(data_know.iloc[:,:-1]))
sqDiffMat=diffMat**2
sqDistance=sqDiffMat.sum(axis=1)
Distance=sqDistance**0.5
Distance_sort=Distance.argsort()
for i in range(k):
row=Distance_sort[i]
category=know_data.iloc[row,-1]
if category not in category_dict:
category_dict.setdefault(category,1)
else:
category_dict[category]+=1
best_category=sorted(category_dict.items(),key=lambda item:item[1],reverse=True)[0][0]
unknow_data.iloc[num,-1]=best_category
print('此时第%s行数据的预测结果为%s' % (num+1,best_category))
return unknow_data
def main():
data_know=pd.read_excel(r'test_data_know.xlsx')
data_unknow=pd.read_excel(r'test_data_unknow.xlsx')
new_unknow_data=knn(data_unknow,data_know,5)
sns.set()
true_data=pd.read_excel(r'test_data.xlsx')
test_data=new_unknow_data
plt.scatter(true_data.iloc[13:,]['ID'],true_data.iloc[13:,]['Sales Revenue'])
sns.lineplot(true_data.iloc[13:,]['ID'],true_data.iloc[13:,]['Sales Revenue'])
plt.plot(true_data.iloc[13:,]['ID'],test_data['Online Rate'])
plt.scatter(true_data.iloc[13:,]['ID'],test_data['Online Rate'])
#sns.lineplot(true_data.iloc[13:,]['ID'],test_data['Online Rate'])
if __name__=='__main__':
main()
在练习中小编还将预测出来的结果进行了个可视化,发现其实效果一般般,还凑合吧,有时间的话再改进改进...