《Machine Learning in Action》—— 女同学问Taoye,KNN应该怎么玩才能通关

《Machine Learning in Action》—— 女同学问Taoye,KNN应该怎么玩才能通关

女同学问Taoye,KNN应该怎么玩才能通关???某问得,给这位妮子安排上!

这篇是机器学习系列文章所涉及到的第六篇文章了,前面已经介绍过了支持向量机SVM以及决策树算法,一个躲在小房间里认真阅读过的读者应该对他们都有了一定的认识,算法的过程和原理也都大致了解了。

这篇文章我们来看看K-近邻(KNN)算法,关于KNN算法,由于比较的简单,没有SVM那么复杂的公式和过程,所以会肝一篇文章来结束。

更多机器学习系列文章,欢迎各位朋友关注微信公众号:玩世不恭的Coder

本篇文章主要包括以下几个部分的内容:

  • 什么是K-近邻算法(KNN),通过一个关于电影分类的小案例帮助大家快速认识KNN
  • 基于KNN实现约会网站的对象配对,通过KNN来找对象,岂不是美滋滋
  • 基于KNN实现手写数字识别系统,机器学习/深度学习领域的Hello World

一、什么是K-近邻算法(KNN)

简单地说,K-近邻算法采用测量不同特征值之间的距离方法进行分类。它的优点是精度高、对异常值不敏感、无数据输入假定。缺点是时间复杂度和空间复杂度高。主要适用于数值型和标称型数据范围。

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

这是啥意思呢???通俗的解释一哈吧

假如现在我有两类数据集,数据集数目是总共100个。现在有一个新的数据集,我们应该将其归于哪一类呢???

是酱紫的,首先会将这个新的数据与这100个数据分别计算“距离”(这个距离后面详细讲),然后选取前K个最小的数据,在这K个中统计哪类数据样本数最多,则将这个新的数据归于哪一类。

我们来尝试一下通过KNN来对电影类别进行分类吧。例子来源:《机器学习实战》

有人曾经统计过很多电影的打斗镜头和接吻镜头数目,以此来判别该电影是动作片还是爱情片。(注意:该例中只存在这两种电影类别,不存在其他类别,也不存在爱情动作片)。下图显示的是6部电影的打斗和接吻镜头数。假如有一部未看过的电影,如何确定它是动作片还是爱情片呢???

首先我们需要明确的是这六部电影的各个属性特征值,也就是打斗镜头和接吻镜头的数目,具体数据如下表所示:

根据我们上述所说的原理那样,即使我们不知道未知电影的实际类别,我们也可以通过某种方法计算出来。

首先,计算未知电影与其他六部电影的“距离”,该距离的计算有多种方式,它主要用来体现的是两个样本的之间的相似度。在这里,我们主要采用的是欧式距离来表示,具体如下:

\[L(x_i,x_j) = \sqrt{\sum_{l=1}^N|x_i^{(l)}-x_j^{(l)}|^2} \]

当然了,在机器学习的学习过程中,我们会与多种距离公式有邂逅的机会,至于其他“距离”,我们用到了再来提及。对此,我们对未知样本与其他六个样本之间分别计算欧式距离,得到的距离结果如下所示:

现在我们得到了样本集中所有电影与未知电影的距离,按照距离的递增排序,可以找到K个距离最近的电影。假设,这里我们取K=5,则我们可以发现在这五个样本中,有三个样本的类别为爱情片,有两个类别为动作片,所以我们理应将这部未知电影归类于爱情片

以上内容,就是K-近邻算法的原理以及过程,想必读者对KNN已经有了一定的了解,下面我们不妨通过代码来实现上述的KNN分类过程

首先第一步当然是准备数据集了,为此我们定义一个establish_data方法,分别返回属性特征和对应的标签:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 用于生成样本的属性特征以及对应的标签
    Return:
        x_data: 数据样本的属性,其中包括两个属性
        y_label: 样本属性所对应的标签
