机器学习-kNN

机器学习-kNN

本节介绍机器学习中比较简单的一种监督学习算法,kNN算法,以及其Python实现。

部分内容引用自《Machine Learning in Action》


概述

监督学习

明确知道想要得到什么。例如判断某辆机动车的类型(小车,卡车,公交车),预测明天是下雨,天晴还是多云,对某个曲线做拟合等等。如果目标变量是离散型,则使用分类算法,如果目标变量是连续型,则可以使用回归算法。

无监督学习

不需要预测目标变量的值。如果需要将数据划分为离散的组,可以使用聚类算法。如果还需要估计数据与每个分组的相似程度,则需要使用密度估计算法。

kNN简介

kNN(k nearest neighbor)k近邻算法,是一种简单的监督学习算法,其可以非常高效的对目标变量做分组,从而判断其类型。基本思想是找出目标变量与数据集中最相似的k个数据,再找出这k个数据中次数最多的那个类别,该类别就是原目标变量的类别。

算法流程

  1. 计算目标变量和数据集中所有点的距离(空间中两个点的距离公式,略)
  2. 按照距离递增排序
  3. 选取前k个点
  4. 确定前k个点所在类别的出现概率
  5. 返回概率最高的那个点作为目标变量的类别

实例

假设二维空间中有四个点,[1, 1.1], [1, 1], [0, 0], [0, 0.1],其类别分别为 ['A', 'A', 'B', 'B'],求点 [0.9, 0.9]和点[0.2, 0.2]的类别。

先画一个图,直观查看这几个点的位置:

通过直觉,可以看出 [0.9, 0.9]距离右上两个点最近,而右上两个点的类别是A,所以 [0.9, 0.9]的类别应该也是A。同理,[0.2, 0.2]的类别应该是B

下面通过Python实现kNN,

import operator

import matplotlib.pyplot as plt
import numpy as np


def create_dataset():
    group = np.array([[1, 1.1], [1, 1], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


def classify(in_x, data_set, labels, k):
    # shape returns a tuple which means the size of each dimensions,
    # 0 represents the first dimension, 1 represents the 2nd dimension
    data_set_size = data_set.shape[0]
    if k >= data_set_size:
        k = data_set_size
    # np.tile() is used to extend a matrix on each dimension
    tmp_mat = np.tile(in_x, (data_set_size, 1)) - data_set
    tmp_mat = tmp_mat ** 2
    # sum() is used to calculate sum on given dimension
    tmp_mat = tmp_mat.sum(axis=1)
    tmp_mat = tmp_mat ** 0.5
    print("Distance of point %r to each data set: %r" % (in_x, tmp_mat))
    # argsort() means sort elements, but returns key not the element
    tmp_mat = tmp_mat.argsort()

    label_count = {}
    for i in range(k):
        label = labels[tmp_mat[i]]
        label_count[label] = label_count.get(label, 0) + 1
    # print(label_count.items())
    # => [('B', 2), ('A', 1)]
    # Sort the elements in a dict by the second item of each element
    sorted_label_count = sorted(label_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_label_count[0][0]


def test():
    group, labels = create_dataset()
    test_point1 = (0.9, 0.9)
    label1 = classify(test_point1, group, labels, 3)
    print("Lable of point %r is %r" % (test_point1, label1))

    test_point2 = (0.2, 0.2)
    label2 = classify(test_point2, group, labels, 3)
    print("Lable of point %r is %r" % (test_point2, label2))

    plt.title("kNN demo")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.plot(group[:, 0], group[:, 1], 'ob')
    plt.plot(test_point1[0], test_point1[1], 'or')
    plt.plot(test_point2[0], test_point2[1], 'oy')
    plt.show()


if __name__ == '__main__':
    test()

运行结果:

D:\work\python_workspace\machine_learning\venv\Scripts\python.exe D:/work/python_workspace/machine_learning/kNN/kNN.py
Distance of point (0.9, 0.9) to each data set: array([0.2236068 , 0.14142136, 1.27279221, 1.20415946])
Lable of point (0.9, 0.9) is 'A'
Distance of point (0.2, 0.2) to each data set: array([1.20415946, 1.13137085, 0.28284271, 0.2236068 ])
Lable of point (0.2, 0.2) is 'B'

Process finished with exit code 0

上面的实例仅仅展示了kNN的算法思想和Python实现,真实场景中不会出现上面实例中这么简单的数据。真实场景往往非常复杂,例如数据集可能包含成千上万的数据元素,每个元素的属性有很多(几十上百甚至上千),属性可能有多种类型(数值型,非数值型)等等。

对于数值型属性,往往需要做归一化处理,常见的一种方式是将数据转化到0和1之间,

new\_value = (old\_value - min)/(max - min)

对于非数值属性,需要对其编码,使其转换为数值类型。

归一化和编码是两个比较重要的话题,后面会专门展开讨论,这里就不再赘述了。

kNN优缺点

kNN是分类算法中最简单最有效的算法,无论是思想还是编码实现都很容易掌握,在数据量比较小的情况下是非常高效的。但它也存在一些缺点,例如(1)如果数据集很大,我们就必须使用很多的存储空间,(2)每次判断某个分类时都要计算到所有点的距离,因此需要很多的计算资源,(3)每次判断某个分类的计算都是独立的,无法给出数据集的任何基础结构信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值