kNN算法
1.准备带有标签的数据(需要转换成矩阵格式)
2.提供一个待分类的数据
3.求待分类数据与每一个带标签的数据的”距离“
4.选取“距离”最小的k个带标签数据
5.求k个数据中出现频率最高的数据得出分类结果
python 代码实现
from numpy import *
import operator
#inX为待分类数据,dataSet为数据,labels为标签
def classify0(inX,dataSet,labels,k):
'''求距离'''
#将inX整体复制成为(dataSet.shape[0],1)的矩阵
#dataSet.shape[0]表示dataSet行数目
diffMat=dataSet-tile(inX,(dataSet.shape[0],1))
#每个元素平方
squMat=diffMat**2
#对每一行求和,axis=1表示变化范围是列,即对行求和
sumMat=squMat.sum(axis=1)
#每个元素开平方
distances=sumMat**0.5
'''排序'''
#对distances排序,得出从小到大排序的索引号(方便求标签号)
sortedIndexs=distances.argsort()
#构建一个类,用作字典
classCount={}
for i in range(k):
#构造字典,get(键,默认值)表示取字典对应键的值
#没有则取默认值,整体效果为对k个最小标签进行频率统计
classCount[labels[sortedIndexs[i]]=...
classCount.get(labels[sortedIndexs[i],0)+1
#排序,items返回(键,值)二元组
#itmgetter(1)表示按照值排序
#reverse=True表示降序排列
sortedclassCount=sorted(classCount.items(),...
key=operator.itmgetter(1),reverse=True)
return sortedclassCount[0][0]
#数据测试
group=array([[1,1],[1,1.1],[0,0],[0,0.1]])
labels=['a','a','b','b']
classify0([0.0.2],group,labels,3)
实例:约会网站配对
1.数据读取(截取一部分数据,在本文末尾,名为datingTestSet2.txt)
'''
将前三列数据导入数据矩阵,将最后一列数据导入标签列表
将这个函数加入kNN模块,即上面那个函数
'''
def file2matrix(filename):
fr=open(filename)
arrayofLines=fr.readlines()
#初始化0矩阵
returnMat=zeros((len(arrayofLines),3))
#初始化列表
classLabel=[]
index=0
for line in arrayOLines:
#将line两端的'\n','\t'等空白字符消去
line=line.strip()
#以tab为分割,将line分为一个列表
listFromLine=line.split('\t')
#将前三列数据导入数据矩阵
returnMat[index,:]=listFromLine[0:3]
#将最后一列数据导入标签列表
classLabel.append(int(listFromLine[-1]))
index+=1
return returnMat,classLabel
2.归一化数值
由于要计算差值,而第一列数值由于远大于另外两列,对结果影响很大,
为了消除这种影响,需要进行归一化数值,将结果映射为0-1的数字
'''
归一化算法newValue=(oldValue-min)/(max-min)
'''
def autoNorm(dataSet):
minVals=dataSet.min(0)
maxVals=dataSet.max(0)
ranges=maxVals-minVals
normDataSet=zeros(shape(dataSet))
m=dataSet.shape[0]#返回行数目
normDataSet=dataSet-tile(minVals,(m,1))
normDataSet=normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
3.算法测试,错误率计算
每发现一个错误,计数器+1,错误率=错误数/总测试数
def datingClassTest():
hoRatio=0.1#选取测试数据的比例
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
normMat,ranges,minVals=autoNorm(datingDataMat)
m=normMat.shape[0]
numTestVecs=int(m*hoRatio)
errorCount=0.0
for i in range(numTestVecs):
classifierResult=classify0(normMat[i,:],\
normMat[numTestVecs:m,:],\
datingLabel[numTestVecs:m],3)
print ("the classifier came back with:%d,\
the real answer is:%d"\
%(classifierResult,datingLabels[i]))
if(classifierResult != datingLabels[i]):
errorCount += 1.0
print("the total error rate is : %f"\
%(errorCount/float(numTestVecs)))
4.程序运用
def classifyPerson():
resultList=['not at all','in small doses','in large doses']
percentTats=float(input("percentageof time spent playing video games?"))
ffMiles=float(input("frequent flier miles earned per year?"))
iceCream=float(input("liters of ice cream consumed per year?"))
datingDataMat,datingLabels=file2matrix("datingTestSet2.txt")
normMat,ranges,minVals=autoNorm(datingDataMat)
inArr=array([ffMiles,percentTats,iceCream])
classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print("you will probably like this person:",resultList[classifierResult-1])
数据(简化版,复制到txt即可使用)
(仅复制数据即可,第一列代表每年飞行数
第二列代表玩游戏所占百分比,第三列代表冰淇淋每周消费量
第四列表示好感程度,3最大)
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
72993 10.141740 1.032955 1
35948 6.830792 1.213192 3
42666 13.276369 0.543880 3
67497 8.631577 0.749278 1
35483 12.273169 1.508053 3
50242 3.723498 0.831917 1
63275 8.385879 1.669485 1
5569 4.875435 0.728658 2
51052 4.680098 0.625224 1
77372 15.299570 0.331351 1
43673 1.889461 0.191283 1
61364 7.516754 1.269164 1
69673 14.239195 0.261333 1
15669 0.000000 1.250185 2
28488 10.528555 1.304844 3
6487 3.540265 0.822483 2
37708 2.991551 0.833920 1
22620 5.297865 0.638306 2
28782 6.593803 0.187108 3
19739 2.816760 1.686209 2
36788 12.458258 0.649617 3
5741 0.000000 1.656418 2
28567 9.968648 0.731232 3
6808 1.364838 0.640103 2
41611 0.230453 1.151996 1