"""
def establish_data():
    x_data = np.array([[3, 104], [2, 100], [1, 81],
                      [101, 10], [99, 5], [98, 2]])
    y_label = np.array(["爱情片", "爱情片", "爱情片", "动作片", "动作片", "动作片"])
    return x_data, y_label

其次,定义knn_classification方法通过KNN原理和思想来实现分类,这里简单介绍几个点:

  • np.sqrt(np.power((np.tile(in_data, [data_number, 1]) - x_data), 2).sum(axis=1)),该代码就是根据公式来计算与各自样本之间的距离,在操作过程中要熟练Numpy的使用,具体可参考之前Taoye整理出的一篇文章:print( "Hello,NumPy!" )
  • distance.argsort(),该代码中的argsort()返回时数组从小到大的索引,比如在这里返回的结果是[1, 2, 0, 3, 4, 5],意思是最小值的索引为1,其次索引为2。这个方法要尤其注意。
  • class_count.get(label, 0),字典的get方法传入第二个参数代表的是,假如字典没有这个key,那就默认其value为0
  • sorted(class_count.items(), key=operator.itemgetter(1), reverse=True),前面我们不是已经获得了结果字典么,但是我们最终需要的是数量的最多的,所以还需要通过sorted对其进行排序

具体代码如下:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: KNN的核心分类方法
    Parameters:
        in_data: 目标分类样本
        x_data: 已知标签的样本属性特征
        y_label:样本标签
        k:K-近邻当中的k,也就是自定义的超参数
    Return:
        result: 最终的分类结果
"""
def knn_classification(in_data, x_data, y_label, k):
    data_number, _ = x_data.shape
    distance = np.sqrt(np.power((np.tile(in_data, [data_number, 1]) - x_data), 2).sum(axis=1))
    print("计算出的距离为:", distance)
    distance = distance.argsort()    # 返回的是[1, 2, 0, 3, 4, 5],意思是最小的在索引为1,其次索引为2
    class_count = dict()
    for index in range(k):
        label = y_label[distance[index]]
        class_count[label] = class_count.get(label, 0) + 1
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    print("分类结果为:%s, 该类型数量为:%d,其中k=%d" % (sorted_class_count[0][0], sorted_class_count[0][1], k))
    return sorted_class_count[0][0]

代码运行结果如下所示:

程序运行结果与我们手动推导KNN的原理结果如出一辙,完美,哈哈哈!!!

完整代码:

import numpy as np
import operator

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 用于生成样本的属性特征以及对应的标签
    Return:
        x_data: 数据样本的属性,其中包括两个属性
        y_label: 样本属性所对应的标签
"""
def establish_data():
    x_data = np.array([[3, 104], [2, 100], [1, 81],
                      [101, 10], [99, 5], [98, 2]])
    y_label = np.array(["爱情片", "爱情片", "爱情片", "动作片", "动作片", "动作片"])
    return x_data, y_label

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: KNN的核心分类方法
    Parameters:
        in_data: 目标分类样本
        x_data: 已知标签的样本属性特征
        y_label:样本标签
        k:K-近邻当中的k,也就是自定义的超参数
    Return:
        result: 最终的分类结果
"""
def knn_classification(in_data, x_data, y_label, k):
    data_number, _ = x_data.shape
    distance = np.sqrt(np.power((np.tile(in_data, [data_number, 1]) - x_data), 2).sum(axis=1))
    print("计算出的距离为:", distance)
    distance = distance.argsort()    # 返回的是[1, 2, 0, 3, 4, 5],意思是最小的在索引为1,其次索引为2
    class_count = dict()
    for index in range(k):
        label = y_label[distance[index]]
        class_count[label] = class_count.get(label, 0) + 1
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    print("分类结果为:%s, 该类型数量为:%d,其中k=%d" % (sorted_class_count[0][0], sorted_class_count[0][1], k))
    return sorted_class_count[0][0]
    
if __name__ == "__main__":
    x_data, y_label = establish_data()
    print("分类结果为:", knn_classification(np.array([18, 90]), x_data, y_label, 5))

二、基于KNN实现约会网站的对象配对

上面我们已经通过KNN实现了一个小小的案例,接下来看看如何对约会网站实现对象配对的功能。

参考资料:《机器学习实战》

