欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《机器学习实战》萌新入门笔记 ① — — K近邻算法 趣味讲解和书本实例详细注释后代码

程序员文章站 2022-05-02 14:02:45
...

开坑前言:大一在读新生开启了自己的机器学习之旅,从接触到现在已经有快两个月了,现在回过头为夯实基础,从开始看起《机器学习实战》这本书,即使是最简单的KNN算法,详细看过作者用python实现的代码后还能感觉到不少收获。开这个坑希望能分享一些经验给到更多一同在学习这本书的朋友,共同进步。

若本文有漏洞或者希望交流的朋友可以添加企鹅好友:27157812,欢迎大家指正。

本系列笔记正式开始:

故事引入:
首先!有一只小牛在网上冲浪,它正在找伴侣,于是在一个约会网站上搜啊搜。

由于约会网站很是发达也有些缺点,这只小牛在这个网站上找到了1000个可叫来约会的对象,但是对于这些对象只知道三个信息,分别是身高,体重,颜值(满分为10分)。

于是小牛把这1000个对象的信息储存在一个表格里,小牛和这1000个对象逐个叫来约会……

过了N年,小牛和1000个对象一一约会完毕。每个对象小牛都给出了一个喜爱程度,1是不喜爱,2是一般般,3是特别喜爱。

约会完以后,约会网站又给小牛分配了1000个新对象,但是这个小牛不想再通过约会来知道这些对象是不是他喜爱的了,他想通过约会网站给出的下一个对象的三个信息,来预估自己喜不喜欢下一个对象(如果不喜欢或者一般就不去约会了 )。

小牛根据之前1000个老对象的三个信息,和约会得出的喜不喜欢,建立了一个三维坐标轴,这三维分别是身高 体重 颜值,通过这三个维度,点出了每个对象在三维坐标系中所在的位置。

而每个对象都有对应的喜欢程度,而喜欢程度都对应一个颜色,不喜欢的就是灰色,一般般的就是蓝色,特别喜欢的就是红色,小牛由此建立了一个装载了1000个老对象的三维坐标空间。

小牛把新对象一个个放进坐标系中进行比较,根据三个信息确定了他们在空间里的位置,计算了新对象和所有老对象在空间坐标系中的距离。

再找到离这个新对象最近的10个老对象,看看他们是什么颜色的,如果距离最近的老对象们大多是红色的,那么新对象一定也差不到哪去,小牛笃定这个新对象一定是值得约会的!如果最近的老对象们大多是黑色的,小牛笃定这个新对象肯定很差劲,于是就根本不打算和这个差劲的新对象约会。


是不是非常简单易懂呀,实际上就是对于训练集(老对象们)建立了一组三维空间坐标系,根据几何距离的关系来对测试样本(新对象)的类别做出判断。
而KNN的算法是在本故事的基础上将问题上升到了n维空间中,而故事里边寻找的距离新对象最近的老对象的数量,指代的就是KNN中的K,如果K=1,算法就叫最近邻,K=3,算法就叫3近邻。


这里将书本上算法实现流程码在下面仅供参考:

对未知类别属性的数据集中的每个点依次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离
(2)按照距离递增次序排序
(3)选取与当前点距离最小的k个点
(4)确定前K个点所在类别的出现频率
(5)返回前K个点出现频率最高的类别作为当前点的预测分类

下面给出《机器学习实战》中,对于datingTestSet2.txt这一数据集实现绘制数据分析散点图和使用KNN算法预判类别功能的代码,(运行于版本最新的Python3.9):

这个代码需要结合书本来看,也就是说该代码对于有书的同学帮助较大。它是在原代码的基础上进行了优化和整合,将我注释的代码和源代码一一对应和比较更容易看懂~

这里给出各个函数对应的功能方便查阅:

  1. file_matrix 读入数据集
  2. classify0 实现KNN算法
  3. vasual_map 绘制数据分析图
  4. create_dataset 无视即可
