本系列概述

核心内容是深度学习,只不过我们会进行代码实践,来巩固我们讲的概念的基础。会使用机器学习开发可以实际使用的工程项目,这也是我们这个系列跟其它机器学习最大区别的地方。

深度学习的意义

当然,不可能通过几个系列涉及深度学习的所有方法,所以我们重点关注的是近几年广泛得到运用的深度学习技术。可以预见的也是深度学习在现在或将来将会成为最有效的、最流行的机器学习方式之一。因为深度学习在这个海量数据的时代,已经被很多不同行业、不同企业、不同领域所应用。而且得到了印证,深度学习确实有用。可以解决很多实际的问题。比如说投行高盛、摩根士丹利都会使用深度学习技术去完善和加强他们的业务。深度学习在我们看来在机器学习领域是最火的,也将在未来火上很长很长时间。

系列简介

  • 基础篇
    什么是机器学习,机器学习的主要任务,解决什么样的问题。 部署后面会使用的开发环境。通过python去实现几个机器学习中的经典算法。让大家对整个机器学习领域有一个大致的了解。
    还会去介绍一些分类器,包括决策树、K-Means算法,Logistic回归、支持向量机、以及贝叶斯网络。

  • 神经网络篇
    以基础知识为导向跟大家介绍深度神经网络是怎么回事。

  • 深度学习篇
    了解什么是深度学习,将很多概念,用代码去跟大家展示。跟普通的文章有很大的区别。所以大家一定要把这个开发环境装好,我们会以实战为导向,带着大家一起去做。从我的角度来看,如果只了解机器学习是什么,了解了几个算法,然后不知道怎么去用,其实是很大的问题。

  • 高性能编程
    主要的概念讲完之后,我们会涉及到高性能编程,事实上深度学习很大程度上依赖于高性能计算。这一块我们会带着大家一起去入门C++,把在机器学习领域和深度学习相关的技术来很全面的给大家做一个介绍。主要在这里呢,我们就使用C++编程语言。也包括GPU的计算,我们完全会讲到,大家不用担心。

  • 编程实战篇
    重头戏来了,实时上我会抽象一个实际的产品给大家。当然我不能说原来的那个产品什么样子,这个产品是完全可以工作,也可以上线的。这个产品包含了前端、后端、以及客户端。这个就涉及到的东西非常多了,我们会非常全面的跟大家做一个讲解。
    这个系统分为两块,第一块是云端服务器,涉及到大数据和海量数据的实时处理和分析,除此之外呢,深度神经网络我们会去部署Caffe和Tensorflow这样的集群,然后去编写机器学习的代码,实现我们的这个深度神经网络的服务器。
    构建好这个服务器之后,我们肯定会去想,有了这个服务器之后,我们怎么去用呢。所以我们不仅会去开发一整套完整的从业务逻辑,到底层框架的组织架构,还有最底层的通信系统,我们都会有一个全面的介绍,跟大家讲一讲整个深度学习服务器到底是怎么构建起来的。所以说,大家如果经过这个编程实战篇之后,大家应该有一个非常完整的认知,就是深度神经网络怎么能解决我们现实的问题。那我们解决什么样的实际问题呢,我们会根据系列的推进,做一些调整。
    所以说,分两块,一块是服务器,一块是客户端,我们都会去做一个实现。


本篇主题

  • 机器学习基础:
    机器学习到底是什么,能解决什么样的问题,其实这个非常关键,机器学习现在非常火,但是它真正能解决什么问题呢,我们把它讲清楚。

  • 基本算法介绍:
    机器学习的基本算法做一个介绍,我们最后会使用深度神经网络的东西,在这之前会把机器学习的经典算法跟大家做一个介绍。让大家走进机器学习的世界,了解机器学习到底是什么样子。有这么一个全面的认识,在工程实践之前,这一点其实非常关键。

  • 基本模型入门:
    会带着大家做一个基本模型的入门,包括开发环境的搭建,会去实现一些经典的机器学习算法。

机器学习基础

应用场景

人脸识别
机场火车站的无人检票系统;
银行无人开户:放一张身份证,再用摄像头拍一张人脸,检验人脸和身份证是否一致;
人脸识别技术的发展已经可以一定程度上用机器来代替,人脸识别自然用机器学习去实现的。
无人驾驶
涉及到机器学习领域更多更广,完全不能说跟我们之前讲的是一套算法或机制。这里可能会涉及到图像识别、导航定位、驾驶辅助系统,不只是机器学习。除了百度无人驾驶,还有特斯拉。但离成熟距离还很远。
我们是站在机器学习爆发时代的前端,刚刚开始。很多技术爆发出来,但是离成熟还有很大的距离要走。
IT技术在这几年,硬件的发展、软件的发展可能会呈现一个爆炸式的增长。所以,大家现在去学习机器学习我个人觉得是非常好的时机。
医疗
使用机器学习做诊断的系统也越来越多。这也是目前一个热门评议。

什么是机器学习


人可以创造的东西是非常有限的—> 人希望从已知的信息中得到普遍的工具 —> 使用这些工具得到我们未知的但想要知道的信息。比如各种物理定律就是这个过程的产物。我们可以类比机器学习是这样大致的一个过程的产物。

从最简单的例子来说吧,大家只要学过最基础的统计学,大家肯定都知道。提到这个统计学大家可能会担心数学基础,觉得 统计学、概率论很长时间没有学了,大家不用担心,如果涉及到这方面内容,我们也会给大家去讲,不会说,让大家自己去看。

比如:如何知道某个厂生产的产品有多少个次品?

是不是通过简单的统计就可以做到呢。在这种情况下,我们往往会从实际的产品中抽取一定的样本,计算样本里的次品数量、计算样本里的次品频率。我们会假定样本和正式产品同分布。比如样品里有10件商品,1件次品,我们可以假定次品率10%。如果总共有100个产品,次品数量可以推断为10个。

大家想象一下这个过程,我们已知的是样本的情况,包含多少个工件,里面有多少个次品,还有整体的数量,这些信息是已知的。在这里我们将这些信息称作为原始数据。就是上图当中看到的原始数据,最后得出的是一个整体的数目。也就是说未知需要我们预测一个值。这是我们想要得到的信息。