海伦一直使用在线约会网站寻找适合自己的约会对象,尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结。他发现曾交往过三种类型的人:

  • 不喜欢的人
  • 一般般、马马虎虎、还行吧,这个人
  • 哇撒,这个对象太帅了,我一定要约出来

海伦为了邀约比较满意的对象,也是煞费苦心啊。她收集数据已经有了一段时间,她把这些数据存放在文本文件 datingTestSet2.txt中,每个样本数据占据一行,总共有1000行。海伦收集的样本主要包含以下3中特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所耗时间百分比
  • 每周消费的冰淇淋公升数

部分数据如下图所示:

搞不懂,真的搞不懂。从以上三个海伦判别对象的属性来看,海伦比较看重对象的飞行里程、游戏时间、冰淇淋???

换句话说,海伦可能不是个花痴,而是个吃货。

不管了,不管了,既然数据集给出的是这个,那就用这个数据集吧。

老规矩,首先需要准备数据集。

我们定义一个establish_data方法来从txt文件中读取数据并通过numpy进行返回,方法的代码如下:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 用于生成样本的属性特征以及对应的标签
    Parameters:
        file_name: 样本数据所在的文件名称
    Return:
        x_data:属性特征
        y_label:标签
"""
def establish_data(file_name):
    f = open(file_name)
    line_datas = f.readlines(); data_number = len(line_datas)
    x_data, y_label = list(), list()
    for line_data in line_datas:
        line_data_list = line_data.split("\t")
        x_data.append(line_data_list[:-1])
        y_label.append(line_data_list[-1].strip())
    return np.array(x_data, dtype = np.float32), np.array(y_label, dtype = np.float32)

上述方法中的代码还是挺简单的,主要是从文件中读取数据,然后将数据保存至ndarray中并返回,运行的结果数据如下所示:

现在已经从文本文件中导入了数据,并将其格式转化为我们想要的格式,接着我们需要了解数据表达的真实含义。当然我们可以直接浏览文本文件,但是这种方法不是特别的友好,我们不妨对上述数据进行一定的可视化,以便更好的观察数据属性特征与结果之间的关系。

上述数据可视化代码如下:

from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据可视化
"""
def show_result(x_data, y_label, axis, scatter_index):
    plt.subplot(2, 2, scatter_index)
    plt.scatter(x_data[:, axis[0]], x_data[:, axis[1]], c = y_label)
    font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
    label_list = ["每年获得的飞行常客里程数", "玩视频游戏所耗时间百分比", "每周所消耗的冰淇淋公升数"]
    plt.xlabel(label_list[axis[0]], FontProperties = font); plt.ylabel(label_list[axis[1]], FontProperties = font)

if __name__ == "__main__":
    x_data, y_label = establish_data("./datingTestSet2.txt")
    show_result(x_data, y_label, [0, 1], 1)
    show_result(x_data, y_label, [0, 2], 2)
    show_result(x_data, y_label, [1, 2], 3)
    plt.show()

可视化结果如下所示:

上述是三个属性特征两两配对的散点图,其中紫色代表不喜欢,绿色代表一般般,而黄色代表超级喜欢。从可视化的结果来看,我们大致可以做出如下推论:

  • 海伦比较喜欢有生活质量不错的对象,但是也不能常年在外飞行,毕竟对象的身体还是比较看重的嘛
  • 海伦还比较喜欢玩游戏时间占比相对比较多的对象,游戏时间长 -> 对象可能是个王者 -> 可以带带海伦这个青铜,这不美滋滋嘛,从这可以看到海伦可能也是的个游戏痴狂者,但奈何游戏技术不咋地,所以希望找个能带她飞的对象。
  • 至于冰淇淋,这个属性特征嘛,感觉海伦对这个没有特别高的要求,只要每天有的吃就行。

从欧氏距离的公式来看,属性特征中数字差值最大的属性对计算结果的影响会比较大,也就是说,每年获取的飞行常客里程数对于计算结果的影响将远远大于其他两个属性特征对结果的影响,但对于海伦来讲,这三个的属性特征没有什么大小之分,因此我们需要对数据进行一个归一化处理,尽可能减小属性特征对分类结果的影响差距。我们通常采用的是数值归一化,将数值区间转换到0-1或-1-1之间,我们不妨通过以下公式来进行归一化处理:

\[new\_value = \frac{old\_value-min\_value}{max\_value} \]

对此,我们定义一个normaliza_data方法来实现归一化功能:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据归一化
"""
def normalize_data(x_data, y_data):
    data_number, _ = x_data.shape
    min_data, max_data = np.tile(x_data.min(axis = 0), [data_number, 1]), np.tile(x_data.max(axis = 0), [data_number, 1])
    new_x_data = (x_data - min_data) / (max_data - min_data)
    return new_x_data, y_label

归一化结果如下所示:

一切准备就绪,接下来我们来看看knn的实际分类结果,定义一个calc_error_info方法,用来对数据进行预测并输出相关错误信息:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 对数据进行预测并输出相关错误信息
"""
def calc_error_info(x_data, y_data, info_text):
    error_count = 0
    for index in range(x_data.shape[0]):
        predict_result = knn_classification(x_data[index], x_data, y_label, 20)
        if (int(predict_result) != y_label[index]): error_count += 1
    print("%s预测错误的个数为:%d,错误率为:%f" % (info_text, error_count, error_count / 1000))

运行结果如下所示可,可见数据的归一化体现出的效果还是不错的:

完整代码:

import numpy as np
import operator

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 用于生成样本的属性特征以及对应的标签
    Parameters:
        file_name: 样本数据所在的文件名称
    Return:
        x_data:属性特征
        y_label:标签
"""
def establish_data(file_name):
    f = open(file_name)
    line_datas = f.readlines(); data_number = len(line_datas)
    x_data, y_label = list(), list()
    for line_data in line_datas:
        line_data_list = line_data.split("\t")
        x_data.append(line_data_list[:-1])
        y_label.append(line_data_list[-1].strip())
    return np.array(x_data, dtype = np.float32), np.array(y_label, dtype = np.float32)

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: KNN的核心分类方法
    Parameters:
        in_data: 目标分类样本
        x_data: 已知标签的样本属性特征
        y_label:样本标签
        k:K-近邻当中的k,也就是自定义的超参数
    Return:
        result: 最终的分类结果
"""
def knn_classification(in_data, x_data, y_label, k):
    data_number, _ = x_data.shape
    distance = np.sqrt(np.power((np.tile(in_data, [data_number, 1]) - x_data), 2).sum(axis=1))
    distance = distance.argsort()
    class_count = dict()
    for index in range(k):
        label = y_label[distance[index]]
        class_count[label] = class_count.get(label, 0) + 1
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_class_count[0][0]

