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

记录一下最近学习的最简单的k-近邻算法入门。
文章和别人的相似甚至神似,为什么会这样呢?因为是踩着前人的肩膀过来的吖。

1. 何为 k-近邻算法

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。
该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。

2. 实现原理与优缺点

用官方的话来说,所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。
换句话说就是: 样本已知属性、新样本暂未知属性。先求出两点之间的距离,新样本的属性即为 离样本最近的样本属性。

以下关于k-近邻算法的优缺点引自–机器学习–K近邻 (KNN)算法的原理及优缺点。

算法优点:

  1. 简单,易于理解,易于实现,无需估计参数。
  2. 训练时间为零。它没有显示的训练,不像其它有监督的算法会用训练集train一个模型(也就是拟合一个函数),然后验证集或测试集用该模型分类。KNN只是把样本保存起来,收到测试数据时再处理,所以KNN训练时间为零。
  3. KNN可以处理分类问题,同时天然可以处理多分类问题,适合对稀有事件进行分类。
  4. 特别适合于多分类问题(multi-modal,对象具有多个类别标签), KNN比SVM的表现要好。
  5. KNN还可以处理回归问题,也就是预测。
  6. 和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感。

算法缺点

  1. 计算量太大,尤其是特征数非常多的时候。每一个待分类文本都要计算它到全体已知样本的距离,才能得到它的第K个最近邻点。
  2. 可理解性差,无法给出像决策树那样的规则。
  3. 是慵懒散学习方法,基本上不学习,导致预测时速度比起逻辑回归之类的算法慢。
  4. 样本不平衡的时候,对稀有类别的预测准确率低。当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。
  5. 对训练数据依赖度特别大,对训练数据的容错性太差。如果训练数据集中,有一两个数据是错误的,刚刚好又在需要分类的数值的旁边,这样就会直接导致预测的数据的不准确。

3. 代码示例

先看下面一个例子,分类主要依据是X轴和Y轴的数值。(不严谨之处,请谅解)
在这里插入图片描述在这里插入图片描述
在这里会用到高中时候学习的两点之间的距离公式,当然了,这里的距离是二维坐标。
在这里插入图片描述
有黄色A和绿色B两类样本数据,现在新增了一个星号数据,那么这个星号数据是从属于哪一类呢?
虽然看上去就是属于A类,但是只要看上去那这篇文章就毫无意义了。
下面用代码来实现一下。
首先是样本数据集。

import numpy as np


# dataset()为训练数据集
def dataset():
    """
    :return: 返回样本数据以及标签
    """
	# dataset_为训练数据集, lables为数据集对应的标签
    dataset_ = np.array([[10, 10], [17, 20], [20, 30], [100, 80], [110, 70], [120, 90]])
    lables = ['A', 'A', 'A', 'B', 'B', 'B']
    return dataset_, lables

python实现 k-近邻算法。

def classify_knn(new_array, dataset, lables, k):
    """
    :param new_array: 新实例
    :param dataset:   训练数据集
    :param lables:    训练集标签
    :param k:         最近的邻居数目
    :return:          返回算法处理后的结果
    """
    # np.shape是取数据有多少组,然后生成tile生成与训练数据组相同数量的数据
    # 然后取平方
    # np.sum(axis=1) 取行内值相加,然后开发,求出两点之间的距离
    datasetsize = dataset.shape[0]
    diffmat = np.tile(new_array, (datasetsize, 1)) - dataset
    sqrdiffmat = diffmat ** 2
    distance = sqrdiffmat.sum(axis=1) ** 0.5

    # np.argsort将数值从小到大排序输出索引
    # dict的get返回指定键的值,如果值不在字典中返回默认值。
    # 根据排序结果的索引值返回靠近的前k个标签
    sortdistance = distance.argsort()
    count = {}
    for i in range(k):
        volelable = lables[sortdistance[i]]
        count[volelable] = count.get(volelable, 0) + 1
    count_list = sorted(count.items(), key=lambda x: x[1], reverse=True)
    return count_list[0][0]
    

if __name__ == '__main__':
    dataset, lables = dataset()
    result = classify_knn([40, 50], dataset, lables, 5)
    print(result)	# A

星号坐标为[10, 50]时候,返回的结果为A
星号坐标为[100, 10]时候,返回的结果为B
bingo!!!

4. 总结

三个步骤:

  1. 准备训练数据集
  2. 计算新的实例与训练数据集最邻近的K个实例
  3. 得出结果

因为个人功底太差,这个机器学习入门的k-近邻算法我花了好几个小时才弄明白一丢丢。说出来真是贻笑大方。
文章有错漏之处,恳请各位不吝指正。
完。

发布了34 篇原创文章 · 获赞 210 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_45081575/article/details/103578815
今日推荐