这是一个简单的过程,我们用一个数学模型就已经解决问题了,所以说在还没有计算机的时候,我们解决这类问题完全使用数学模型来帮我们解决问题。而建立数学模型我们需要考虑系统当中所有的因素,并思考这些因素当中的逻辑关系。得到准确的数据公式。这个数学模型的本质也就是数学建模需要完成的任务。这种思路就是希望使用数学来描述我们现实当中的一切现象。用数学来抽象我们现实生活当中的一些问题。然后呢,通过这些模型来解决某个问题。虽然如此,数学很美,但是光使用数学,在现如今复杂的情况下呢,很多问题就解决不了。我们思考一个简单例子。

为何机器学习如此重要


机器学习出现的背景
天气预报,需要考虑的情况非常多,还需要进行趋势预测,在这种情况下,数学模型只能完成最基本的运算,如果想要更高的准确率呢,那数学模型其实早就力不从心了。

对于疾病的预测更是如此,人体是非常复杂的,一般我们使用数学模型的思路是观察我们的数据,然后使用数学工具呢,去人为的思考,抽象。去人工分析,并建立数学模型,但在这种情况下,人的精力是有限的,当遇到海量数据,去使用传统的人工抽象的方式肯定是不切实际的。那我们能不能让机器自己去观察它的数据呢。为了解决这个问题,机器学习也就出现了。

机器学习的思路
我有一定量的数据,那我就将人分析数学模型的过程转移给计算机,让计算机读取数据,并提取数据当中的一些特征,注意这里的特征,比如疾病预测里我们需要考虑到的因素,除了基本的各项身体健康指标以外,可能还要考虑各种基因的因素, 这些健康指标和基因其实都是一个特征。计算机所要做的就是提取这些特征。然后再寻找这些特征和我们想要的结果之间的关联关系。我们需要做的其实就是设计和寻找的范围,我们不能通过人的抽象思维直接得到一套算法,但是我们通过机器的帮助、通过机器学习来寻找这个算法,并使用程序来实现。具体如何寻找或者这个算法最后什么样子,那完全交给计算机去做。

所以大家考虑这个问题到底是什么样子的。

机器学习与原来程序开发的区别
我们现在解决问题或者编程的时候,我们先要预想这个问题该如何解决,通过人的思维去编写一套算法,去解决我们的问题。这个算法是由人的思维去编写的。这是现有的状况,那么,机器学习是怎么回事呢。

如果要处理现实世界当中特别复杂的问题,人的大脑肯定不够用了。 在很多时候无法推导出来现实生活中的模型。这种情况下我们需要借助机器学习技术去寻找这个算法,所以这里面大家看到最大的区别在哪里呢,原来我们是直接设计程序,现在算法太复杂,我们已经写不出来了,通过机器学习的方式去寻找这个算法。寻找到这个算法解决我们的实际问题。这就是机器学习最大的功能和任务。所以说为什么机器学习如此重要,因为我们现在需要解决的实际问题太复杂。通过人的思维已经无法去编写一个程序去解决问题了。我们需要一个特别特别复杂的机器学习算法。这个算法来交给机器学习技术来帮我们寻找。这就是机器学习和我们现有方式最大的区别。

本节小结
现在的趋势和未来发展的方向,我认为一定是往这个方向发展的。就是使用机器学习模型来替代我们传统的数学模型来解决现实问题。

那么为什么现在机器学习变的越来越重要,会取代数学模型地位呢。

一是因为现在人们需要解决的问题已经越来越复杂,很多问题数学模型已经无法胜任。

二是我们现在数据来源越来越丰富,而且数据量越来越大。俗话说:巧妇难为无米之炊。哪怕我们用了机器学习模型,但是没有数据,又有什么用呢,只不过现在呢刚刚迎上了大数据的风口浪尖。确定是最好的时代,所以大家这个时候学习机器学习的确是特别好的时机。

最后呢,为什么现在机器学习这么火呢,这也得益于现有机器性能的提升。在以前,很多机器学习无法使用的原因就是因为机器性能不够。比如深度神经网络,也就是我们这个系列最核心的概念。现在随着GPU性能的提升、异构运算、分布式计算的兴起,我们可以使用的资源就越来越多了,以前一个月需要处理的数据,现在可能几个小时就能处理完。

所以,现在我们用机器学习解决现实问题是极有可能,而且是真的有用。在以前,这种事情完全是天方夜谭。所以说机器学习技术是建立在大数据之上的。所以,在我们的系列当中也会跟大家去讲大数据处理和分析的实战。所以大家不用担心,我们会从最原本的东西跟大家去讲。

机器学习模型


首先我们了解一下机器学习的大致过程,然后我们再看看机器学习到底是什么。

模型就是机器帮我们生成的超级复杂的算法。模型是我们的产物之一,也是我们希望得到的那一个复杂的算法。
预测程序:即我们给机器测试数据,机器给我们答案,我们比较一下测试的正确答案和机器给出的答案,就可以给机器学习打一个分数,类似考试,分数就是最终测试的准确率,准确率也是用数据。但是机器可能需要几万道题,才能知道是否准确。

我们简单梳理一下大致流程
1. 我们会整理一系列数据,给训练程序,这些数据就叫做训练数据,
2. 我们再给训练程序制定一个现成的模型学习方法,训练程序就会乖乖根据我们的方法读入数据,并得到训练后的东西,这里这个模型我们可以抽象称为泛化的函数。它的作用就是输入一堆自变量。自变量是数据当中的特征。然后得到因变量,也就是问题的答案。理论上讲,我们就可以拿这个模型到生产环境当中去使用了。不过在这之前我们还有两个步骤要做。第一,输入训练数据,看看模型是否能得到正确的结果。如果第一步能做到,我们就考虑第二步,第二步是输入一堆测试数据,让模型给出结果,我们再来看看准确率到底如何。如果这两步当中有一步不满足,那我们只能换训练数据,也就是换课本了,课本和老师不行嘛,我要让机器学习重新去学,直到这两个步骤都满足为止,我们才认为这个模型是合格的。这个模型就是通过机器学习最终得到的结果,这个模型合不合格,我们需要通过这样的方式去验证。

一个问题:一个训练上表现良好的模型,到底效果好不好呢
其实不一定,如同课本会告诉我们1+1= 2;但不会告诉你9999+1 =10000,那我们要学会的方法本质呢是要举一反三,对于机器学习来说也是如此。机器呢,要从训练数据当中找其规律所在。注意这个规律,规律非常多,机器学习的关键就在于寻找这个规律。找到这个规律之后才能应用现实世界当中的实际问题。不然就成了一个只会做课本题目的傻学生了。只能解决我告诉他的问题,当我再给他一个类似的问题,看不懂。那这就不是我们机器学习最终想要达到的目的,这就不是机器学习。所以举一反三,发现规律非常重要。

