python机器学习——k-近邻算法

本文的项目是参照《机器学习实战》中的“约会网站配对效果”来实现的。进行了一些改变,并进行了更详细的说明。

k-近邻算法:准备大量的数据样本,然后计算目标向量(即需要预测的数据)和各个样本之间的“距离”, 取前k个数据中存在最多的标签做为目标向量的标签。

需要的包:numpy,operator,matplotlib

from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt

方法介绍顺序:

预测数据——>读文件——>绘图——>归一化——>测试——>工程化

 

一、classify0()

功能说明:
    通过比较,获取数据的预测值
参数说明:
    输入向量inX, 训练样本集dataSet, 向量标签labels, k值
公式:
    \sqrt{\left ( x_{2}-x_{1} \right )^{2}+(y_{2}-y_{1})^{2}}
开发思路和步骤:
    1、获取训练样本集的总条数
    2、用过tile方法,让inX变为数量与训练样本相同的矩阵,并和训练样本集矩阵相减,获得一个新的矩阵
    3、新获取的矩阵进行平方
    4、对相减的数据进行相加
    5、对相加后的数据进行开方
    6、将获取的数据从小到大进行排序,并获得其下标
    7、循环遍历k个数据,判断最多的值
    8、返回输出
方法总结:
    1、shape[0]:
        用于获取矩阵的长度,0表示行(矩阵中有多少条数据),1表示列(每条数据几个字段)
    2、tile:
        将向量进行重复,并分别进行操作
        tile(list,x)列重复
        tile(list,(y,x)),行重复y次,列重复x次
    3、sum(axis=1):
        Numpy中的sum表示对矩阵进行求和,axis=0表是列求和,axis=1表示行求和
    4、argsort():
        将数组从小到大排序的索引返回为一个新的数据
    5、items():
        获取对象的迭代器(用于遍历)
        在python2中使用iteritems() 
    6、itemgetter():
        operator.itemgetter函数
        operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号。看下面的例子
        a = [1,2,3] 
        >>> b=operator.itemgetter(1)      //定义函数b,获取对象的第1个域的值
        >>> b(a)
    7、get():
        获取字典的某个值。get(x,y)中x表示字典的索引,y表示默认值。

def classify0(inX, dataSetMat, labels, k):
    dataSize = dataSetMat.shape[0]
    shotDataMat = (((tile(inX,(dataSize,1))-dataSetMat)**2).sum(axis=1))**0.5
    shotDataMatIndex = shotDataMat.argsort()
    labelDict = {}
    for i in range(k):
        label = labels[shotDataMatIndex[i]]
        labelDict[label] = labelDict.get(label,0)+1
    resultList = sorted(labelDict.items(),key=operator.itemgetter(1),reverse=True)
    return resultList[0][0]

二、fileToMatrix()

功能说明:
    读取文件,获取到训练样本矩阵
参数说明:
    filename,文件所在路径
公式:无
开发思路和步骤:
    1、读取文件
    2、将文件按行转为数组
    3、根据文件中所包含的属性个数(需要使用的)以及数据条数,创建一个矩阵
    4、创建一个数组,用于存放标签向量集合
    5、处理数据,并返回值
方法总结:
    open():
        根据路径,打开一个文件
    readlines():
        返回列表,包含所有的行。
    zeros(shape,dtype,order):
        shape:(行,列)
        dtype:
            t ,位域,如t4代表4位
            b,布尔值,true or false
            i,整数,如i8(64位)
            u,无符号整数,u8(64位)
            f,浮点数,f8(64位)
            c,浮点负数,
            o,对象,
            s,a,字符串,s24
            u,unicode,u24
        order:可选参数,c代表与c语言类似,行优先;F代表列优先
        创建一个0组成的矩阵、
    strip():
        清除数组前后的空格、回车
    xxx[index,:]:
        一个二维数组中,第一纬度的第index个。类似于取xxx[index]
遇到问题:
    报错:
        list indices must be integers or slices, not tuple
    代码:
        file_mat[index,:] = f_list[0,3]
    修改代码:
        file_mat[index,:] = f_list[0:3]
    错误分析:
        mat中不能接收字符串类型的数据,只可以是int或者slices。而不能是元组(字符串就是元组)
        原因,取数组的区间,要使用:而不是, !!

def fileToMatrix(filename):
    file = open(filename)
    file_list = file.readlines()
    file_count = len(file_list)
    file_mat = zeros((file_count,3))
    labels = []
    index = 0
    for f in file_list:
        f = f.strip()
        f_list = f.split("\t")
        #file_mat[index,:] = f_list[0,3]
        file_mat[index,:] = f_list[0:3]
        labels.append(int(f_list[3]))
        index+=1
    return file_mat, labels

