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

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

 

二、一般流程:收集数据→准备数据→分析数据→测试算法→使用算法

 

三、使用python导入数据

python输出矩阵

from numpy import *

group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])

group输出为:

[[1.  1.1]
 [1.  1. ]
 [0.  0. ]
 [0.  0.1]]

group,shape[0] 输出为4

 

三、创建函数createDataSet()

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

 

四、k-近邻算法的伪代码:

对未知类别数学的数据集中的每个点依次执行以下操作

(1)计算已知类别数据集中的点与当前点之间的距离

(2)按照距离递增次序排序

(3)选取与当前点距离最小的k个点

(4)确定前k个点所在类别的出现频率

(5)返回前k个点出现频率最高的类别作为当前点的预测分类

 

五、k-近邻算法的python实现

 一些小的知识准备如下:

 (1)欧氏距离公式

 用来计算已知类别数据集中的点与当前点之间的距离

 

(2)numpy库中的tile()函数

第一个参数为数组,第二个参数可以是一个数字,大多数情况下是一个元组

a = array([0, 1, 2])
b = tile(a, (2, 1))
print(b)

//结果为
[[0, 1, 2],  
 [0, 1, 2]]

 

(3)numpy库中的argsort()函数

import numpy as np
 
a = np.array([[1,3,6],[9,5,6],[2,2,3]])
 
b = np.sum(a , axis=1)
 
sortindex = np.argsort(b)
print("%s+下标[0,1,2]" % b)
print(sortindex)

输出为:

[10 20 7]+下标[0 1 2]
[2 0 1]

 

(4)字典dictionary的get()用法

Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值

dict.get(key, default=None)

 

 (5)items()和iteritems()函数的用法

在写到

classCount.iteritems()

运行程序报错

 改为

classCount.items()

运行成功,查询资料后发现Python3中已不再支持iteritems(),将iteritems()改成items()

items()方法是将字典中的每个项分别做为元组,添加到一个列表中,形成了一个新的列表容器

 

(6)sorted()函数

sorted()函数对所有可迭代的对象进行排序操作。

 

与sort函数的区别:

sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。

语法:

sorted(iterable, cmp=None, key=None, reverse=False)

iterable -- 可迭代对象。

cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。

key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。

reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

 

(7)operator库中的itemgetter()函数

from operator import itemgetter
cutting_dim = 1
points = [(6,8), (1,2), (0, 0), (10, -5)]
points.sort(key=itemgetter(cutting_dim)) 
print(points) #[(10, -5), (0, 0), (1, 2), (6, 8)]

 


最终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


def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]  # 训练数据集的个数,本例中dataSetSize值为4
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet  # 利用tile函数计算出输入的数据集与已知数据集中每个数据的差值
    sqDiffMat = diffMat ** 2  # 求平方
    sqDistances = sqDiffMat.sum(axis=1)  # axis默认值为0,值为1时为将矩阵每一行的向量相加
    distance = sqDistances ** 0.5  # 开根号,得出欧氏距离
    sortedDistIndicies = distance.argsort()  # argsort函数对数组进行排序,并返回下标,默认从小到大

    classCount = {}  # 创建一个字典

    # 统计前k个点所在类别的出现频率
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    sortedClassCount = sorted(classCount.items(),
                              key=operator.itemgetter(1), reverse=True)
    # iteritems()返回一个迭代器,python3后无iteritems,变为items,将字典中的每个项作为元组,添加到一个列表中
    # 如{'A':2, 'B':1} 变为 [(A, 2), (B, 1)]
    
    return sortedClassCount[0][0]  # 返回出现频率最高的类别


group, labels = createDataSet()
inX1 = [0, 0]

b = classify0(inX1, group, labels, 3)
print(b)  # 本例输出结果为B

代码来自机器学习实战P19,注释是根据自己的理解来写的,希望能对大家有所帮助。

 

posted @ 2020-03-01 16:43  _Cheung  阅读(208)  评论(0编辑  收藏  举报