但是现实当中的确有在训练和测试当中表现非常好,在现实当中又不怎么样的模型。我们将这种现象叫做过拟合。这个过拟合是一个术语,大家可以去记 。对于很多模型来说,如果我们给机器学习的数据量太少,我们就会出现过拟合的问题。它能考虑和学习的量太少,所以说无法满足我们的需求。这种情况就会出现过拟合。模型设计不当的话,给再多的数据也没有用,如果我们训练出的模型是过拟合的,也就没什么价值了,这也不是我们希望去做机器学习工作的目的。这种需求呢,我们称之为模型的范化能力。所以所有的客户在使用机器学习产品的时候,都需要使用自己的数据去验证模型的使用价值。当然了,如果你足够聪明,能够想得到,如果学生最弊,把学过的全部告诉老师,老师在试卷上都是对应他讲过的题。这个学生很高兴就得100分,那就更不用说机器了。这种情况我们称之为作弊。可以看到机器学习的很多概念都是跟我们生活中是一一对应的。非常相似,希望通过这样的方式让大家对机器学习有一个大致的了解。

大家可以看到机器学习就像一个黑盒子,在数学建模时代呢,我们必须非常清楚这个盒子里面的构造,还要知道盒子当中每个零件是怎么来的。而现在只需要有这个盒子,知道这个盒子的基本结构就行了,至于里面的零件和参数让机器自己去处理吧。因为这个算法和模型太复杂了,人已经无法理解了。让机器帮我们发现,我们也不需要知道这个参数具体学习校正的过程。

机器学习能解决什么问题

我们再来看机器学习模型里面的最后一个问题,机器学习可以用来解决什么样的问题或完成什么样的任务呢?

  1. 第一类问题叫做分类,机器学习可以帮我们做分类。
    比如:我们知道鸟的各个特征,现在要根据各个特征确定这只鸟属于哪种鸟类,这就是一个分类过程。比如现在有app—微软识话,去拍一张花,就可以知道这种花属于哪种花。这个属于机器学习的分类。

  2. 第二个就是机器学习可以帮我们做回归
    比如,我根据病人的身高体重等表征信息预测一下病人的血糖,看似这个问题很复杂,我们要自己写一套算法几乎是不可能完成的任务。所以我们用机器去写。这里呢血糖浓度是一个数值,表征信息属于特征,也是数值,这种对数值型数据的预测呢,我们就称为回归。回归的学习过程就是收集每一个病人的体征及血糖浓度,最后呢,我们通过回归学习,学习出一个模型,再让用户输入体征信息呢,就可以计算出血糖浓度。

这两类问题我们不仅需要提供原始数据里面的特征,注意这个特征,也是一个数据,我们后面会不断的去搞。还要提供每个样本的结果。也就是目标,机器学习是从特征到目标之间的映射关系。通过映射关系得到这套模型,或者人也看不懂的复杂算法,这种机器学习我们称之为监督学习

与之对应的是无监督学习,我们只需要提供样本的特征数据,比如刚刚我们提到的人体的表征信息,体重,血糖浓度这样的数值,把这些特征交给机器去做训练。不需要提供任何标签和对应的结果,机器学习就能训练出一个模型供我们使用。

无监督学习中的典型任务就是聚类。 比如说我给你一堆鸟的特征样本,不告诉你每一个只鸟对应哪个类,让你通过机器学习计算出哪些鸟属于哪一类,那这个问题是比刚才复杂的多了,最后生成的无监督学习的作用是什么呢,给你一只鸟,然后你预测一下这只鸟和训练数据集里面哪些鸟属于同一类。这种情况我们就称之为聚类。由于我们现实生活中收集的很多数据都没有做过数据的标注。所以聚类算法不仅可以用于数据的预测,还可以用于监督学习的数据预处理。也就是说预先给数据打上标签

基本算法介绍

首先了解两个无监督学习算法

聚类算法 — K-means


任务:从一些未标注的数据里面找出同类数据。

比如我给你一些鸟的特征,身高、体重、羽毛等,然后你告诉我哪些鸟是属于一类的,但是你不用告诉我这个鸟的类别叫什么,这个是机器学习不到的。

最常用的聚类算法就是K-means算法,中文K均值算法。

K-means算法计算逻辑

  1. 比如,有100只鸟,想分出五个类别,参数K就等于5,也就是创建分类,每只鸟代表1类,把100只鸟归到5个类里;
  2. 先选出五只鸟,这五只鸟代表各个品种的中心,也就是K个中心对象;
  3. 我们计算其他95只鸟和这五只鸟的距离,这个距离是抽象概念,我们通过鸟的一些特征得到的,我们后面会讲距离怎么计算。我们得到所有距离之后呢,我们看每只鸟和这5只鸟相比,距离是最小的,我认为距离最小的为一类。第一次分类之后会把这95只鸟全部分到这5类下面;
  4. 但是第一次分类大家认为不一定是最好的,机器学习的思路是不断迭代调整的过程,我们接着重新选取每个分类的中心对象。怎么选定呢,我们能就把这个分类里面所有求出来的值做一个平均数,比如把鸟的体重做个平均数,把鸟的翅膀长度做个平均数,把鸟的颜色做个平均数,然后就把所有鸟的平均数作为所谓的中心对象。
  5. K均值算法是让用户制定分几类,分K类,means:均值,我每次迭代都会在每个分类里面的数据对象取一个平均作为他的新的中心对象。我在拿着所有100只鸟去和五个新的中心对象做一个距离比较,我们再把这95只鸟分到新的最短距离里,做一个重分类。直到我第n次重分类和第n+1次重分类结果一样为止。

这中间缺少一步推导的过程,我们可以证明我们这个算法在数学上是收敛的算法。 这个讲到聚类算法时再简单的做个证明。

此算法的难点

  1. 我如何定义K,可能有五类,八类,我人是不知道这个K的,K如何选择是一个问题,
  2. 第二个是选中K之后如何选择中心对象,选择中心对象会导致后面训练有差距。
  3. 第三个两只鸟属性之间的距离函数怎么定义,这个最短距离怎么定义。

关联算法—Apriori


应用场景:关联规则算法,常常用于我们的一些推荐。

