机器学习算法之KNN算法(Python代码)

有数据如何作处理?

本文基于机器学习中监督学习算法下的KNN分类算法做详细介绍,个人总结,参考网络资源。

参考:Jack-Cherish/Machine-Learning

算法描述:

已经存在带标签的数据组(训练样本),当输入新的不带标签的数据时,与原样本数据的特征之间作比较,我们选取与样本最相似的数据的标签作为新输入数据的标签。在本算法中,事先给定k,即选择样本中的前k个数据作比较,看在这k个数据中对应的标签出现的频率,以出现频率最大的作为新数据标签值。

算法涉及的知识:

1、最相似数据的比较:

通过距离来判定相似程度,距离计算公式(欧式距离):

但是实际中会出现这样的情况,数据特征的标定可能有大有小,比如某产品销量很大,价格很低如销量100000,价格0.99元,如果这种特征代入计算会淹没价格的影响,所以我们需要事先对样本数据作归一化。

2、数据归一化:

归一化我们采用将同一特征下的数据全部转化为0~1之间的数值,一般简单的处理采用线性归一化公式:

max和min分别为特征数据的最大最小值。

下面基于“海伦约会”项目作为测试,整体代码及结果:

#-*- coding:utf-8 -*-
import numpy as np
import operator
#import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.font_manager import FontProperties

def file2matrix(fiename):
file=open(fiename)
data=file.readlines()
row=len(data)
P_Mat=np.zeros((row,3))###双括号,不然报错
index=0
label=[]
for line in data:
line_From=line.strip().split('\t')
P_Mat[index]=line_From[0:3]###list是从0开始计数,0,1,2
if line_From[-1]=='didntLike':
label.append(1)
elif line_From[-1]=='smallDoses':
label.append(2)
elif line_From[-1]=='largeDoses':
label.append(3)
index+=1
##转置
#label=np.array([label]).T
font=FontProperties(fname=r'c:\Windows\Fonts\simsun.ttc',size=10)
fig=plt.figure()
pic=fig.add_subplot(111,projection='3d')
pic.scatter(P_Mat[:,0],P_Mat[:,1],P_Mat[:,2])

pic.set_xlabel('每年获得的飞行常客里程数',FontProperties=font)
pic.set_ylabel('玩视频游戏所消耗时间比',FontProperties=font)
pic.set_zlabel('每周消耗冰淇淋公升数',FontProperties=font)
plt.show()
'''
plt.scatter(P_Mat[:,0],P_Mat[:,1],marker='o')
plt.show()
plt.scatter(P_Mat[:,0],P_Mat[:,2],marker='o')
plt.show()
plt.scatter(P_Mat[:,1],P_Mat[:,2],marker='o')
plt.show()
'''
##输出数据表格式,方便操作
#df=pd.DataFrame(np.hstack((P_Mat,label)),columns=['A','B','C','Label'])
return P_Mat,label

###数据归一化
def nomalFcn(dataSet):
##获取最大值
maxValue=dataSet.max(0)
##获取最小值
minValue=dataSet.min(0)
value=maxValue-minValue
num=np.shape(dataSet)
##(oldValue-min)
normData=dataSet-np.tile(minValue,(num[0],1))
##归一化(oldValue-min)/(max-min)
normData=normData/np.tile(value,(num[0],1))
return normData
##定义分类方法,输入变量分别为:输入数据,样本数据,标签,k值
def classfy(InMat,DataMatrix,Labels,k):
Data_Size=DataMatrix.shape[0]
difMat=np.tile(InMat,(Data_Size,1))-DataMatrix
#print(difMat)
sum_difMat=(difMat**2).sum(axis=1)
#print(sum_difMat)
dis=np.power(sum_difMat,0.5)
#print(dis)
sort_dis=dis.argsort()
labelCount={}
for i in range(k):
voteLabel=Labels[sort_dis[i]]
labelCount[voteLabel]=labelCount.get(voteLabel,0)+1

sort_labelCount=sorted(labelCount.items(),key=operator.itemgetter(1),reverse=True)
##取出sort_labelCount[0]是一个元组如('动作片',1),再从中取出标签
return sort_labelCount[0][0]
##主函数运行测试
if __name__=='__main__':
P_Mat0,label0=file2matrix('datingTestSet.txt')
nomalData=nomalFcn(P_Mat0)
r=0.10
error=0
m=P_Mat0.shape[0]
numTest=int(r*P_Mat0.shape[0])
for i in range(numTest):
result=classfy(nomalData[i],nomalData[numTest:m],label0[numTest:m],4)
print('分类结果:%d\t 真实结果:%d'%(result,label0[i]))
if result!=label0[i]:
error+=1.0

print('错误率:%f%%'%(error/float(numTest)*100))
print(error)
print(numTest)

测试结果:

发表评论

电子邮件地址不会被公开。 必填项已用*标注