zoukankan      html  css  js  c++  java
  • 利用Python实现kNN算法

      邻近算法(k-NearestNeighbor) 是机器学习中的一种分类(classification)算法,也是机器学习中最简单的算法之一了。虽然很简单,但在解决特定问题时却能发挥很好的效果。因此,学习kNN算法是机器学习入门的一个很好的途径。

      kNN算法的思想非常的朴素,它选取k个离测试点最近的样本点,输出在这k个样本点中数量最多的标签(label)。我们假设每一个样本有m个特征值(property),则一个样本的可以用一个m维向量表示: X =( x1,x2,... x),  同样地,测试点的特征值也可表示成:Y =( y1,y2,... y)。那我们怎么定义这两者之间的“距离”呢?

      在二维空间中,有:d2 = ( x- y)2 + ( x- y),  在三维空间中,两点的距离被定义为:d2 = ( x- y)2 + ( x- y)2  + ( x3 - y)我们可以据此推广到m维空间中,定义m维空间的距离:d2 = ( x- y)2 + ( x- y)2  + ...... + ( xm - y)2 。要实现kNN算法,我们只需要计算出每一个样本点与测试点的距离,选取距离最近的k个样本,获取他们的标签(label) ,然后找出k个样本中数量最多的标签,返回该标签。

      在开始实现算法之前,我们要考虑一个问题,不同特征的特征值范围可能有很大的差别,例如,我们要分辨一个人的性别,一个女生的身高是1.70m,体重是60kg,一个男生的身高是1.80m,体重是70kg,而一个未知性别的人的身高是1.81m, 体重是64kg,这个人与女生数据点的“距离”的平方 d2 = ( 1.70 - 1.81 )2 + ( 60 - 64 )= 0.0121 + 16.0 = 16.0121,而与男生数据点的“距离”的平方d2 = ( 1.80 - 1.81 )2 + ( 70 - 64 )= 0.0001 + 36.0 = 36.0001 。可见,在这种情况下,身高差的平方相对于体重差的平方基本可以忽略不计,但是身高对于辨别性别来说是十分重要的。为了解决这个问题,就需要将数据标准化(normalize),把每一个特征值除以该特征的范围,保证标准化后每一个特征值都在0~1之间。我们写一个normData函数来执行标准化数据集的工作:

    1 def normData(dataSet):
    2     maxVals = dataSet.max(axis=0)
    3     minVals = dataSet.min(axis=0)
    4     ranges = maxVals - minVals
    5     retData = (dataSet - minVals) / ranges
    6     return retData, ranges, minVals

    然后开始实现kNN算法:

     1 def kNN(dataSet, labels, testData, k):
     2     distSquareMat = (dataSet - testData) ** 2 # 计算差值的平方
     3     distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和
     4     distances = distSquareSums ** 0.5 # 开根号,得出每个样本到测试点的距离
     5     sortedIndices = distances.argsort() # 排序,得到排序后的下标
     6     indices = sortedIndices[:k] # 取最小的k个
     7     labelCount = {} # 存储每个label的出现次数
     8     for i in indices:
     9         label = labels[i]
    10         labelCount[label] = labelCount.get(label, 0) + 1 # 次数加一
    11     sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) 
    12     # 对label出现的次数从大到小进行排序
    13     return sortedCount[0][0] # 返回出现次数最大的label

      注意,在testData作为参数传入kNN函数之前,需要经过标准化。

      我们用几个小数据验证一下kNN函数是否能正常工作:

    1 if __name__ == "__main__":
    2     dataSet = np.array([[2, 3], [6, 8]])
    3     normDataSet, ranges, minVals = normData(dataSet)
    4     labels = ['a', 'b']
    5     testData = np.array([3.9, 5.5])
    6     normTestData = (testData - minVals) / ranges
    7     result = kNN(normDataSet, labels, normTestData, 1)
    8     print(result)

      结果输出 a ,与预期结果一致。

    完整代码:

     1 import numpy as np
     2 from math import sqrt
     3 import operator as opt
     4 
     5 def normData(dataSet):
     6     maxVals = dataSet.max(axis=0)
     7     minVals = dataSet.min(axis=0)
     8     ranges = maxVals - minVals
     9     retData = (dataSet - minVals) / ranges
    10     return retData, ranges, minVals
    11 
    12 
    13 def kNN(dataSet, labels, testData, k):
    14     distSquareMat = (dataSet - testData) ** 2 # 计算差值的平方
    15     distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和
    16     distances = distSquareSums ** 0.5 # 开根号,得出每个样本到测试点的距离
    17     sortedIndices = distances.argsort() # 排序,得到排序后的下标
    18     indices = sortedIndices[:k] # 取最小的k个
    19     labelCount = {} # 存储每个label的出现次数
    20     for i in indices:
    21         label = labels[i]
    22         labelCount[label] = labelCount.get(label, 0) + 1 # 次数加一
    23     sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) # 对label出现的次数从大到小进行排序
    24     return sortedCount[0][0] # 返回出现次数最大的label
    25 
    26 
    27 
    28 if __name__ == "__main__":
    29     dataSet = np.array([[2, 3], [6, 8]])
    30     normDataSet, ranges, minVals = normData(dataSet)
    31     labels = ['a', 'b']
    32     testData = np.array([3.9, 5.5])
    33     normTestData = (testData - minVals) / ranges
    34     result = kNN(normDataSet, labels, normTestData, 1)
    35     print(result)
    View Code

     

  • 相关阅读:
    [].copyWithin.call({length:5,3:1},0,3)
    url、 src 和href 标签的区别
    http请求方法(GET、POST、HEAD、OPTIONS、PUT、DELETE、TRACE、CONNECT)
    windows环境下配置webpack
    typeof作用
    行内块之间存在间隙
    “DllRegisterServer的调用失败”问题解决办法
    SQL Server集群服务器的优缺点
    UTF8转成GB2312乱码问题解决思路
    什么是RFID技术
  • 原文地址:https://www.cnblogs.com/magic-girl/p/python-kNN.html
Copyright © 2011-2022 走看看