比如你去amazon买书,你买一本,它常常给你推荐第二本,关联规则起源于沃尔玛的啤酒与尿布的故事,他们发现很多人去买尿布的时候会顺便买瓶啤酒,把这两个东西放在一起销量就突飞猛进。

  • 这里面有两层关系:
    一、尿布和啤酒常常出现在一起;
    二、因为去买尿布所以买啤酒,他们存在一个因果关系。
    那么我怎么把这两层关系给分析出来呢,这就是我们关联规则算法,所关心的问题。我们现在介绍这个算法就能达到这个目的。

先介绍两个基本概念:支持度置信度
这个例子来自《机器学习时代》,比较有代表性

上图为一个超市某天的商品订单。

  1. 支持度:数据集中某个项集出现的频率;
    项集:一个数据项的集合,比如豆奶、莴苣就是一个包含两个数据项的项集。这个豆奶我们既可以看成一个数据项又可以看成一个包含一个数据项的项集。
    比如莴苣这个项集出现在4个订单里面,除以订单总数5,支持度就是4/5.橙汁的支持度就是2/5。
    支持度:反应项集在我们所有数据里出现的频繁程度。

  2. 置信度:关联规则的成立概率,置信度越大,关联规则的成立概率越高。反之,越小。
    弄清它们的因果关系,比如我是因为去买尿布才买啤酒,而不是相反的。
    我先计算豆奶+莴苣的支持度是3/5,去除以我关联规则的前导,就是我希望通过莴苣去推出豆奶。所以我去除以蜗居的支持度4/5,所以由蜗居推出豆奶的置信度是3/4,即75%。

支持度与置信度的作用

  • 支持度可以帮我们发现频繁项集。频繁在我们商品里出现的项集。
  • 置信度帮助我们发现关联规则,哪些之间是有因果关系的。

Apriori算法计算逻辑

  1. 我们首先设定支持度的值,也就是滤值;
  2. 遍历所有商品,计算每一个商品的支持度;
  3. 去掉所有我们预先设定的小于支持度的项,剩下的就是频繁出现的项集,它们就是所谓的频繁项集,只不过是包含一个数据的频繁项集;
  4. 接着进行组合,比如用一项集去组成一个二项集,计算所有二项集的支持度,再把二项集支持度里面低于滤值的全都去掉。如果说我还留下一些二项集,我再用二项集去组成三项集、四项集。一直不断的把小的项集组成更大的项集。并且去计算它的支持度,计算完之后,直到我们不能组成更大的项集,或者项集都没超过我们的滤值。这样的话我就可以先通过这个算法得到所有的频繁项集;
  5. 接下来去从我们的频繁项集里面发现我们的关联规则。这个和我们发现频繁项集的方法是共通的。先扫描所有的频繁项集,大家知道频繁项集里面是包含着非常多的数据项的。我们去生成这些数据的不同组合。一个排列组合,比如我的频繁项集里是蜗居和豆奶,就可以生成两种排列 莴苣—> 豆奶,或豆奶—> 莴苣。

然后计算所有排列组合的关联规则的置信度。我们把所有置信度低于滤值的这些关联的都去掉。通过这一步我们就只剩下置信度大于滤值的关联规则。
这样你就可以发现同时满足支持度和置信度的关联规则。后面文章会详细介绍代码实现。

刚刚我们在讲非监督算法,现在我们讲监督算法

分类算法 —KNN


现在是介绍分类的,后面还会介绍回归用的算法。

分类算法里面最经典的一个是KNN,即K临近算法(k-NearestNeighbor),是一个分类算法,和K均值算法有非常类似的地方的。

它的思想是:我有一堆的数据,我要预测一个新来的数据,看新来的数据和我原有数据之间的距离。然后我筛选出所有和这个数据距离最小的前k个数据。前这前k个数据大多是哪个分类。我们来看一下示例数据,来看一下KNN算法是怎么做的。

数据背景
我非常喜欢看奥特曼,假如我是奥特曼里面的科学特搜队,大家都知道奥特曼最后一集挂了,我们是人类吗,只能靠自己的力量去保护自己。我怎么保护自己呢,我先收集奥特曼前39集里外星人的数据。我把这些数据做预先分类,假设这些外星人有两种。A类外星人,和B类外星人。我们用A类外星人和B类外星人残留下来的尸体我们去提取它的激素。假设所有外星人都有两种激素,一种是激素A,一种是激素B,然后我们记录下来所有外星人激素A的水平和激素B的水平,以及它是属于哪种类型的。

我们的任务
我们先看编号1-5,6是未知类型先不管,我现在有5个训练数据,激素A和激素B是我们的特征,类型是我们的训练目标。也就是标签,每个数据有两个特征和一个标签。然后有一个新的外星人来了,我希望通过提取他的激素水平知道它是A类外星人或B类外星人。

如何判断新的外星人属于哪一类
比如我们6号外星人,他的激素水平是18、90,我们计算6这个外星人和0这个外星人的距离,怎么计算,其实就是欧式距离公式。我们把激素水平看做平面上的两个点:6号外星人的点:x = 18,y = 90,0号外星人点:x = 3,y = 104.这两点之间的距离是多少。(18 - 3)的平方,加上(90 - 104)的平方。相加完之后再开根号。大家可以算一下它的结果就是20.5.这就是一个欧式距离。机器学习里面非常常用的距离算法。以此类推,我们依次算出它(外星人6)和其他四个外星人的距离。现在算出了6个外星人和前五个外星人的距离。

KNN算法的思路
我去这里面找距离最小的K个外星人。就是K个样本,比如我们的K是4,那我们就从计算完的距离里面挑出距离最小的四个样本。其实就是0、1、2、3这四个样本,我们的目标是类型,他们分别对应类型A、A、A、B。它有75%的概率是A,我们就认为它是A,因为A的概率更大。我们就排序完,看最小的K个样本里面,居多的是哪个类型,我们就认为它就是这个类型。这样我们就判定又有一个外星人类型是A。

大家现在可以理解KNN的思路了,就是计算待运算数据和所有样本之间的距离。 挑出其中距离最小的K个元素。看这K个元素大多属于哪些标签。我们就认为它的标签就是这个标签。

分类算法 — 决策树

这是第二个分类器。

关于相亲的决策过程
这其实是一个分类问题,只有两个结果,见还是不见。我不考虑相亲的后果,我只考虑去不去相亲,这是一个二分类问题。根据我的逻辑,最后帮我得出来一个结果,见还是不见。对方的年龄、长相、性格是我的输入,结果就是见还是不见。