from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据可视化
"""
def show_result(x_data, y_label, axis, scatter_index):
    plt.subplot(2, 2, scatter_index)
    plt.scatter(x_data[:, axis[0]], x_data[:, axis[1]], c = y_label)
    font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
    label_list = ["每年获得的飞行常客里程数", "玩视频游戏所耗时间百分比", "每周所消耗的冰淇淋公升数"]
    plt.xlabel(label_list[axis[0]], FontProperties = font); plt.ylabel(label_list[axis[1]], FontProperties = font)

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据归一化
"""
def normalize_data(x_data, y_data):
    data_number, _ = x_data.shape
    min_data, max_data = np.tile(x_data.min(axis = 0), [data_number, 1]), np.tile(x_data.max(axis = 0), [data_number, 1])
    new_x_data = (x_data - min_data) / (max_data - min_data)
    return new_x_data, y_label

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 对数据进行预测并输出相关错误信息
"""
def calc_error_info(x_data, y_data, info_text):
    error_count = 0
    for index in range(x_data.shape[0]):
        predict_result = knn_classification(x_data[index], x_data, y_label, 20)
        if (int(predict_result) != y_label[index]): error_count += 1
    print("%s预测错误的个数为:%d,错误率为:%f" % (info_text, error_count, error_count / 1000))

if __name__ == "__main__":
    x_data, y_label = establish_data("./datingTestSet2.txt")
    norm_x_data, norm_y_label = normalize_data(x_data, y_label)
    calc_error_info(x_data, y_label, "归一化数据之前:")
    calc_error_info(norm_x_data, norm_y_label, "归一化数据之后:")

三、基于KNN实现手写数字识别系统

读到这里,是不是可以感觉到KNN其实并没有那么难???

还是挺简单的,对吧???

接下来,我们再通过KNN实现一个手写数字识别系统。

我们都知道,在我们没学习一门语言的时候,都会来一波print("Hello world!"),而在机器学习或者深度学习领域中,手写数字识别就相当于Hello world!的存在。

在trainingDigits目录下包含了大约2000个数字txt文本,每个例子中的内容如下图酱紫,每个数字0-9大约有200个样本;testDigits目录下包含了900个测试数据,数据如同trainingDigits下的样本;我们使用trainingDigits中的数据作为数据训练分类器,使用testDigits目录中的数据测试分类器的效果,两组数据没有重叠。

数据可来此处下载:https://pan.baidu.com/s/1o8qC6PqFGxuhRUbwUYHjQA 密码:u4ac

老规矩,同样的,我们需要定义一个establish_data方法来准备数据,但是在此之前,我们需要对数据进行一定处理,由于我们数字文本txt文件中的内容是一个32x32的,而对于KNN来讲,每一个样本都应该是一个特征向量的形式,所以我们需要将32x32的数据转化成1x1024的向量,也就是将其拉平,对此,定义一个flatten_digit_data方法来实现这个功能:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 将数字txt文本文件内容拉伸
    Parameters:
        file_name: 样本数据所在的文件名称
    Return:
        x_data:属性特征
        y_label:标签
"""
def flatten_digit_data(digit_file_name):
    flatten_digit = list(); f = open(digit_file_name)
    for index in range(32):
        for j in range(32): flatten_digit.extend(list(f.readline())[:-1])
    return np.array(flatten_digit, dtype = np.int32)

接下来定义establish_data方法来整合数据,将多个数字文件转化为一个m x 1024的矩阵,矩阵中的每个行代表一个样本,每个样本1024个属性特征,总共有m个样本,这里我们需要导入os模块以方便操作文件夹,establish_data具体代码如下:

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据准备方法,将所有数字文本转换成矩阵形式
    Parameters:
        digit_file_name: 单个数字文本文件的名称
    Return:
        flatten_digiy:转换成行向量之后的样本
"""
def establish_data(folder_name):
    import os
    y_label = list(); file_names = os.listdir(folder_name)
    x_data = np.zeros([len(file_names), 1024])
    for index, file_name in enumerate(file_names):
        y_label.append(file_name.split("_")[0])
        x_data[index] = flatten_digit_data(folder_name + file_name)
    return x_data, np.array(y_label, dtype = np.int32)

后面就是实现knn_classificationcalc_error_info方法了,方法具体代码内容与前面的大体相同,只需稍作修改即可,KNN实现手写数字识别的完整代码如下:

import numpy as np

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 将数字txt文本文件内容拉伸
    Parameters:
        digit_file_name: 单个数字文本文件的名称
    Return:
        flatten_digiy:转换成行向量之后的样本
"""
def flatten_digit_data(digit_file_name):
    flatten_digit = list(); f = open(digit_file_name)
    for index in range(32):
        for j in range(32): flatten_digit.extend(list(f.readline())[:-1])
    return np.array(flatten_digit, dtype = np.int32)

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 数据准备方法,将所有数字文本转换成矩阵形式
    Parameters:
        digit_file_name: 单个数字文本文件的名称
    Return:
        flatten_digiy:转换成行向量之后的样本
"""
def establish_data(folder_name):
    import os
    y_label = list(); file_names = os.listdir(folder_name)
    x_data = np.zeros([len(file_names), 1024])
    for index, file_name in enumerate(file_names):
        y_label.append(file_name.split("_")[0])
        x_data[index] = flatten_digit_data(folder_name + file_name)
    return x_data, np.array(y_label, dtype = np.int32)

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: KNN的核心分类方法
    Parameters:
        in_data: 目标分类样本
        x_data: 已知标签的样本属性特征
        y_label:样本标签
        k:K-近邻当中的k,也就是自定义的超参数
    Return:
        result: 最终的分类结果
"""
def knn_classification(in_data, x_data, y_label, k):
    data_number, _ = x_data.shape
    distance = np.sqrt(np.power((np.tile(in_data, [data_number, 1]) - x_data), 2).sum(axis=1))
    distance = distance.argsort()
    class_count = dict()
    for index in range(k):
        label = y_label[distance[index]]
        class_count[label] = class_count.get(label, 0) + 1
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_class_count[0][0]