三、drawMatplotlib()

功能说明:
    绘制散点图
参数说明:
    matrix为展示的矩阵,labels为矩阵的向量标签,x轴的值对应的索引,y轴的值对应的索引
公式:无
开发思路:无
方法总结:

    1、figure():
        创建一个图形实例
    2、add_subplot(x,y,z):
        将画布分成x行y列,图在从左到右从上到下的第z块
    3、scatter(x, y):
        绘制散点图
    4、show:
        展示图形

def drawMatplotlib(matrix,labels,x,y):
    fg = plt.figure()
    pic = fg.add_subplot(111)
    pic.scatter(matrix[:,x],matrix[:,y],15*array(labels),15.0*array(labels))
    fg.show()

四、autoNorm()

功能说明:
    数据归一化:
        按照之前的计算方式,当某一项数值存在的差值过大的时候,就会严重的影响到结果。
    而正常情况下,我们是不希望出现这种严重影响结果的数据(除非本身就想这样的)
    所以我们通过一个算法,将它固定在一个0~1这样的范围里,如此就可以公平的比较。
参数说明:
    matrix需要归一化的矩阵
公式:
    val = (val-min)/(max+min)
开发思路:
    1、获取矩阵最大值、最小值的矩阵
    2、求最大值、最小值的差
    3、创建一个新的矩阵
    4、通过公式计算,将新的矩阵赋值到矩阵中
方法总结:
    1、mat.min(0)/mat.max(0):
        必须加0!
        获取矩阵中每一列的最大/小值,并返回一个矩阵

def autoNorm(matrix):
    #val_min = matrix.min()
    #val_max = matrix.max()
    val_min = matrix.min(0)
    val_max = matrix.max(0)
    ranges = val_max-val_min
    result_mat = zeros(shape(matrix))
    #up_val = tile(matrix,(matrix.shape[0],1))
    up_val = matrix-tile(val_min,(matrix.shape[0],1))
    #zero_matrix = up_val/ranges
    result_mat = up_val/tile(ranges,(matrix.shape[0],1))
    return result_mat,ranges,val_min

五、studingTest()

方法说明:
    针对学习集,按照百分比进行拆分。前X%做为目标向量,剩余数据做为样本数据,对学习算法进行测试
参数说明:
    filename为样本数据文件路径。percent为百分比
公式:无
开发思路:

    1、调用fileToMatrix方法获取矩阵和标签
    2、将所有矩阵中的数据进行归一化处理
    3、循环前percent个数据,与样本数据进行比较测试,获取准确率
方法总结:无
思路分析:

    疑问:dataLabels为什么是一个数组,怎么和矩阵进行对比?
    答:在循环遍历的过程中,还是通过索引i来查询。而矩阵中的横向只是数据的属性。
        所以labels通过一个单一的数组就可以对应上

def studingTest(filename, percent, k):
    dataMat,dataLabels = fileToMatrix(filename)
    dataNormMat, _, _= autoNorm(dataMat)
    data_len = dataNormMat.shape[0] 
    testNum = int(percent*data_len)
    errorNum = 0
    for i in range(testNum):
        test_result = classify0(dataNormMat[i,:],dataNormMat[testNum+1:],dataLabels[testNum+1:], k)#
        print("old value  = {}, test value  = {}".format(dataLabels[i],test_result))    
        if test_result != dataLabels[i]:
            errorNum+=1
    print("errorNum={},percent={}".format(errorNum,errorNum/testNum))

六、classifyPerson()

方法说明:
    传入一个person字典,包含mile,ice,play三个属性
参数说明:
    person字典,包含mile,ice,play三个属性
公式:无
开发思路:

    1、将person变为向量
    2、获取样本数据
    3、对比
        --向量归一化
    4、输出
方法总结:无
问题总结:

    1、传入的person属性都需要为float类型
    2、比较的时候必须将目标向量也归一化
    3、目标向量的归一化不能直接调用autoNorm方法,而是要用样本矩阵所返回的min和ranges来计算

def classifyPerson(filename,person, k):
    person_vec = array([person.get('mile'),person.get('play'),person.get('ice')])
    data_mat,data_labels = fileToMatrix(filename)
    data_norm_mat,ranges,min_val = autoNorm(data_mat)
    rs = classify0((person_vec-min_val)/ranges,data_norm_mat,data_labels,k)
    print(rs)

 

最后是执行代码的主函数:

if __name__ =="__main__":
    person = {'mile':float(10000),'ice':float(1),'play':float(1)}
    classifyPerson('datingTestSet2.txt',person,5)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值