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