我的机器学习之旅(五):K近邻算法(KNN)

原理:

存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

KNN的一般流程:

(1)收集数据集,特征和类别标签

(2)准备数据,数据的归一化,去除坏数据等

(3)构造输入数据集,运用KNN判定数据的分类类别

(4)计算错误率,获得比较合适的K值

(5)输入需要预测分类的数据集

乳腺癌判断实例:

(1)获取数据:

import pandas as pd
import numpy as np

name_c=['sample code number','clump thickness', 'uniformity of cell size', 'uniformity of cell shape','marginal adhesion','single epithelial cell',
       'bare nuclei','bland chromatin','normal nucleoli','mitoses','class'
       ]
data=pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data',names=name_c)
data=data.replace(to_replace='?',value=np.nan)
data=data.dropna(how='any')

l=[] 
###第7列数据是字符形式,这里为了简便就不要那一列了
for i in name_c[1:10]: 
    l.append(data[i ].values) if i!=name_c[6] else 0

(2)数据处理:

#数据归一化函数
def
autoNorm(dataSet): #获得数据的最大最小值 print ("**********************") minVals = dataSet.min(0) maxVals = dataSet.max(0) print ("minValues:",minVals) print ("maxValuse:",maxVals) #计算最大最小值的差 ranges = maxVals - minVals #shape(dataSet)返回dataSet的矩阵行列数 normDataSet=np.zeros(np.shape(dataSet)) #返回dataSet的行数 m = dataSet.shape[0] #原始值减去最小值 normDataSet=dataSet-np.tile(minVals,(m,1)) #除以最大值和最小值的差,得到的归一化的数据 normDataSet = normDataSet/np.tile(ranges,(m,1)) print (normDataSet) return normDataSet,ranges,minVals


(3)kNN算法,计算欧式距离,选择距离最小的前k个点,并返回分类结果。

def classify(intX,dataSet,labels,k):
    '''
    KNN算法
    '''
    #numpy中shape[0]返回数组的行数,shape[1]返回列数
    dataSetSize = dataSet.shape[0]
    #将intX在横向重复dataSetSize次,纵向重复1次
    #例如intX=([1,2])--->([[1,2],[1,2],[1,2],[1,2]])便于后面计算
    diffMat = np.tile(intX,(dataSetSize,1))-dataSet
    #二维特征相减后乘方
    sqdifMax = diffMat**2
    #计算距离
    seqDistances = sqdifMax.sum(axis=1)
    distances = seqDistances**0.5
    #print ("distances:",distances)
    #返回distance中元素从小到大排序后的索引
    sortDistance = distances.argsort()
    #print ("sortDistance:",sortDistance)
    classCount = {}
    for i in range(k):
        #取出前k个元素的类别
        voteLabel = labels[sortDistance[i]]
        classCount[voteLabel] = classCount.get(voteLabel,0)+1
    #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
    #计算类别次数

    #key=operator.itemgetter(1)根据字典的值进行排序
    #key=operator.itemgetter(0)根据字典的键进行排序
    #reverse降序排序字典
    sortedClassCount = sorted(classCount.items(),key = operator.itemgetter(1),reverse = True)
    #print(intX)
    print ("sortedClassCount:",sortedClassCount)
    return sortedClassCount[0][0]

(4)数据的分类测试  

def datingClassTest(datingDataMat,datingLabels,k=10):
    #取所有数据的10%
    hoRatio = 0.1
    #数据归一化,返回归一化后的矩阵,数据范围,数据最小值
    normMat,ranges,minVals = autoNorm(datingDataMat)
    #获得nornMat的行数
    m = normMat.shape[0]
    #百分之十的测试数据的个数
    numTestVecs = int(m*hoRatio)
    #分类错误计数
    errorCount = 0.0

    for i in range(numTestVecs):
        #前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集
        classifierResult = classify(normMat[i,:],normMat[numTestVecs:m,:],
            datingLabels[numTestVecs:m],k)
        print ("分类结果:%d 	真实类别:%d"%(classifierResult,datingLabels[i]))
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print ("错误率:%f"%(errorCount/float(numTestVecs)*100))
datingClassTest(np.array(l).T,data[name_c[10]].values,10)

 缺点:如果数据大,需要耗费大量内存和运算时间。无法给出分类的典型特征。

原文地址:https://www.cnblogs.com/allenren/p/8657379.html