在丰富的自然语言处理领域中,文本分类是最基本的应用场景,因此使用一套合适的方案对于文本分类上的运用具有积极的效果。本文主要介绍基于词频的TF-IDF的特征提取,加上XGBoost的文本多分类方方案。
1.数据预处理
首先,文本数据源来自于网络爬取数据,所有标签都通过人工标注的方式产生,具有数据质量不高,结构复杂的问题。其结构为每一行代表一个新闻训练实例,其中context中表示爬去的新闻具体文本内容,tittle表示新闻标题,theme表示每一个新闻训练实例的标签(label)。从中可以看出数据中含有网络爬虫包含的HTML标签,部分数据项为空,包含无关标点符号(比如逗号,顿号,句号等),也包含了数字等等,同时也包含文本主题分类无关的高频词汇(如的,得等)。这些内容增加了利用监督学习训练模型的的噪声干扰。因此对于数据我这里做了基本预处理,引入Python正则表达式库,将HTML标签,文本标点符号,数字内容过滤掉,然后引入中文停词表(可以上网络下载),也将数据集中的文本在中文文本分词阶段,过滤掉在停词表中的词汇。
2.中文文本分词
对于自然语言领域而言,中英文数据集有个显著特点,就是中文词汇之间没有明显的分隔符,而英文之间却有自然的空格符来分隔,因此数据需要使用分词工具来将一大段文本分割为不同的单词词汇,用以转为训练矩阵进行主题分类。这里使用的是中文jieba分词工具,将每一段文本处理成分词结构,之后存储于一个txt文件中,分词处理的代码和处理后的数据如下图所示:
3.文本特征提取
经过如上步骤的文本数据处理过程之后,我们需要将文本文件转化为数值向量以便于能够带入机器学习分类器进行分类,本文此处使用的是TF-IDF算法进行处理。
3.1 TF-IDF算法原理
该算法通过统计字词分布频率用以评估一个字词对于一个文本数据集的重要程度。字词的重要性是指如果它在文本中出现的次数越多,那么其所占概率分布相比于其他词汇更高,则表明该词汇对这个文本而言越重要。TF-IDF的算法思想就在于如果一个分词相对于一个文档出现频率(TF)越高,则表示这个分词对于这个文档而言很重要。如果一个文档集合中(多个文档构成的集合),该类分词出现的文档数目越少,则越能将此类文档与其他文档区分开,而表征此类文档出现的状态参数即为IDF(逆文档频率)值大小。最后将二者频率相乘,即可得到文本词频矩阵,我们也就完成了文本向量化过程。
3.2TF-IDF算法过程
1.计算文本中每一个分词频率(TF)
2.计算每一个分词的逆文档频率值(IDF)
3.计算该类分词文本词频的值(TF-IDF),计算公式即为:TF-IDF=TFIDF
4.将计算所得所有分词词频值构成一个矩阵
3.3IF-TDF算法缺陷
基于TF-IDF的方法是通过统计的思想来实现文本数据向数值型数据转化的。在中文文本语义中,一般开头第一二句话表示该文本主题思想。而这类方法有个缺点,即为通过频率分布可能无法得到表示某一类文本中心思想的主题句段,字词的特征,因此在文本情感分类,主题分类方面存在误差,也可以说这也是基于词频的文本处理方案的通病。
四.文本分类
经过以上步骤处理过的文本数据集就转化为了词频矩阵。这类矩阵维度适中,可以直接带入统计机器学习库进行主题分类处理,本文在之前比赛经验中,决定采取统计机器学习中对于高精度要求具有普适性的XGBoost进行建模应用,以达到分类目的。
4.1 XGBoost算法前置理论
**4.1.1 决策树模型与Boosting算法**
决策树作为一类基础的二叉树模型,每一个决策结果只有“是”或者“否”,其简单,易分类的特点使其广泛用于机器学习分类与回归的基础场景,这里一般采用CART生成算法,为了减少过拟合现象,对于生成的树会进行剪枝操作(该部分详细理论请参阅李航《统计学方法》第五章)。
Boosting算法,即提升方法,该算法思想通过将不同的弱分类器线性叠加,同时赋予相应权重,以对于数据进行拟合,从而达到相关分类或者回归效果。其通过拟合下面的假设函数(如下图所示)进行建模。其中w为模型基函数(即为弱分类器),W(m)为每一个弱分类器权值。
一般Boosting算法建模过程如下图所示,来源于李航《统计学方法》:
其思路即为不同弱分类器线性加法,通过添加不同的弱分类器进行训练,得到损失函数最小值后即停止模型计算过程。
**4.1.2 Gradient boosting(GB)算法**
Gradient Boosting是一种Boosting的方法,其代价函数是常见的拟合程度+正则化项结构,损失函数值取得最小值则代表该模型效果最好。它在数据建模过程中,每一次建模会对于通过代入预先设定好的不同弱分类器和弱分类器数目进行建模。其在模型损失函数的梯度下降方向进行探索,在找到沿着梯度方向下降的时候,此时找到了模型损失函数瞬时最小值,会记录参数进行建模。之后其会进一步沿着梯度下降方向进行相同操作,最后当梯度值变化不大或者相等时停止整个过程。除此外GB算法中弱分类器可以更换为任意机器学习基础模型。
**4.1.3 Gradient boosting Decision Tree(GBDT)算法**
顾名思义,该算法即为GB算法与决策树相结合,其将多个决策树模型作为弱分类器,代入到GB算法作为框架拟合数据集的算法模型。其中CART决策树可以用如下假设函数来表示:
其中Rj表示假设空间,γ每次决策树分叉的返回值,I()表示指示函数,在空号中条件成立情况下为1,否则为0.其中的参数J表征树的深度。
而GBDT算法流程大致如下图所示:(图片来源于《The Elements of Statistical Learning》一文)
其中可知该算法关键在于通过不断迭代损失函数值,从而不断拟合下面的式子(如下图所示),从而得到最优解。(注意该式子有的材料将其称作残差计算式,但该算法核心还是在于梯度更新最优解)
**4.1.4 XGBoost算法**
Xgboost是基于GB算法框架来实现的,其弱学习器除了可以是CART决策树也可以是线性分类器。通过参阅paper《XGBoost: A Scalable Tree Boosting System》,其跟CART决策树的GB算法大致有如下区别:
(1). 如下图所示,xgboost在损失函数中的拟合程度,加上了正则化项,当学习器为CART决策树时,正则化项fk与树的参数相关。
(2).如下面两幅图所示, GB中使用使用损失函数对f(x)的一阶导数计算出梯度最优解,来迭代损失函数从而学习生成f(x),而XGBoost算法在迭代过程中是将一阶导数和二阶导数结合起来进行f(x)更新从而达到快速优化每次模型训练速度的目的。如下图所示,第t次损失函数更新计算式。
(3). 如下四副图所示,在文中等式4表示XGBoost模型损失函数,其中XGBoost利用5式计算叶节点最优权重值和利用式子6计算叶子节点最优值。CART回归树中寻找树每一层根节点的最佳切分点的衡量标准是最小化均方差,而在XGBoost中的切分点的标准是树的LR和LF集合并集最大化,计算式如式子7所示 ,式子一般用来计算取得最佳切分点位置,式子中参数都在损失函数(式子4)每次取最优解后迭代更新,确定最优切分点位置。
**4.1.5XGBoost算法实现**
代码如下图所示,此处基于XGBoost的sklearn入口实现算法应用,其中在数据切分后,先来者5轮交叉验证进行模型参数选择,之后利用选取的参数模型进行建模训练,最终得出相关数据报告即可,这部分关键代码截图如下所示:
*五.文本主题分类结果
最终我们选取了learning—rate=0.1的模型进行建模,最终结果如下图所示:
模型精度达到了74%,远远胜过于贝叶斯的63%与logistic模型的69%(这两类模型作者之前跑过作为对比),的确XGBoost方法对于高精度应用场景具有更好的效果。最后在输出模型标签分布图,即可看到具体标签重要程度,可以进行建模的特征选取。如下图所示:
(注意:此处作者训练服务器python库matpolib中文乱码,就不再处理,详情请自己添加中文规则进入matpolib源码中设置即可)
机器学习算法实践之决策树
决策树是一种基本的分类与回归方法。决策树模型呈现树形结构,在分类问题中,表示基于特征对实例进行分类的过程,它可以认为是if-then规则集合,也可以认为是定义在特征空间与类空间上的条件概率分布,其主要优点是模型具有可读性,分类速度快。在进行数据学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型。预测时对新的数据利用决策树模型进行分类。决策树模型学习过程主要包含三个步骤:特征选择,决策树生成,决策树修剪。我们将在后面逐步探讨这些内容。
1.决策树模型理论
区块链技术体系初步
1.背景
在传统互联网的TCP/IP协议下,我们进入了信息爆炸时代。在当前情况下,信息快速成型,低成本传输与大量信息共享得到了实现。目前的互联网金融模式是以中心化记账形式来进行等价值货币转移而运行的,比如A在互联网上转账给B,A需要通过网上发送请求给中心化机构承担者,通过在中心机构记账的方式,将信息转化为价值,再由中心机构将等价值的货币转移至B的账户上。这种情况需要政府或者企业利用信用为中心化机构承担者做出保障,但由于传统信息互联网部分个体篡改局部数据情况无法及时发现甚至无法掌握相应情况,因此这种结构依然存在安全性问题。
因此,我们如何实现传统网络传递价值?这就是近几年火起来的新技术——区块链。2008年中本聪在互联网上一个讨论信息加密的邮件组中发表了一篇文章,文章名叫《Bitcoin: A Peer-to-Peer Electronic Cash System》,勾画了比特币系统的基本框架。 2009年他为该系统建立了一个开放源代码项目 (open source project),正式宣告了比特币的诞生。区块链技术刚开始是为了支持比特币生成与交易而产生的底层技术,其目的是通过建立去中心化的信任,从而不再依托于单个中心结构记账,从而通过P2P网络直接进行价值交换,从而使得实现传统信息交换互联网变为价值交换互联网成了可能。后续这门技术得到了进一步提炼发展,便从比特币中提取出来,成了今天的区块链技术。
2.区块链的初步以及几个名词解释
2.1 什么是信用?
信用,是指依附在人之间、单位之间和商品交易之间形成的一种相互信任的生产关系和社会关系。如果我们用数据m量化描述这个概念,那么当m的值越高,则描述个体的信用程度越大,人们就更容易相信该个体发布的交易与账户信息。目前的中心化交易体系就是如此,国家建立法制的社会信用体系,利用国家公信力与强有力的法律为银行做保证,从而提升市场对于银行的信用程度,通过银行这一中心化的组织来进行经济行为有效监管与控制。然后大型互联网企业则利用自身平台影响力,不断提升自己平台影响力,通过自身理念与遵守相关法律法规增加用户对其信用基础,从而让用户能够安心使用平台所提供的网络价值交换服务。
2.2 什么是价值转移?
价值转移,是指具有同等购买力的货币进行流通。在当前金融体系下,价值转移行为需要由第三方进行价值记账,价值交换等行为的操作,控制,才能实现价值在不同个体间的转移。
2.3 什么是P2P网络?
P2P网络,即对等网络(Peer-to-peer networking),网络参与者共享他们自己的硬件资源(处理能力,存储容量,网络连接,打印机等)的一部分,通过网络提供服务和内容,并且可以由其他对等方直接访问而无需中间实体。 该网络的参与者既是资源,服务和内容提供者(服务器),也是资源,服务和内容获取者。在P2P网络环境中,多台彼此连接的计算机处于相同的位置。 一台电脑可以作为服务器并为网络设置共享资源使用其他计算机,也可作为工作站,网络一般不依赖于专用的集中式服务器,也没有专门的工作站。 网络中的每台计算机既用作对网络服务的请求,也用于响应其他计算机提供资源,服务和内容的请求。
2.4 区块链的定义
区块链技术是指一种去中心化的分布式共享记账存储技术,本质上是数据库技术,是一连串使用密码学方法产生相关联的数据块,每一个数据块即为区块,其包含了一段时间内全网交易信息和用于验证其有效性的信息,每一个区块通过指针连接,上一个区块可以创建下一个区块,整体呈现链式排布。
如下图所示,即为传统中心化交易体系,这类体系下中心企业信用度指数要高,同时对于现有以信息传递的互联网体系下,无法实现在线价值转移必须经过第三方平台转移之后才能实现此功能。
这类体系存在如下问题:1.黑客可以修改转账信息,更改数据后,如果无有效交易检验方法,则在现有的信息网络情况下,这种情况不容易被发现,然后矫正。2.中心化体系下,必须对于中心单位给予强有力的信用保证,但对于网上支付平台下,大部分企业自监自查,一旦中心单位出现数据丢失等不可控困难,这种情况存在很大经济波动风险。3.传统交易体系下,网上支付无法直接在线进行价值交换,使用不是很方便。为了解决上述问题,区块链技术便横空出世了。
2.5 区块链系统交易过程
如下图所示,在区块链技术体系下,一个区块链系统有很多节点构成,每一个参与的节点都能够记账,即更新数据库信息。区块一利用私钥签名创建交易后,将信息发往全网进行广播,其交易记录通过P2P网络向后传播,然后经过系统共识机制对交易进行验证,确定交易信息有效性后,将验证结果与上一个节点交易记录一起再次利用P2P网络传递给下去,最后各个记账节点依托于验证结果将交易记录写入账本,更新区块存储信息,从而实现了去中心化的分布式记账。
而共识机制是用来确定分布式系统节点中的账本记录节点的一种机制,其中目前最常用的是工作量证明机制——各个节点通过区块接入系统,通过本地计算能力高低来确认记账与否的能力。计算能力越高的节点,则越能成为账本记录节点,就能将自己节点的交易信息形成一个新的区块加入链中。一旦加入链中,如果想要修改一个区块链中某个区块交易信息,就必须完成该区块与后一个区块的工作量,从而让更改数据成为不可能。
鉴于此,实现区块链技术的关键因素也就出来了,即:1.由于每个节点可以自由加入或退出系统,则形成有效的盘P2P动态网络是关键因素。2.形成时间有序排列的切不可更改的系统主体交易账本(由于个体交易账本篡改不会影响后续节点,真实交易记录会在多个节点存在,因此更改局部节点交易账本一般不会对整体系统产生作用)。3.系统含有有效的统一采用的共识机制模型。
3.区块链技术理论详解
3.1 区块与区块链结构
区块结构如上图所示,每一个区块包含前一个区块ID,交易记录信息,本区块ID等信息。其中交易记录也被称作账本,其结构有两种,一种是采用链式Hash结构防篡改,一串数据hash区块组成链,每个区块账本包含了最近交易集合的hash值,一旦某个部分数据更改,那么hash校验就会出现许多新的结果,从而实现欺骗行为的甄别。另一种是采用公钥密码机制标识的资产所有者,从而利用公钥做为标识,仅仅只有相应私钥的用户才能拥有转移价值行为操作基础。
如上图所示,区块链是由多个区块连接起来的一种链式结构,区块链之间彼此用指针相互对应关联起来,如图3.1-2,由于每一个区块都可以创建一个新的区块,故需要一种共识机制,也是目前应用最广泛的工作量证明机制,通过比拼不同区块也就是节点的计算能力,算力越高,则就越能获得合法的记账权,从而挂载入区块链,同时产生下一个区块。算力不高的区块就无法挂载入链中,其原理类似于大自然中动物群体生殖权争夺。而新区块的ID不一定是前一个区块加1,此处仅仅作为合理性展示才如此画图。除此外,链越长,信用指数越高,越容易受到人们认可,除此外区块链采用高冗余度的存储系统来进行数据存储,在运用工作量证明机制后,也带来高能耗等缺点,此处我们后面再谈。
3.2 区块链的模型架构
首先提两个概念,公有区块链与私有区块链。公有区块链是指全世界任何人都有权限,可随时随地读取的、任何人都能发送交易且交易能获得有效确认的、任何人都能参与其中共识过程的区块链,对用户访问区块链系统不做权限限制的区块链,链越长信用度就越高,这也是公有链越能获得大多数人认可的重要原因。而私有区块链通过严格的权限限制供特定人访问运行,安全度得不到保障。
如下图所示,区块链模型结构类似于TCP/IP模型结构一样,由图中所示六层组成,从技术最底层向上排列分别是数据层、网络层、共识层、激励层、合约层、应用层。其中数据层,封装了底层数据区块的链式结构和相关的非对称数据加密技术和时间戳等技术;网络层,包含了分布式组网机制数据传播和验证机制,对于交易过程控制意义重大;共识层封装网络节点的共识机制算法模型,对于确立记账节点有重大作用;激励层则包含经济发行机制与分配机制,用于激励遵守规则参与记账的节点,惩罚违反规则的节点;合约层则封装各类算法,编程协议,这给了区块链技术编程基础;应用层则为各类区块链应用程序提供了运行环境。其中图中红色三层为区块链必须的层数,其他三层为非必需层数。
除此外,在私有链中,一般不含有激励层,可能由私有链使用者添加强制性因素进行记账节点分配。
3.3 区块链的共识机制模型
共识机制是区块链技术的核心,其主要起到了交易账本信息验证和确认的作用,同时其决定了哪个区块节点为共识记账节点。同时在拼接区块链时,在上一个区块具体挂载下一个区块时的,所需区块节点也由工作量证明机制来决定的。此处介绍两个运用广泛的共识算法模型。
**3.3.1 工作量证明机制(POW)**
如2.5节的图中所示,在一个稳定的,多个节点达成统一共识机制的系统中,其中一个节点作为证明者,提交已知的,难以计算但容易验证的结果,其他任何节点都能通过验证这个结果确信证明者为了求得结果已经大量完成了相应工作量的计算结果,这就是工作量证明机制。比如飞行员有了10000小时飞行时间,则我们都可以相信这个飞行员有高超的驾驶技术,工作量机制与之同理。工作量证明机制中,其利用SHA256 hash算法计算工作量。一个符合要求的区块hash值由n个前导邻,前导邻个数取决于网络的复杂度。要得到合理的区块hash需要大量的运算,运算速度取决于机器hash运算速度。一个节点拥有合理hash值是一个概率性事件,因此当节点拥有合理hash值时,需要运用大量资源进行计算,完成了相当的工作量,因此算力值越高的节点就越能成为记账节点,这也是挖矿时严重耗电的重要因素。
获得记账权概率为算力占总节点算力值的概率值,这也为POW系统的安全提供了很高的保障,毕竟要想攻破一个基于POW的区块链系统,没有一定的算力资源可没法攻破这个系统。
**3.3.2 权益证明机制(POS)**
这是一个shy256算法替代品,避免大量计算工作量的算法模型。其通过对每一笔的交易销毁的币/天数,来实现证明者对某些数量的钱展示所有权。币天数代表一个特定的币,作为网络中权益代表量化单位,一旦有交易发生币天数就会被销毁且无法重复使用。在给定时间点内,存在有限币/天数是有限的,鉴于此在区块链中,持有更多数据货币的人就会有更多币天数,则类似于股份权益,占比更多的人分红更多。
POS安全性将不再靠工作量来保护,而是通过链的一体性来决定的其安全性的,即凡是处于POS中的人区别只是收益不同,但大家都有收益的前提是系统安全性,因此其中大股东更加注重链的安全性与完整性。
3.3 区块链的类型
**3.3.1 公有链与私有链**
具体阐述请见3.2区块链模型架构。此处谈一谈公有链与私有链区别,公有链一般含有一个完整的代币系统,在激励层能够奖励遵守规则的记账节点,惩罚违反规则的记账节点,而私有链中节点是某个组织内部节点,注入权限就不会含有代币系统。公有链就类似于互联网,私有链就类似于局域网,当前大部分公司都在采用私有链技术。
**3.3.2 联盟链**
其共识过程受到选择预先节点选择控制的区块链,在系统建立前就预先决定记账节点分布与其他节点状态。
**3.3.3 许可链**
是指每个节点加入区块链需要取得许可的一种区块链种类。
**3.3.4 混合链和复杂链**
伴随着区块链技术发展,链中每个节点可以根据不同需要通过权限控制其功能,比如在同一个系统中,有的节点记账,有的节点可以查询整个链信息,有的节点只能查询部分信息,从而构成了一个复杂但高效的区块链网络。
4.总论
区块链初步理论体系记录到此结束了,但智能合约部分暂未记录,还在研究,在后续会进行更新完成。从目前收集资料上来看,区块链技术的确有对互联网进行变革的潜力,其价值转移互联网一旦成型,将会对目前的信息网络带来更多积极的影响,值得关注。
机器学习算法实践之感知机模型
本篇文章作为算法实践系列第三篇,将着重理清楚线性分类模型——感知机。
1.感知机理论
感知机模型主要是解决二类分类问题的线性分类模型,其分为原始形式与对偶形式。其输入为实例的特征向量,输出为实例的类别(分为正实例和负实例,取值分别为+1和-1)。在几何意义上,感知机将输入的实例划分为正负两类的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化操作,从而求得感知机模型。
(待后续更新!)
机器学习算法实践之贝叶斯算法
本文作为算法实践系列第二篇,将重点讲解朴素贝叶斯算法与贝叶斯算法理论与应用。
1.朴素贝叶斯算法理论
朴素贝叶斯算法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集合,首先基于特征条件独立假设学习输入/输出的联合概率分布,然后基于此模型,对于给定的输入的X,利用贝叶斯定理求出后验概率最大的输出的Y值,即为输入实例所属的分类。
此处假设输入空间X为n维向量的集合,输出空间为数据分类标记集合Y={c1,c2,c3….,ck},x是定义在X上的随机向量,y是定义在Y上的随机向量,p(x,y)是x和y的联合概率分布,训练数据集T={(x1,y1),(x2,y2),…,(xN,yN)}是由P(x,y)独立同分布产生的。在上述条件下,朴素贝叶斯法通过训练数据集,先学习先验概率分布p(Y=ck),k=1,2….K,之后在学习条件概率分布P(X=x|Y=ck)=P(X(1)=x(1),…,X(n)=x(n)|Y=ck),k=1,2,….,K(注意:此处(n)是指输入空间的第n个特征向量,也可以理解为上标序号)。最后学习得出两者参数值后,在运用贝叶斯定理,对给定的输入实例x=(x(1),x(2),x(3),…x(n))^T的后验概率P(Y=ck)P(X(n)=x(n)|Y=ck)P(X(n-1)=x(n-1)|Y=ck)…P(X(1)=x(1)|Y=ck)计算比较,最终后验概率最大值所在的Y=ck值,即为该输入实例所属分类情况。
其中,对于后验概率最大化即为所属输入实例的分类情况,其含义即为满足了期望风险最小化准则,即以此准则推导出的函数式f(x)=arg max(P(ck|X=x))就是朴素贝叶斯法所采用的原理。此处只是略微提一下原理,请勿和判别模型f(X)决策函数搞混,贝叶斯分类方法与朴素贝叶斯都属于生成模型,由数据驱动学习概率分布得出分类结论,没有决策函数f(x).
2.朴素贝叶斯算法实践步奏
2.1 前置理论——极大似然估计
朴素贝叶斯法中,学习表示通过数据出发估计先验概率P(Y=ck)和条件概率P(X(n)=x(n)|Y=ck),一般通过极大似然估计法估计相应概率。首先,先验概率P(Y=ck)的极大似然估计计算式如下图所示:
其中I为指示函数,满足条件值为1否则为0。之后,在设第j个特征向量x(j)可能取值的集合为{a[j,1],a[j,2],a[j,3],……,a[j,S]},条件概率p(X(j)=a[i,j]|Y=cK)的极大似然估计计算式即为:
其中j=1,2,…,n;l=1,2,…,s;k=1,2,….,K,式中x(i)(j)是指第i个样本的第j个特征,a[j,l]是指第j个特征可能取第l个值。
*2.2 算法实践步奏
- 对数据进行预处理
- 计算数据集中每个特征向量的先验概率和条件概率
- 对于给定的实例x=(x(1),x(2),x(3),…x(n))^T,计算后验概率P(Y=ck)P(X(n)=x(n)|Y=ck)P(X(n-1)=x(n-1)|Y=ck)…*P(X(1)=x(1)|Y=ck)的值
- 得到最后根据后验概率大小得到输入实例预测的分类结果。
3.朴素贝叶斯算法实践
具体代码我已上传至Git仓库,详情请点击查看,
数据为模拟分类数据,所用python为3.5版本,执行结果如图所示:
4.贝叶斯估计理论
在用朴素贝叶斯算法进行数据分类处理时,可能会遇到所要估计的概率值为0的情况。这种情况是会影响到具体的后验概率计算结果,使得分类产生偏差,鉴于此,使用贝叶斯估计方法就可以避免上述问题。其中,贝叶斯估计执行逻辑与朴素贝叶斯一样,唯一的区别在于先验概率和条件概率计算式不同。
其中,先验概率的贝叶斯估计为:
条件概率的贝叶斯估计为:
在上述式子中,λ≥0,等价于在随机变量各个取值的频数上加上一个正数λ>0。当λ=0时为极大似然估计。在常用的数据分类器中,取λ=1称为拉普拉斯平滑(Laplace smoothing)。最终该算法学习过程与朴素贝叶斯学习过程一样,就不在对其代码进行扩展,整个贝叶斯相关的算法基础模型也就到这里结束了。
机器学习算法实践之KNN算法
1.KNN算法前置概念
在进行算法基本描述前,先介绍两个概念。对于数据分类算法中,一般性应用场景即为监督学习。监督学习方法分为生成方法和判别方法,最终所得到的模型即为生成模型和判别模型。生成方法由数据学习联合概率分布P(X,Y),然后求出条件概率分布P(Y|X)作为预测模型。该模型特点在于表现了给定输入X产生输出Y的生成关系,是基于数据出发所触发的模型学习过程,其可以还原出联合概率分布P(X,Y),判别方法不能。除此外,生成方法学习收敛速度更快,当样本容量增加的时候,学到的模型可以更快的收敛于真实模型。典型的生成模型有:朴素贝叶斯法和隐马尔可夫模型。
判别方法是由数据直接学习决策函数f(X)或者条件概率分布P(Y|X)作为预测的模型,此处待引入训练数据后,由具体训练数据集得出函数模型后,带入具体测试数据集的得出具体数据分类结论即可。判别方法直接面对预测,学习准确率更高。此处需要注意的是,在存在数据特征预处理不完善或者其他无法量化所有特征参数情况下,一旦存在隐变量,判别方法则无法使用,但可以使用生成方法。判别模型有K近邻法,感知机,决策树,logistic回归模型等。
2.KNN算法基础理论描述
KNN算法,即为K近邻算法,其最简单的描述即为:给定一个训练数据集,将其分好类之后,对于新输入的实例,在训练数据集中找到与该实例最邻近的K个示例,这K个示例多数属于某一类,就将该输入实例分为这一类。鉴于此,我们讨论下算法核心思想,距离度量。
2.1KNN算法距离度量
在训练数据集给定的情况下,找到具体数据每一项特征向量,将其结合在一起构成一个特征向量集合,即为特征空间。在使用欧式距离公式(公式如下图所示):
运用特征空间里的参数将其实例之间的欧式距离计算出来,结果数值越小则两个实例点几何距离越近,分类结果越相似。
2.2 K值选择
k值的选择也要在偏差与方差之间取得平衡。若k取很小,例如k=1,则分类结果容易因为近似误差减小而出现错误,导致只有与输入实例相近的训练实例才会有分类效果,其他实例则无法准确分类,容易发生过拟合现象;若k取很大,例如k=N(N为训练集的样本数),则对所有测试样本而言,其利用较大领域范围中的训练实例进行预测。与输入实例较远的训练实例也会对预测产生作用,使得近似误差增大,使得预测产生错误。利用交叉验证(Cross Validation)评估一系列不同的k值,选取结果最好的k值作为训练参数。此文中数据情况简单,K值就取的是5即可达成需要。
2.3 分类决策规则
算法中的分类决策规则为多数表决,即由输入实例的K个近邻的实例中的多数类来决定该输入实例所属分类情况。
3.KNN算法分类步骤
- 对数据进行预处理,多个特征参数的数据要进行归一化处理
- 求输入实例与训练样本之间的相似性
- 依据欧式距离数值从小到大排序
- 选择前K个最为相似的数据中,得到多数相同分类样本对应的类别
- 得到输入实例预测的分类结果。
4.KNN算法实践
具体代码我已上传至Git仓库,详情请点击查看,数据来源于kaggle上某约会网站训练数据,具体仓库中有,最终数据可视化展示结果如下图所示:
图中横轴是训练数据集分类,Y轴是训练数据与输入实例欧式距离,红色即为与实例相近的实例分类情况。
到此,此算法大致就结束了。
WY's FE Resources
基于Node.js的开发技术
1.Github;
2.VUE.JS;
3.vue.js论坛;
4.iview2.0 UI库,这是vue,js专有UI库;
5.segmentfault,IT技术讨论社区;
6.react小书,react技术入门必备;
7.Webpack很好地总结资料,搭建脚手架基础的资料;
8.Webpack中文文档,很好地文档资料;
9.Fetch交互方式,基于promise前后端异步交互方法;
10.Axios中文文档,前后端交互方式文档,与fetch不一样;
11.Ant Design,这是react技术广泛使用的UI库;
12.Ant Motion,这是基于react的动画解决方案;
13.Express,基于node.js的前端调试服务器,可以解决跨域访问问题与其他模拟后端请求问题;
14.V2EX,这是技术解决方案的讨论平台;
15.Stack Overflow,在线技术交流平台;
16.jsbin,在线JS代码编写调试工具;
17.Mongodb,数据库教程;
18.Echart,百度推出的数据可视化库;
19.D3.js另一种功能强大的数据可视化库;
基于原生体系的开发技术
1.FIS,百度推出的前端调试服务器;
2.JQ与bootstrap常用效果库;
3.Bootstrap可视化布局,在线进行页面布局,生成相应bootstrap代码。
JS(ES6)实践记录(三)
这篇文章将记录JavaScript ES6下函数相关内容,在ES6中,函数特性大幅度更新,使得JS编程更加灵活。
1.ES6中默认参数
在ES6中,JS简化了为形参提供默认值的过程,如果没有参数传入值则为其提供一个初始值。示例如下:
**function makerequest(url,timeout=2000,callback=functio(){}){
//函数其余部分
}
**
>
其中,url为必须参数,其余两个参数为默认参数.对于函数默认参数而言,个数没有限定。在ES6中,如果一个函数使用了默认参数值,则无论是否显式定义了严格模式,arguments对象行为与ES5严格模式保持一致。默认参数值存在使得arguments对象保持与命名参数分离,默认参数在函数中的变化不会导致arguments对象改变。比如:
**function mixArgs(first,second=”b”){
console.log(arguments.length);//1
console.log(first===arguments[0]);//true
console.log(second===arguments[1]);//false
first="c";
secod="d";
console.log(first===arguments[0]);//false
console.log(second===arguments[1]);//false
}
mixArgs(“a”)
**
>
此例子在ES6中,只给mixArgs传入了一个参数字符串a,因此arguments元素构成的数组只有一个元素字符串a,故其长度为1,且会一直为初始值,不会受函数内部变量变化影响。
对于默认参数表达式而言,函数可以通过非原始传参从而得到默认参数的值,示例如下:
**let value=”5”;
function getvalue(){
return value++;
}
function add(first,second=getvalue()){
return first+second;
}
console.log(add(1,1));//2
console.log(add(1));//6
console.log(add(1));//7
**
>
在此示例中,初次解析函数声明时不会调用getvalue()方法,只有当调用add()方法并传入第二个参数时才会调用。变量value初始值为5,每次调用getvalue()方法时加1.第一次调用add(1),只传入一个参数,没有传入第二个参数,所以执行函数getvalue,使得second默认值变为5,之后代入到函数add()中执行得到6,后面在执行add(1)与之同理。在执行add(1,1)时,直接执行逻辑“1+1”即可返回2.由此观之在没有传入具体参数赋予默认参数时,函数执行过程中任何时候都可以改变其值。
除了上面函数传值外,还有一种是固定参数与默认参数之间传值,比如:
**function getvalue(value){
return value+5;
}
function add(first,second=getvalue(first)){
return first+second;
}
console.log(add(1,1));//2
console.log(add(1));//7
**
>
在这个示例中,声明second=getvalue(first),所以尽管add(1,1)返回是2,但在执行默认参数为变量的函数值时,执行add(1)返回(1+6)即为7.除此外,还要注意。在引用默认参数时,只允许后面的参数引用前面参数的值,即先定义的参数不能访问后面的参数值,否则会抛出错误。
2.ES6中不定参数
在函数命名前加三个点(…)就表明这是一个不定参数,该参数为一个数组,包含着自它之后传入的所有参数,通过这个数组名即可逐一访问里面的参数。代码示例如下:
**function pick(object,…keys){
let result = object.create(null);
for (let i=0,len=keys.length;i<len;i++){
result[keys[i]] = object[keys[i]];
}
return result;
}
**
>
在这个示例中,不定参数keys包含的是object之后传入的所有参数,除此外需要注意每个函数最多只能声明一个不定参数而且一定要包含在末尾。注意,函数的length属性统计的是函数命名参数数量,不定参数的加入不会影响length属性的值。在本示例中,只会pick()函数length值为1,因为只会计算object。
3.展开运算符
JS(ES6)实践记录(二)
Javascript ES6扩展了字符串一些新的功能,在这里主要记录一下字符串新增内容。
1.codePointAt()方法
ES6新增加了完全支持UTF-16的codePointAt()方法,此方法接受编码单元的位置而非字符位置作为参数,返回与字符串中给定位置对应的码位。示例如下:
**let text=”比特s”
console.log(text.codePointAt(0))//27604
console.log(text.codePointAt(1))//29305
console.log(text.codePointAt(2))//115
**
>
2.String.fromCodePoint()方法
与codePointAt()方法相反,该方法根据指定的码位生成一个具体的字符串。示例如下:
console.log(String.fromCodePoint(27604));//比
console.log(String.fromCodePoint(29305));//特
console.log(String.fromCodePoint(115));//s
3.normalize()方法
在ES6中,js要对字符串进行对比操作时,需要将字符串标准化为同一种形式,故新增normalize()方法,此方法提供了一个Unicode的标准化形式,将具体调用此方法字符转化为相同标准以方便执行具体对比操作,码位计算等等。代码示例如下:
let value=[‘ae’,’be’];
let normalized=value.map(function(text){
return text.normalize();
});
normalized.sort(function(a,b){
if(a<b){
console.log(-1);
}else if(a===b){
console.log(0);
}else{
console.log(1);
}
});//-1此处将数组value中存储的字符串转换为统一标准后调用sort()方法进行排序处理,最后成功返回值-1.
4.字符串中子串识别
此处主要包含3个方法:
includes()方法,如果在字符串中检测到指定文本则返回true,否则返回false。
startsWith()方法,如果在字符串起始部分检测到指定文本则返回true,否则返回false。
endsWith()方法,如果在字符串的结束部分检测到指定文本则返回true,否则返回false。
以上3个方法都接受两个参数,第一个参数指定要搜索的文本,第二个参数指定搜索位置的索引值,为可选参数。如果指定了第二个参数,则includes()方法和startsWith()方法会从索引值位置开始匹配,endsWith()方法会从字符串长度减去这个索引值位置开始匹配。如果不指定第二个参数,则includes方法和startsWith()方法从字符串起始处开始匹配,而endsWith()则从字符串末尾处开始匹配。示例如下:**let text=”hello world!”;
console.log(text.includes(“hello”));//true
console.log(text.endsWith(“!”));//true
console.log(text.startsWith(“w”));//false
console.log(text.includes(“o”,4));//true
console.log(text.endsWith(“o”,4));//false
console.log(text.startsWith(“o”,4));//true
**
>
5.repeat()方法
repeat()方法接受一个number类型的参数,表示当前字符串的重复次数,返回值是当前字符串重复一定次数后的新字符串。
示例如下:
console.log(“x”.repeat(3));//“xxx”
console.log(“hello”.repeat(2));//“hellohello”
console.log(“abc”.repeat(4));//“abcabcabcabc”
6.模板字面量
在ES6中JS通过模板字面量补齐了ES5所缺少的字符串特性,通过多行字符串、基本字符串格式化、HTML转义等全新的方法来跳出已有的JS字符串体系,解决了相关问题。
6.1 HTML转义
代码示例如下:
let message =
hello world!
;
console.log(message);//“hello world!”
console.log(typeof message);//string
console.log(message.length);//12此处使用模板字面量语法创建了一个字符串,直接用反撇号将其包含起来即可。这是变量的值与一个普通字符串无差异。
如果想在字符串中使用反撇号,就用反斜杠()将其转义即可,代码示例如下:let message =
\
hello` world!; console.log(message);//"
hello` world!”
console.log(typeof message);//string
console.log(message.length);//14其中需要注意的是,在模板自变量中,不需要转义单、双引号。
6.2 多行字符串
在ES6中新增多行字符串写法,类比于python中raw字符串方式理解,主要有如下几种代码示例:let message =
hello world!
;
console.log(message);//“hello
// world!”
console.log(typeof message);//string
console.log(message.length);//30在模板字面量中··之间包含的皆属于字符串一部分,所以直接将字符串换行即可。还有另一种转义方法创建多行字符串,代码如下:
let message =
hello\nworld!
;
console.log(message);//“hello
// world!”
console.log(typeof message);//string
console.log(message.length);//12转义方法将js同行字符串换行处理,类似于c语言一样,长度就是字符数组元素个数。
对于ES5标准下多行字符串添加方式示例如下,对比观之即可:var message=[“hello”,
“world”].join(“\n”);
console.log(message)
6.3 字符串占位符
字符串占位符是由${}组成,中间可以包含任意JS表达式。正在一个模板自变量中,我们可以将任何合法的js表达式嵌入到占位符中并将其作为字符串的一部分输出到结果中。
代码示例如下:
*let count=10,
price=0.25,
message=`${count} cost $${(countprice).toFixed(2)}`;
console.log(message);//10 cost $2.50
**
>
综上,ES6中对于字符串操作又定义了很多新东西,这些果然为JS增添了无穷魅力。
JS(ES6)实践记录一
Javascript ES6标准自推广以来,使得js这门语言应用范围越来越广。很庆幸我在读研期间能够有时间对这门语言按照自己的方式系统性理解,学习,记录。在此我希望自己能够借此机会,能够虔诚的走上技术追寻的道路,以下就此开始Javascript旅程。
1.var申明与变量提升机制
在ES5标准中常用var声明具体变量,无论在js代码过程中何处声明,期都会被当做当前作用域顶部声明的变量,这就是具体变量提升机制。比如以下代码:
function getvalue(condition){
if(condition){
var value=”blue”;
return value;
}else{
return null;
}
}
}由于在JS函数预编译阶段,变量value的声明会被提升只函数顶部,其他条件判断依然在远处,从而导致else语句能访问到value变量,由于变量value尚未初始化,从而返回值为undefined。因此,此处对于没有块级作用域的ES5标准下的js开发者带来了困惑。
2.块级声明
在ES6中,JS作用域分为全局作用域,块级作用域,局部作用域。其中块级声明用于声明在指定块之外无法访问的变量。块级作用域存在于:函数内部,{}包含的块中。
2.1 Let声明
let用法与var相同,但用let代替var声明变量,会将变量作用域限制在当前代码块中。具体代码示例如下:
function getvalue(condition){
if(condition){
let value=”blue”;
return value;
}else{
return null;
}
}
}与以上例子对比可知,通过let声明变量value后,变量不会提升至函数顶部。当执行流离开if程序块后,value立即被销毁,则如果condition值为布尔值false时,就不会声明并初始化value的值,从而返回null。除此外,对于重声明情况,es5会后面变量覆盖前面变量的值,而在ES6中,在同一个作用域下严禁重声明,否则会抛出错误。
2.2 const声明
使用const声明的是常量,其值不可更改,类似于Python中tuple元素一样。每一个const声明的常量必须初始化才有意义。其和let类似,皆声明创建一个块级作用域,域外变量无法访问域内常量。同时常量也不会提升至作用域顶部,示例如下:
if(condition){
var max=6;
//更多代码
}
//此处无法访问max在这段代码中,常量max在if程序块中执行后即刻销毁,在代码块外访问不到这个常量。除此外,const严禁重声明行为发生,会导致错误抛出情况的发生。
3.临时死区(TDZ)
Javascript引擎在代码执行时,先扫描代码,当发现变量声明时,若遇到var声明,将会把它们提升至作用域顶部。若遇到let和const声明,会将声明放置于TDZ中。因此,在没有执行过变量语句之前访问TDZ中的变量,就会报错。只有执行具体变量声明与初始化后,变量才会从TDZ中移出,然后可以正常访问。示例代码如下:
if(condition){
console.log(typeof value);//引用错误
let value=”blue”
}在以上代码实例中,console.log语句会导致抛出错误。由于let定义并初始化变量value的语句不会执行,其还位于”临时死区”中,这种现象明显的展现出let,const这类声明的变量不提升的效果。
4.循环中块级作用域绑定
请看如下很常见的代码示例:
**
var a=[];
for(var i=0;i<=10;i++){
a.push(function(){
console.log(i);
});
}
a.forEach(function(func){
func();
})**
>
为了使得预期结果是输出数字0——10,故初步写出上述代码,结果发现输出了10次重复数字10,这是因为var在全局作用域下,任何局部作用域都能访问到,因此每次循环迭代都是共享着变量i,循环内部创建的函数全部保留了对于变量的引用情况。循环结束后变量i的值为10,覆盖了前面循环产出的数值,所以每次调用console.log就会输出数字10.因此若将var声明的变量i改为let进行声明,则每次循环时let声明都会创建一个新变量i,并将其初始化为当前的值,循环内部创建的每个函数都会得到属于他的值,因此会输出数字0-10.代码示例如下:
**
var a=[];
for(var let=0;i<=10;i++){
a.push(function(){
console.log(i);
});
}
a.forEach(function(func){
func();//0-10
})
>
5.全局块级作用域绑定**
当var被用于全局作用域时,它会创建一个全局变量作为全局对象(window对象)的属性。因此用var可能会覆盖一个已经存在的全局变量而如果使用const和let声明变量,则不会破坏全局作用域,不会存在此种情况,具体三种情况代码示例如下:
**
let request=”hello”;
console.log(request);//hello
console.log(window.request==request);//false
const request=”hello”;
console.log(request);//hello
console.log(window.request==request);//false
var RegExp=”hello test”;
console.log(RegExp);//hello test
console.log(window.RegExp==RegExp);//true**
>
由此可见,对于三种声明方式而言,块级作用域下声明更加安全可靠。let和const行为和var类似,但它们在循环中的行为却不一样。在循环中,let和const每一次迭代都会创建新的绑定,从而使循环体内创建的函数可以访问到相应迭代的值,而不是入var一样输出最后一次迭代的值。鉴于此,对于三种声明最佳实践方案是:默认情况下使用const,只有在确定需要改变变量值的时候使用let,循环最好使用let。全局作用域下,涉及跨window或者frame访问代码时最好使用var声明,这样可以避免一些错误,也能提升安全性。