难度在于如何建出这个树,它有好几种算法,常用的有id3算法,c4.5算法。后面我们讲决策树时候会讲一下如何构建这颗树。采用算法实现一下。这里我们先了解一下决策树是什么东西。

分类算法 — 朴素贝叶斯

第三个分类器— 朴素贝叶斯分类器。

我这边没有写数学公式,其实它是一个基于概率统计的一个分类器。如果你还记得概率论的话,它里会讲到一个叫贝叶斯公式。

回到刚刚那个例子,外星人有两个特征:激素A、激素B。

那么来了一个外星人怎么知道外星人是A还是B呢?

激素A大于50在外星人A分类中的出现频率,再看一下B激素大于50在A分类种的出现频率。然后,再看一下A外星人在所有外星人里所占的频率。我们就可以计算出两个特征的条件概率和一个总的概率。

当来了一个新的外星人,看它激素A大于50的概率,要么是1,要么是0,激素B大于50的概率。然后我们在根据贝叶斯公式做一个计算。最后就会得出我这个数据是不是外星人A的概率。也就是我只要计算出每个特征的条件概率和我这个分类标签出现的总概率。我就可以建出一个模型,这个模型套用公式就可以了。

应用场景
比如:打黄扫非,分析一篇文章是不是小黄文。对于这个需求来说呢,朴素贝叶斯就是很好的选择了。

怎么做呢?统计一下小黄文里的敏感词,假设说有5个敏感词,我去计算一下,在我收集的所有小黄文里面,这些敏感词的出现频率。然后再计算一下我收集的所有文章里面小黄文的出现频率。

现在你发一条微博,我想看看这条微博是不是小黄文。我把敏感词的频率抽出来。套用公式,把我所有敏感词的出现概率和小黄文出现的概率做一个计算,就可以算出这个概率了。

至于为什么成立,我们会做一个数学公式的推导。到时候会有代码的演示来更好的理解。

回归算法 — 线性回归

回归算法— 希望通过N多的特征算出它的数值。

学数理统计的时候呢,最基本的问题就是如何用一条直线去拟合这个散点图。这个散点图很像一个直线,所有我就用一个一元一次函数常识拟合它。

x,y已知,w,b未知。

在数学里面w,b是我们的参数。 学概率统计时候我们要做一个参数估计,数学有数学里参数估计方法,机器学习有机器学习的参数估计方法,当然也是根据数学方法推出来的。具体讲Logistic回归的时候讲怎么做。

这是一个二元问题,我们用一条直线拟合我们平面上的散点。假如我们得到了这个函数,再输入x,我们就得到y的值。这个就可以预测到我数值的结果。

刚才是一个二维平面,现在来看三维空间。要用一个平面来拟合这些散点,训练数据里面x1,x2是已知的,我要估计w1,w2,b,估计出来之后就学习完这个函数,这是我训练出来的参数,来了一个新的点就知道y是多少,就可以在三维空间中表示出来。

使用场景
如根据老人的其他体征回归出老人的血糖水平,而不是抽血(训练数据是需要抽血的)。

分类算法 — Logistic回归

刚刚我们讲回归算法,现在回到分类算法。
大家注意,虽然我们这个算法叫Logistic回归,但其实它是用来做分类的。

这个函数是Sigmoid函数,定义如上,
在某一点,突然从0到1,这样的函数称为阶跃函数,
这个分类是一个二分类,要么是0,要么是1。

后面会介绍多分类的情况。

分类算法 — 支持向量机(SVM)

最后一个算法:它会有很多数学上的推导,今天只介绍一个思路。

支持向量机是一个分类模型,怎么实现分类呢,这张图是从网上找了一张图。

x、y代表病人的两个特征,比如x = 血压,y = 血糖;根据病人的数据把点描在平面上。

我用一个函数把我这个空间里面分出两部分,左边正常病人,右边患癌症病人,我要学的是中间这个函数,平面上这个函数是一元一次方程。具体学习方法我介绍SVM时候介绍。

假设有三个特征,就会再画一个轴出来,就会变成三维空间,就和刚刚介绍的线性回归一样,三维的线性回归我们要用一个平面去回归。如果说我要做一个三维的分类,我要设计的函数是一个平面。这个平面可以把我空间分成两部分:normal patients and cancer patients。

如果我的特征越来越多,它就变成三维、四维、五维、六维,我们就认为它是一个高纬空间,二维、三维大家还能够想象出来,四维、五维大家就想象不出来了,只能用数学公式去推导了。

我有n个特征之后呢,我就可以设计出y = ⍬+⍬x(⍬=0…n,x = 0…n),来对我的数据进行分类。分类中我的参数是⍬(⍬=0…n),训练过程是我已知x,估计⍬(⍬=0…n),估计完成之后,就认为训练完成。之后我就可以做预测,把它x的特征输入进来,我就可以知道y。

注意这里我们是由一元一次函数来分类的,但实际上我们会用其他函数来分类,因为一元一次函数太简单了。做不到实际的分类,我们把这种实际用来分类的函数叫做核函数kernal function。之后我们详细介绍SVM的时候,会介绍不同的kernal,不同的kernal会有不同的适应情况,大家可以先去了解。我们之后会详细解析。

今天没有讲人工神经网络和深度学习,这个是我们的重点,后面会以非常多的章节去讲者两个东西。

基本模型入门(包括开发环境搭建)

开发环境搭建

开发工具

  • JDK
  • Pycharm
  • Python

工具库

  • NumPy
  • SciPy
  • Scikit-Learn

我们用Scikit-Learn框架的SVM模型实现手写数字识别的例子
我们的框架用的是:Scikit-Learn,我们用它实现好的SVM模型,用它实现好的SVM模型来做一个手写数字识别。
什么是手写数字识别:假如我写一个1,输入给程序,程序就会给你输出数字1,代表你的手写数字是几。这是一个非常经典的一个例子。

需要用到的开发工具
先安装一下JDK,主要是因为我们现在用的IDE是PyCharm,PyCharm使用Java开发的。它是JetBrains公司开发的,JetBrains公司的IDE,这个公司的IDE都是用Java开发的。所以用它之前必须得装jre(Java Runtime Environment ),我们就偷懒直接装JDK了,
然后呢,我们会装一下Python,我们给大家提供给的工具包是Anaconda,那个库里面包含了Python,还包含了我们需要用到的所有工具库,包括NumPy、SciPy、Scikit-Learn这三个框架。