"""
    Author: Taoye
    微信公众号: 玩世不恭的Coder
    Explain: 对数据进行预测并输出相关错误信息
"""
def calc_error_info(x_data, y_data, test_x_data, test_y_label, k):
    error_count = 0
    for index in range(test_y_label.shape[0]):
        predict_result = knn_classification(test_x_data[index], x_data, y_label, k)
        if (int(predict_result) != test_y_label[index]): 
            error_count += 1
            print("KNN预测错误,预测结果为:%d,真实结果为:%d" % (predict_result, test_y_label[index]))
    print("预测错误的个数为:%d,错误率为:%f" % (error_count, error_count / test_y_label.shape[0]))

if __name__ == "__main__":
    x_data, y_label = establish_data("./digits/trainingDigits/")
    test_x_data, test_y_label = establish_data("./digits/testDigits/")
    calc_error_info(x_data, y_label, test_x_data, test_y_label, 20)

完整代码运行结果如下所示:

可以看见,该KNN实现手写数字识别的效果还是可以的,测试数据总共有946个,其中预测错误了26个,错误率为2.7%,还行吧,这错误率~~~ 只是时间复杂度有点高了

另外,该模型测试结果是在k=20的前提下的得到的,读者可自行修改K参数的值,来进一步观察模型预测的错误率

KNN相关的内容就写到这里了,总体上来讲,KNN算法还是挺简单的,没有太多花里胡哨的东西,也没有多么复杂的公式,认真阅读的读者都能够将KNN吸收到位。

手撕机器学习系列文章目前已经更新了支持向量机SVM、决策树、K-近邻(KNN),但从后台数据上来看,受众结果不是很理想。的确,机器学习系列文章的受众人群实属有限,大多比较的枯燥乏味,没有前后端开发那么的香。

说归说,闹归闹。手撕机器学习系列文章,Taoye还是会继续肝下去的,下一篇算法应该是朴素贝叶斯了吧,敬请期待。

感觉一直更新机器学习系列文章有点对不起读者朋友,毕竟太枯燥了。本想写一篇关于如何霸屏微信运动榜首的爬虫文章,感觉这个大家会更感兴趣一点,但前几天用Fiddler抓取数据包的时候迟迟无果(之前还是可以抓取到的),也就只好暂时搁置了。11月1号抓取到的接口还是有效的,依然是可以正常修改步数的

这篇文章更不更,再看吧!

舍友小弟有点担心Taoye的秀发了,不过学习还是会保持的,文章还是会更新的,感谢每一位点进来阅读的朋友,

这篇文章就暂时写到这里吧,希望每一位进来的朋友都能够有所收获。(虽然粉丝不多)

我是Taoye,爱专研,爱分享,热衷于各种技术,学习之余喜欢下象棋、听音乐、聊动漫,希望借此一亩三分地记录自己的成长过程以及生活点滴,也希望能结实更多志同道合的圈内朋友,更多内容欢迎来访微信公主号:玩世不恭的Coder

我们下期再见,拜拜~~~

参考资料:

[1] 《机器学习实战》:Peter Harrington 人民邮电出版社
[2] 《统计学习方法》:李航 第二版 清华大学出版社

推荐阅读

《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机
《Machine Learning in Action》—— hao朋友,快来玩啊,决策树呦
《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”
《Machine Learning in Action》—— 剖析支持向量机,优化SMO
《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM
print( "Hello,NumPy!" )
干啥啥不行,吃饭第一名
Taoye渗透到一家黑平台总部,背后的真相细思极恐
《大话数据库》-SQL语句执行时,底层究竟做了什么小动作?
那些年,我们玩过的Git,真香
基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境

posted @ 2020-11-26 15:37  玩世不恭的Coder  阅读(136)  评论(0编辑  收藏  举报