from numpy import *
import operator
import matplotlib.pyplot as plt


def file_matrix(filename):
    fr = open(filename)
    # open()函数用于打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写
    array_in_line = fr.readlines()
    # file.readlines([size]) :返回包含size行的列表, size 未指定则返回全部行
    number_of_lines = len(array_in_line)
    # Python len() 方法返回对象(字符、列表、元组等)长度或项目个数。
    return_mat = zeros((number_of_lines, 3))
    # return_mat为len行,一行三元素的由零组成的数组,视为初始化样本数组
    class_label_vector = []
    index = 0
    for line in array_in_line:
        line = line.strip()
        # 去除该行的首尾空格
        list_from_line = line.split('\t')
        # \t为制表符,意为分割有空格分隔开的各元素
        return_mat[index, :] = list_from_line[0:3]
        # 注意,这里只取0 1 2个元素,不包括第三个元素,该数组即为读入的数据
        class_label_vector.append(int(list_from_line[-1]))
        # -1为最后一个元素,是每个样本的标签值
        # 注:必须有int注明为整数变量,否则将读入字符串型
        index += 1
    return return_mat, class_label_vector


def create_dataset():
    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(in_x, dataset, labels, kling):
    dataset_size = dataset.shape[0]
    # 获取训练集的大小
    diff_mat = tile(in_x, (dataset_size, 1)) - dataset
    # 将样本in_x按照dataset的大小纵向复制,(行,列),减去dataset代表各维度相减
    sq_diff_mat = diff_mat**2
    # 样本与测试集的各维度之差做平方
    sq_distances = sq_diff_mat.sum(axis=1)
    # axis=1代表跨行,axis=0代表跨列,这里表示计算样本与训练样本的各维度距离平方和
    distances = sq_distances**0.5
    # 计算样本与所有训练样本的距离
    sorted_dist_index = distances.argsort()
    # 返回对所有距离从小到大排序的索引值
    class_count = {}
    for i in range(kling):
        vote_label = labels[sorted_dist_index[i]]
        class_count[vote_label] = class_count.get(vote_label, 0) + 1
    # get(key, default=None)
    # 参数
    # key -- 字典中要查找的键。
    # default -- 如果指定键的值不存在时,返回该默认值。
    # 这里是选择距离最小的k个点
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    # sorted是对是所有可迭代的对象进行排序操作,items(原iteritems)是将字典以列表的形式返回,itemgetter是返回对象第一个域的值,reverse=Ture是是数据
    return sorted_class_count[0][0]
    # 最后返回排序后的第一个点


def vasual_map(datamat, datalabels):
    fig = plt.figure()
    # 创建自定义图像
    ax = fig.add_subplot(1, 2, 1)
    ay = fig.add_subplot(1, 2, 2)
    # add_subplot(x,y,z) 表示将图像划分为x行y列,此子图占据从左到右从上到下的第z个位置
    ax.scatter(datamat[:, 1], datamat[:, 2], 15.0*array(datalabels), 15.0*array(datalabels))
    ay.scatter(datamat[:, 0], datamat[:, 1], 15.0*array(datalabels), 15.0*array(datalabels))
    # 使用数据矩阵的第二列第三列数据来构建ax子图像,并利用datalabels储存的不同标签,在散点图上绘制了色彩不等,尺寸不同的点
    plt.show()


datingdatamat, datinglabels = file_matrix('datingTestSet2.txt')
vasual_map(datingdatamat, datinglabels)
forecast_class = classify0([35483, 12.273169, 1.508053], datingdatamat, datinglabels, 5)
print(forecast_class)

附上书上用代码绘制出的两个散点图:
《机器学习实战》萌新入门笔记 ① — — K近邻算法 趣味讲解和书本实例详细注释后代码


后续的笔记很快就会更新!也请用这本书学习的同学持续关注我哦。