机器学习实战--k邻近算法

k邻近算法基于距离的测量,选取距离最近的特征值,即为预测的结果。该算法是一种监督算法,基于大量数据的基础上,做出相应的预测,一般运用于手写数字识别,约会网站的大量数据匹配等等。

其优点是:精度高,对异常值不敏感,无数据输入假定

其缺点是:计算复杂度高,空间复杂度高

适用数据范围是:数值型和标称型

 

首先,需要导入需要的库

from numpy import *
import operator

接着创建一个数据集

def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])    #生成一个数组
    labels = ['A','A','B','B']       #表示数据对应的属性,列表方式存储
    return group,labels

通过

group,labels = createDataSet()
print(‘group= ’ ,group)
print('labels= ',labels)

可以得到以下结果:

                                                                    

即基本的k邻近算法基本需要以上两种:数据集和对应的属性特征

 

k邻近算法的实现:

def classify0(inX,dataSet,labels,k):    #k代表选取前k个距离最近的点
    dataSetSize = dataSet.shape[0]       #获得该数据集的行数

    '''tile(A,rep) 功能是重复A的各个维度 A指所有类 rep指各个维度重复次数
    rep中 若仅一个数字表示列方向复制n次 '''

    diffMat = tile(inX,(dataSetSize,1)) - dataSet 

    #以下计算最短距离  
    sqDiffMat = diffMat **2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances **0.5

    sortedDistIndicies = distances.argsort()  #argsort通过调用获得距离由小至大在原数组中的下标

    classCount = {}    #新建一个字典
    for i in range(dataSetSize):    
        #依次取出最小距离下标对应的特征属性
        votelabels = labels[sortedDistIndicies[i]] 
   
        #字典的get方法默认参数,当该字典存在则执行加1,否则添加字典,并默认为后一个参数的值
        classCount[vote] = classCount.get(votelabels,0) + 1 
   
    #按照大小排序,得到的是由大至小的排序,需要对reverse赋值True,得到由小至大的序列
    sortedClassCount = sorted(classCount.item(),key=operator.itemgetter(1),reverse=True)
    
    return sortedClassCount[0][0]    #返回距离最小的元素标签

1、书上提供了一个示例,通过对约会网站的数据分析,在输入相应的信息之后,自动匹配结果

注:约会数据存放在datingTestSet.txt中,最后一行数据是文本类型,在datingTestSet2.txt中转换为int类型,所以接下来使用的是datingTestSet2.txt

该样本主要包含以下3种特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所耗时间百分比
  • 每周消费的冰淇淋公升数

所以,要创建名为file2matrix函数处理输入格式的问题

先来看看datingTestSet2.txt中的内容:

                                                           

前三列分别是我们所需要的数据,最后一列是特征属性,file2matrix函数如下:

def file2matrix(filename):
    fr = open(filename)
    array0lines = fr.readlines()
    numberOfLines = len(array0lines)    #得到文件行数
    returnMat = zeros((numberOfLines,3))    #创建返回的Numpy矩阵,此为零矩阵(文件行数,3列)
    classLabelVector = []
    index = 0
    for line in array0lines:

        #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
        line = line.strip() 

        # print(line)
        listFromLine = line.split('\t')  #以制表符(即不使用表格下在垂直方向按列对齐文本)分开
                                        #使用tab字符\t将上一步得到的整行数据分割成一个元素列表
        # print(listFromLine)

        returnMat[index,:] = listFromLine[0:3]  #选取前3个元素存储到特征矩阵中
        # print(returnMat[index,1])

        classLabelVector.append(int(listFromLine[-1]))  #将列表的最后一列存储到向量                                            
                                                        #classLabelVector中
        # print(classLabelVector)
        index +=1
    return returnMat,classLabelVector

处理以后的数据如下:

                                                          

归一化

上图中的数据参差不齐,值较大和值较小的数在计算过程中会产生较大的误差,所以我们必须采取某种方法使得数据处于0到1,或者是-1到1之间,简称归一化。

可由以下公式所得:

newValue = (oldValue - min) / (max - min)

我们创建一个autoNorm函数进行归一化的处理

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   

对上面数据进行归一化处理得到如下结果:

                                                

 

通过各个部分的功能实现,已经可以实现对约会网站数据的预测,接下来是预测函数的编写。

def classifyPerson():
    resultList = ['not at all','in small doses','in large doses']    #特征属性,表明你的态度
    percentTats = float(input('percentage of time spent playing video games? '))
    ffMiles = float(input('frequent flier miles earned per year? '))
    iceCream = float(input('liters of ice cream consumed per year?'))
    datingDataSet,datingLabels = file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDataSet)
    inArr = array([ffMiles,percentTats,iceCream])
    classifierResult = classify0((inArr - minVals)/ranges),normMat,datingLabels,3)
    print('You will probably like this person: ',resultList[classifierResult - 1])

总代码如下:

from numpy import *
import operator

def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group,labels

def classify0(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX,(dataSetSize,1)) - dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances **0.5
    sortedDistIndicies = distances.argsort()
    # print('sortedDistancesindics:',sortedDistIndicies)
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        # print(voteIlabel)
        classCount[voteIlabel] = classCount.get(voteIlabel,0) +1
    # print(classCount)
    sortedClassCount = sorted(classCount.items(),key = operator.itemgetter(1),reverse=True)
    # print(sortedClassCount)
    return sortedClassCount[0][0]

def file2matrix(filename):
    fr = open(filename)
    array0lines = fr.readlines()
    numberOfLines = len(array0lines)
    returnMat = zeros((numberOfLines,3))
    classLabelVector = []
    index = 0

    for line in array0lines:
        line = line.strip()
        # print(line)
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index +=1
    # print(returnMat)
    # print(classLabelVector)
    return returnMat,classLabelVector

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    # print(minVals)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    # print(normDataSet)
    m = dataSet.shape[0]
    # print(m)
    normDataSet = dataSet - tile(minVals,(m,1))
    # print(tile(minVals,(m,1)))
    normDataSet = normDataSet/tile(ranges,(m,1))
    # print(normDataSet)
    return normDataSet,ranges,minVals

def datingClassTest():
    hoRatio = 0.10
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    errorCount = 0.0
    m = datingDataMat.shape[0]
    numTestVecs = int(m * hoRatio)
    for i in range(numTestVecs):
        # print(normMat[numTestVecs:m,:])
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print('the classfierResult 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)))

def classifyPerson():
    resultList = ['not at all','in small doses','in large doses']
    percentTats = float(input('percentage of 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])

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值