note—最终需要安装的三个软件
1. JDK - 支持PyCharm运行的环境
2. IDE- PyCharm
3.工具包-Anaconda:内含Python语言和NumPy、SciPy、Scikit-Learn这三个框架。

简单介绍一下工具库
NumPy:如果你是学过Python的人,如果你熟悉可以动手安装,安装Anaconda是因为说安装SciPy的时候它需要一些plass库,这些plass库在windons底下默认是没有的,所以,如果你用Anaconda在windows下会非常方便,自己装也无所谓,能够搞定这个环境就行。

如果你搞过Python的科学计算,那你必须会知道这个NumPy,它是一个矩阵算法库,它主要是实现了一个N维数组运算。那你会觉得奇怪,Python里面没有数组吗,还需要单独的库来做数组运算,python有个缺点,计算速度比较慢,NumPy用C实现了一个n维数组,我们用python3,在这个n维数组的上面封了一个Python的接口,这个接口就是NumPy, 虽然你调用的是Python,但你实际上在用C语言做计算。所以它既保证了Python的简单易用,又提高了速度。

大家之后接触的所有深度学习框架都是这样做的,下面是C++的实现,上面用Python,Lua或者JavaScript来做一个胶水语言,当然Python是用的最多的胶水语言,所以我们这边以Python 为主。

SciPy:它是基于NumPy的更强的科学计算库,包含很多矩阵运算算法和其它的各种算法。

Scikit-Learn:是一个机器学习框架,假如你学C++,你就知道C++帮你实现了一些标准数学和标准算法,Scikit-Learn它就是机器学习届的xtl,它帮你实现了所有的经典的机器学习算法,也就是说你自己不需要实现这个算法了,用他这个库它已经实现好了。你只要按它的要求提供训练数据,设置模型的参数,基本参数,就是训练参数,它就可以帮你做训练,训练完之后就得到结果。

各种学习语言简单对比
因为在Tech里面用的Lua,所以Lua用的也比较多,
最多的是Python + C++
R语言也算主流的做科学统计的语言,但是它的缺点是处理超大数据时不是那么方便,作为胶水语言并不是那么好用。所以科学计算里面用Python是最多的。当然,如果你是搞研究用MATLAB除外。


预测代码展示 — 如何做一个预测

代码运行环境
* Pycharm CE(community invironment) + Anaconda3-4.4.0 + JDK

MNIST—手写数字识别

note
以下代码各用例均为注释完整、可实际运行的完整代码,而非代码片段。

本例子展示了如何做一个预测— mnist.py

Pycharm CE 文件目录下右键新建Python File :mnist.py 文件,输入如下代码,即可运行。

mnist.py:数据训练+数字预测综合代码展示

# coding = utf-8
# 本例子展示了如何做一个预测# python 的模块倒入语法,代表:从sklearn包里导入datasets变量,datasets为内置数据集
# 我们不再使用其他数据集,而是直接用模块给我们提供的
from  sklearn import  datasets
# svm:sklearn里面的一个工具,包括所有和svm相关的功能
from  sklearn import  svm# 从datasets里面装载我们的手写数字数据集
digits = datasets.load_digits()'''
digits里包含三个元素:
images:手写数字训练用的图像,即原始图像
data:图像展开的一维数组,即训练数据
target:我的标签,即希望得到的结果,data里面的一个数据,就会对应target里的一个数字
'''
# print()作用:输出我的某个变量
# images是一个数组,所以用python里的数组访问元素语法
# images[0]:取出第0张图像 data[0]: 取出第0个数据项,target[0]:取出第0个标签
print(digits.images[0])
print(digits.data[0])
print(digits.target[0])'''
prints:
// images[0]:表示一个二维数组,内中括号表示二维数组里的小数组,8*8的数组,8行8列
// 数组元素:一个元素代表一个像素点,0代表像素点的灰度为0,5代表灰度为5,
// 数字越大代表颜色越深,数字越少颜色越浅,和我们正常的灰度是相反的。
[[  0.   0.   5.  13.   9.   1.   0.   0.][  0.   0.  13.  15.  10.  15.   5.   0.][  0.   3.  15.   2.   0.  11.   8.   0.][  0.   4.  12.   0.   0.   8.   8.   0.][  0.   5.   8.   0.   0.   9.   8.   0.][  0.   4.  11.   0.   1.  12.   7.   0.][  0.   2.  14.   5.  10.  12.   0.   0.][  0.   0.   6.  13.  10.   0.   0.   0.]]// data[0]: 是一个一维数组,它其实是把我的图像数组拉成了一维数组,8*8,64个元素的数组
// ,因为我们训练的时候不会拿二维数组进行训练,而会拿一维数组进行训练,所以data是我们的训练数据。[  0.   0.   5.  13.   9.   1.   0.   0.   0.   0.  13.  15.  10.  15.   5.0.   0.   3.  15.   2.   0.  11.   8.   0.   0.   4.  12.   0.   0.   8.8.   0.   0.   5.   8.   0.   0.   9.   8.   0.   0.   4.  11.   0.   1.12.   7.   0.   0.   2.  14.   5.  10.  12.   0.   0.   0.   0.   6.  13.10.   0.   0.   0.]// target[0]:这张图片对应的数字是0。0// 可以把这三项元素调成1,再打印试试
'''# 我们做机器学习的时候,会把我们的数据分为两部分:测试集和训练集
# 我们先分出一部分训练集'注意:这里面有个特殊语法,叫切面,跟Java,C++里不太一样,'
'[]:中括号既可以取出数组里的元素,也可以取出(这里数组叫列表,list)' \
'list里面的子列表:冒号左边是我的起始位置,右边是我的结束位置,是一个左闭右开的区间' \
'-1:在python里代表倒数第一个元素,' \
'所以,这句话的意思是从第一个元素取到倒数第一个元素之前' \
'比如1000个元素,取前999个元素作为我训练集' \trainData = digits.data[:-1]
"训练标签:0到倒数第一个个元素"
trainLabels = digits.target[:-1]print("构建SVM分类器-create classfilter")
"注意:Python里构建对象用类SVM,不用new,但是仍然返回一个引用,gamma(灰度系数)、C为两个参数,后面讲SVM会详细介绍这两个参数"
clf = svm.SVC(gamma=0.001, C=100)print("开始训练")
"两个参数:训练数据数组-特征,和结果标签,两者必须一一对应,分类器要求每一个数据都有一个标签"
"训练完之后我们就会得到一个训练完的模型"
clf.fit(trainData,trainLabels)# 测试我们的数据,
"取倒数第一个元素到最后一个元素"
testData = digits.data[-1:]
testLables = digits.target[-1:]# 怎么用测试数据得到它对应的标签--如何做预测print("预测")
"用predit函数,只有一个参数:测试数据,返回值为预测结果"
resultLabels = clf.predict(testData)print(testLables) # prints '8'
print(resultLabels) # prints '8'"取列表的长度,只有1797个数字"
print(len(digits.data))  # prints '1797'
封装训练模型并预测— train.py & predict.py

