算法原理
KNN算法采用测量不同特征之间的距离方法进行分类,通俗的讲就是:给定一个样本数据集,并且样本集中每个数据都存在标签,即我们知道样本集中每个数据与所属分类的对应关系。对新输入没有标签的实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例的多数属于某个类,就把该输入实例分为这个类。
对于每一个在数据集中的数据点:
计算目标的数据点(需要分类的数据点)与该数据点的距离
将距离排序:从小到大
选取前K个最短距离
选取这K个中最多的分类类别
返回该类别来作为目标数据点的预测值
项目实例1:优化约会网站的配对效果
项目概述
海伦使用约会网站寻找约会对象。经历一段时间后,他发现曾交往过三种类型的人:
1:不喜欢的人
2:魅力一般的人
3:极具魅力的人
她希望:
1.不喜欢的人直接排除掉
2.工作日与魅力一般的人约会
3.周末与极具魅力的人约会
现在她收集到了一些约会网站上未曾记录的数据信息,这更有助于匹配对象的归类。
开发流程
Step1:收集数据
海伦把这些约会对象的数据存放在文本文件datingTestSet.txt中,总共有1000行。海伦约会的对象主要包含以下三种特征:
Col1:每年获得的飞行常客里程数
Col2:玩视频游戏所耗时间百分比
Col3:每周消费的冰淇淋公升数
文本文件数据格式如下:
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
38344 1.669788 0.134296 1
Step2:准备数据
使用Python解析文本文件。将文本记录转换为Numpy的解析程序如下所示:
import numpy as np
def file2matrix(filename):
"""
Desc:
导入训练数据
parameters:
filename:数据文件路径
return:
数据矩阵 returnMat和对应的类别 classLabelVector
"""
fr=open(filename)
#获得文件中数据行的行数
lines=fr.readlines()
numberOfLines=len(lines) #type:int
#生成对应的空矩阵
returnMat=np.zeros((numberOfLines,3))
classLabelVector=[]
index=0
for line in lines:
line=line.strip()
listFromLine=line.split('\t')
returnMat[index,:]=listFromLine[0:3]
classLabelVector.append(int(ListFromLine[-1]))
index+=1
return returnMat,classLabelVector
Step3:分析数据
使用Matplotlib化二维散点图
import matplotlib.pyplot as plt
if __name__=='__main__':
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
color=['r','g','b']
fig=plt.figure()
ax=fig.add_subplot(311)
for i in range(1,4):
index=np.where(np.array(datingLabels)==i)
ax.scatter(datingDataMat[index,0],datingDataMat[index,1],c=color[i-1],label=i)
plt.xlabel('Col.0')
plt.ylabel('Col.1')
plt.legend()
bx=fig.add_subplot(312)
for i in range(1,4):
index=np.where(np.array(datingLabels)==i)
bx.scatter(datingDataMat[index,0],datingDataMat[index,1],c=color[i-1],label=i)
plt.xlabel('Col.0')
plt.ylabel('Col.2')
plt.legend()
cx=fig.add_subplot(313)
for i in range(1,4):
index=np.where(np.array(datingLabels)==i)
cx.scatter(datingDataMat[index,0],datingDataMat[index,1],c=color[i-1],label=i)
plt.xlabel('Col.1')
plt.ylabel('Col.2')
plt.legend()
plt.show()
Step4:训练算法
此步骤不适用于K邻近算法。因为测试数据每一次都要与全部的训练数据进行比较,所以这个过程是没有必要的。
import opertor
def classfiy0(inX,dataSet,labels,k):
dataSetSize=dataSet.shape[0]
#距离度量 度量公式为欧氏距离
diffMat=np.tile(inX,(dataSetSize,1))-dataSet
sqDiffMat=diffMat**2
sqDistances=np.sum(sqDiffMat,axis=1)
distances=sqDistances**0.5
#将距离排序:从小到大
sortedDistIndicies=distances.argsort()
classCount={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
sortedClassCount=sorted(classCount.items(),key=opertor.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
Step:测试算法
计算错误率,使用海伦提供的部分数据作为测试样本。如果预测分类与实际类别不同,则标记为一个错误。
def datingClassTest():
"""
Desc:
对约会网站的测试方法
paramters:
none
return:
错误数
"""
#设置测试数据的一个比例
hoRatio=0.1#测试范围,一部分测试仪一部分作为样本
#从文件中加载数据
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
#归一化数据
normMat,ranges,minVals=autoNorm(datingDataMat)
m=normMat.shape[0]
numTestVecs=int(m*hoRatio)
print('numTestVecs=',numTestVecs)
errorCount=0.0
for i in range(numTestVecs):
classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m],3)
print("错误率:%f”%(errorCount/float(numTestVecs)))
print(errorCount)
Step6:使用算法
产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型
约会网站预测函数如下:
def classifyPerson():
resultList=['不喜欢的人‘,’魅力一般的人‘,’极具魅力的人‘】
ffMiles = float(input("每年获得的飞行常客里程数?"))
percentTats = float(input("玩视频游戏所耗时间百分比?"))
iceCream = float(input("每周消费的冰淇淋公升数?"))
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = np.array([ffMiles, percentTats, iceCream])
intX = (inArr - minVals) / ranges
classifierResult = classify0(intX, normMat, datingLabels, 3)
print("这个人属于: ", resultList[classifierResult - 1])