为了提供精确度,会加大训练数据量,数据越多,训练速度越慢,如果每次预测之前,都要训练一次数据,就会把大量时间都会耗费在重复训练上。我的思路是把我训练出来这个模型保持下来,我们来写一个独立的文件做训练:train.py。

train.py — 专门用来做训练的文件

# 专门用来做训练的文件from  sklearn import  datasets
from  sklearn import  svm# 怎么来保存我们的模型呢:导入joblib这样一个工具,它可以把我们的模型保存成文件
from sklearn.externals import joblibdigits = datasets.load_digits()trainData = digits.data[:-4]
trainLabels = digits.target[:-4]print("构建SVM分类器-create classfilter")
clf = svm.SVC(gamma=0.001, C=100)print("开始训练")
"训练完之后我们就会得到一个训练完的模型"
clf.fit(trainData,trainLabels)# dump方法可以把我们的模型clf保存成model.dat
print("保存数据")
joblib.dump(clf,'model.dat')

运行此文件之后,我们会在右边此目录下看到多了一个model.dat文件; 在工程上我们叫做序列化一个文件,用text打开之后是二进制文件,当然是看不懂的。

总结做训练的步骤:
拿到训练数据–> 构建我们的分类器(构建模型)–> 用训练数据为模型做训练
–> 把模型保存为文件

predict.py我们新建一个predict.py去使用我们的模型

# 使用训练好的模型'model.dat'来做预测:如果可以成功的读取模型,我们就可以得到结果标签from  sklearn import  datasets
from  sklearn import  svm# 怎么来还原我们的模型呢:导入joblib这样一个工具,它可以把我们的模型文件还原为分类器
from sklearn.externals import joblibdigits = datasets.load_digits()print("读取模型")
"load方法:把一个文件还原成分类器"
clf = joblib.load('model.dat')# 测试我们的数据,
"取倒数第四个元素到最后一个元素"
testData = digits.data[-4:]
testLables = digits.target[-4:]print("预测")
"用predict函数,只有一个参数:测试数据,返回值为预测结果"
resultLabels = clf.predict(testData)# 对比测试标签和结果标签的值是否一致
print(testLables) # prints '[0 8 9 8]'
print(resultLabels) # prints '[0 8 9 8]'

总结如何做预测
读取模型 –> 输入预测数据 –> 做预测 –> 输出结果
SVM这种分类器是监督学习模型,一定要有标签

画出手写数字 — 单张图predict plot.py & 多张图 predict plot more images.py

大家可能觉得这个过程比较抽象,其实我们可以把这个过程变的有趣一些;其实我们可以看到它的手写数字的。新建predict plot 文件。

predict plot.py — 画出单张手写数字

# 我们想知道这个数据长得什么样子,教大家怎么看这些数据from  sklearn import  datasets# 怎么把这张图片显示出来,我们要引入另外一个库,叫matplotlib, python里面最常用的绘图库
# 这个是模仿matlib的绘图库,我们可以用matlib的形式把它做绘图
# as plt 是为matplotlib.pyplot绑定一个名字,以便于以后使用方便
import  matplotlib.pyplot as plt# 测试数据是anaconda安装的时候自带的
digits = datasets.load_digits()"取第0张图片"
image = digits.images[0]
label = digits.target[0]# 这张图片是保存在我们数据集里面,怎么显示呢?"这是一张灰度图,我们要指定图片image,把cmap属性指定为灰度"
plt.imshow(image,cmap=plt.cm.gray_r,interpolation= "nearest")
"利用python里面的格式化语法,把数字label的值画上去"
plt.title(' Original %i ' % label)"plt相当于画板,画完之后要显示画板"
plt.show()  # show '0'print(label) # pirnts '0'

运行结果展示:

我们现在调整我们的测试数据和训练数据,实际测试的时候不会只有一个数据的, 现在我们同时显示四张图,新建文件predict plot more images.py 文件。

predict plot more images.py - 画出多张手写数字

# 我们想知道这个数据长得什么样子,教大家怎么看这些数据from  sklearn import  datasets# 这么把这张图片显示出来,我们要引入另外一个库,叫matplotlib,python里面最常用的绘图库
# 这个是模仿matlib的绘图库,我们可以用matlib的形式把它做绘图
import  matplotlib.pyplot as plt
# 怎么来还原我们的模型呢:导入joblib这样一个工具,它可以把我们的模型文件还原为分类器
from sklearn.externals import joblib# 测试数据是anaconda安装的时候自带的
digits = datasets.load_digits()clf = joblib.load('model.dat')originImages = digits.images[-4:]
originLabels = digits.target[-4:]'''
python的遍历语法:这还是很不python的,下次会介绍更加python的写法
len():数组的长度
range()形成新的数组
index :遍历数组里的元素
'''
# note:大家注意,python里面块语句是用缩紧来表示的,所以它没有大括号
for index in range(len(originLabels)):image = originImages[index]label = originLabels[index]"创建一张子图,把我们的窗口变成一张2*4的方格""index = 1,代表在第一格画这张图,index会从0 - 3,代表从第一格画到第四格"plt.subplot(2, 4, index + 1)"这是一张灰度图,我们要指定图片image,把cmap属性指定为灰度"plt.imshow(image,cmap=plt.cm.gray_r,interpolation= "nearest")"利用python里面的格式化语法,把数字label的值画上去"plt.title(' Original %i ' % label)print("预测")
testImages = digits.images[-4:]
testData = digits.data[-4:]
resultLabels = clf.predict(testData)for index in range(len(resultLabels)):image = testImages[index]label = resultLabels[index]plt.subplot(2, 4, index + 5)plt.imshow(image,cmap=plt.cm.gray_r,interpolation= "nearest")plt.title(' Original %i ' % label)"plt相当于画板,画完之后要显示画板"
plt.show()  # show '0 8 9 8 的图和标签'

运行结果如下:

最终得到预测和测试一一对应的数字,在当前数据条件下,预测准确度为100%。

note
1. 大家可能会惊叹代码量很小,那是因为sklean帮我们实现了SVM这个算法,我们要知其然,也要知其所以然,所以我们今后也要去学习怎么实现这个SVM算法,那样的话代码量就不可能同日而语。
2.我们得益于Python,Python是一个表达能力非常强的语言。如果你想在C++里面做一个数组的切割最后四个元素,你是不是用一个迭代器,最后再用一个算法,代码就会变的非常长。 包括下面怎么显示、参数传递都有一些非常强的表达能力,有相同需求的话用Python写代码,总是比C++或Java要短的。这就是脚本语言的优势,很多时候比起我们的运行效率,我们会更关注于我们的开发效率。Python就是一个很好的选择。而我们用C++实现的底层的库,包括线性代数运算、 数字运算都是用C实现的。所以既可以保证我们的开发效率,又可以保证我们的执行效率。


本章总结

本章的内容结束了。

  • 介绍了机器学习的基本概念、机器学习的任务、再介绍几种机器学习的方法,最后做了我们的实践分享。
  • 以后你自己想做一个传统模型训练的话,scikit-learn是一个产品,可以用在产品上的。直接的做训练,如果需要数据量特别大的时候,可能就会用别的方法了。

来源:学习笔记


基础篇 | 01 机器学习基础相关推荐

  1. 视觉slam学习|基础篇01

    系列文章目录 SLAM基础篇01 SLAM基础篇02 目录 系列文章目录 前言 SLAM是干什么的? SLAM的数学建模 机器人学基础 齐次矩阵 关于旋转的表示:旋转向量.欧拉角.四元数 李群和李代数 ...

  2. mysql经典总结文章_MySQL基础篇(01):经典实用查询案例,总结整理

    MySQL基础篇(01):经典实用查询案例,总结整理 发布时间:2020-02-26 22:25:21 来源:51CTO 阅读:244 作者:知了一笑 本文源码:GitHub·点这里 || GitEE ...

  3. 自然语言处理——基础篇01

    自然语言处理--基础篇01 一.什么是自然语言处理? 二.自然语言处理的难点与特点? 三.语言模型 四.NLP的常见任务类型 1. 中文分词 2. 子词切分(Subword) 3. 句法分析 4. 语 ...

  4. MySQ快速基础篇_MySQL数据库基础

    MySQ快速基础篇_MySQL数据库基础 文章目录 MySQ快速基础篇_MySQL数据库基础 MySQL数据库基础 学习目录 学习目标 一.数据库概述 1.数据库介绍 2.数据库分类 ☆ 关系型数据库 ...

  5. 【直播】陈信达:零基础计算机视觉之机器学习基础

    零基础计算机视觉之机器学习基础 直播信息 分享嘉宾:陈信达,Datawhale成员,上海科技大学硕士. 直播时间:2021年07月30日 20:00 直播内容: 线性回归与指针读数识别 逻辑回归原理与 ...

  6. 【基础篇】C#基础知识——面向对象

    [基础篇]C#基础知识--面向对象 第一章 C#基础知识--入门 第二章 C#基础知识--面向对象 文章目录 [基础篇]C#基础知识--面向对象 前言 一.C#面向对象的特性 二.命名空间 2.1 n ...

  7. java玩转区块链-基础篇-solidity语法-基础类型

    java玩转区块链-基础篇-solidity语法-基础类型 java环境配置 代码准备 maven 完整solidity 执行步骤 基础类型 布尔类型 类型标识: 字面常量值: 运算符: 短路规则: ...

  8. 产品经理基础篇 之 产品基础技能

    产品经理基础篇 之 产品基础技能 一.文档 1.BRD(Business Requirements Document,商业需求文档):市场分析.营销策略.盈利预测--给老板看的商业计划PPT,短小精悍 ...

  9. 「ML 基础篇」机器学习概览

    文章目录 1. 什么是机器学习 2. 引入机器学习 3. 应用场景 4. 机器学习分类 4.1. 有无人类监督 4.2. 是否增量学习 4.3. 泛化方式 5. 主要挑战 6. 测试与验证 1. 什么 ...

最新文章

  1. 在VMware Workstation上安装Ubuntu 16.04 Server操作系统
  2. mysql出现1499错误_连接MySQL时出现1449与1045异常解决办法
  3. 深入Java泛型(二):通配符与嵌套
  4. python数据存储与读取_【Python爬虫】数据保存与读取
  5. Le Chapitre VI
  6. (转)函数指针,指针函数,指向函数的指针,返回指针的函数
  7. PHP反序列化—构造POP链
  8. Android 利润,惊人利润:Android系统免费背后影藏的巨大利润
  9. Elasticsearch查询性能优化
  10. C#进行Post请求(解决url过长的问题)
  11. php和java访问中的一些区别
  12. Gartner预测公有云将迎来“双头垄断”局面
  13. 51单片机课程设计数显简易频率计设计
  14. win10升级工具_win10升级安装工具
  15. html5 dreamlive,DREAM LIVE 5th Tour Stargazer即将开演
  16. jenkins重启页面变成英文
  17. Swift iOS macOS 如何 Localize StoryBoard,StoryBoard 本地化,添加多语言支持,基于 String
  18. zblogphp登录和注册_基于PHP的登录和注册的功能的实现
  19. 基于SpringBoot框架的HIS互联网医院门诊信息管理系统源码JAVA语言开发
  20. 泛型是双刃剑?Go1.18 编译会慢近 20%

热门文章

  1. 各种常见文件的文件头及其含义
  2. 360行车记录仪起死回生
  3. 分享一些摘抄的优美句子~(第三波)
  4. CentOs 7.4下使用Docker容器搭建Elasticsearch集群
  5. 如何靠网络快速打造品牌
  6. pacemaker浅析
  7. 阿里云MQTT + STM32 + MQTT + ESP8266 01S WIFI 实现远程继电器控制开关和采集温湿度 登录阿里云网站,进入物联网云平台
  8. 用Rust清理eclipse自动升级后的重复插件
  9. 怎么删除PDF文件中的页面?教你两招删除方法
  10. (C语言版)无迹卡尔曼滤波UKF和容积卡尔曼滤波CKF进行锂电池SOC估计的C语言版本实现