Arthur Samuel非正式的定义过,机器学习是在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。
简单的来讲,我们给计算机足量的数据,这些数据可以是已标注过判定结果的(监督学习),也可以是没有经过标注的(无监督学习),计算机从这些数据中抽象出模型,也即可以看做发现这些数据的之间的规律与联系,然后当训练完成后,给予其训练集之外的数据(测试集),计算机就能『举一反三』,根据学习训练样本所得到的模型,去预测测试样本的相关属性。
我们根据训练样本以及所需解决问题的不同选择恰当的机器学习算法,建立恰当的模型,以求得到最好的预测效果。
这里我采用吴恩达博士的分法,将机器学习分为四类:监督学习、无监督学习、强化学习、迁移学习。
监督学习:是利用已知类别的样本(即有标记的样本 labeled sample,已知其相应的类别),调整分类器的参数,训练得到一个最优模型,使其达到所要求性能,再利用这个训练后的模型,将所有的输入映射为相应的输出,对输出进行简单的判断,从而实现分类的目的,这样,即可以对未知数据进行分类。
通俗的来讲,我们给计算机一堆选择题(训练样本),并同时提供了它们的标准答案,计算机努力调整自己的模型参数,希望自己推测的答案与标准答案越一致越好,使计算机学会怎么做这类题。然后再让计算机去帮我们做没有提供答案的选择题(测试样本)。
无监督学习:实现没有有标记的、已经分类好的样本,需要我们直接对输入数据集进行建模,例如聚类,最直接的例子就是我们常说的『人以群分,物以类聚』。我们只需要把相似度高的东西放在一起,对于新来的样本,计算相似度后,按照相似程度进行归类就好。
通俗的来讲,我们给计算机一堆选择题(训练样本),但是不提供标准答案,计算机尝试分析这些题目之间的关系,对题目进行分类,计算机也不知道这几堆题的答案分别是什么,但计算机认为每一个类别内的题的答案应该是相同的。
强化学习:所谓强化学习就是智能系统从环境到行为映射的学习,以使奖励信号(强化信号)函数值最大,强化学习不同于连接主义学习中的监督学习,主要表现在教师信号上,强化学习中由环境提供的强化信号是对产生动作的好坏作一种评价(通常为标量信号),而不是告诉强化学习系统RLS(reinforcement learning system)如何去产生正确的动作。
通俗的来讲,我们给计算机一堆选择题(训练样本),但是不提供标准答案,计算机尝试去做这些题,我们作为老师批改计算机做的对不对,对的越多,奖励越多,则计算机努力调整自己的模型参数,希望自己推测的答案能够得到更多的奖励。不严谨的讲,可以理解为先无监督后有监督学习。
迁移学习:考虑到大部分数据或任务是存在相关性的,所以通过transfer learning我们可以将已经学到的参数分享给新模型从而加快并优化模型的学习不用像之前那样learn from zero。把已学训练好的模型参数迁移到新的模型来帮助新模型训练数据集。
深度学习是机器学习的一种,是一种『抽象出的模型』在结构上比较特殊(有深度且可以堆叠,比如各类神经网络)的机器学习方法。
一句话概要,将标注好类别的训练样本映射到X(选取的特征数)维的坐标系之中,同样将测试样本映射到X维的坐标系之中,选取距离该测试样本欧氏距离(两点间距离公式)最近的k个训练样本,其中哪个训练样本类别占比最大,我们就认为它是该测试样本所属的类别。kNN是监督学习算法。
kNN的缺点在于计算的时间空间复杂度都太高,首先内存中需要存储所有的训练样本点,而且每个新测试样本需要通过kNN算法分类,都要计算这个测试样本与所有训练样本点的欧式距离。
kNN可以处理数值型(从无限的数值集合中取值,如0.100,42.001等)和标称型(只在有限目标集中取值,如真与假)数据。一种特征对应一个维度,一种特征下的数据可以数值型的也可以是标称型的。
一句话概要,决策树算法的核心在于决策树的构建,每次选择让整体数据香农熵(描述数据的混乱程度)减小最多的特征,使用其特征值对数据进行划分,每次消耗一个特征,不断迭代分类,直到所有特征消耗完(选择剩下数据中出现次数最多的类别作为这堆数据的类别),或剩下的数据全为同一类别,不必继续划分,至此决策树构建完成,之后我们依照这颗决策树对新进数据进行分类。
决策树长什么样?
决策树示例
决策树算法较之于kNN算法一个很显著的不同在于,kNN算法需要持续使用全部的训练数据,而决策树算法经过训练构建出决策树之后,就不再需要将所有的训练样本保持在内存中了,这颗决策树就是在训练样本中抽象出来的模型。
香农(信息)熵用来描述数据的混乱度,混乱度越大熵越大,计算公式如下:
分类前整个数据集的熵
Pi
指第i种数据在这个数据集中所占的比例。
定性理解,如果这个数据集中所包含的数据类别越少,它的熵也就越小(熵是正数,因为对数算出来的结果是负数)。
如果我们将这个数据集按照数据的某个特征(不是按数据类别分,因为我们做的是学习+预测,不是对训练样本分类)进行了分类,分成了多个小数据集,那整个数据集熵的计算公式如下:
按某种特征分类后整个数据集的熵
我们需要知道按照这个特征分类过后,整个数据集的熵减少了多少,也就是信息增益是多少,计算公式如下:
信息增益
信息增益越大,也就是我们对数据的分类越有效,整个数据集的熵减小的越多。
随机森林既可以分类也可以回归
下面是随机森林的构造过程:
1. 假如有N个样本,则有放回的随机选择N个样本(每次随机选择一个样本,然后返回继续选择)。这选择好了的N个样本用来训练一个决策树,作为决策树根节点处的样本。
2. 当每个样本有M个属性时,在决策树的每个节点需要分裂时,随机从这M个属性中选取出m个属性,满足条件m << M。然后从这m个属性中采用某种策略(比如说信息增益)来选择1个属性作为该节点的分裂属性。
3. 决策树形成过程中每个节点都要按照步骤2来分裂(很容易理解,如果下一次该节点选出来的那一个属性是刚刚其父节点分裂时用过的属性,则该节点已经达到了叶子节点,无须继续分裂了)。一直到不能够再分裂为止。注意整个决策树形成过程中没有进行剪枝。
4. 按照步骤1~3建立大量的决策树,这样就构成了随机森林了。
在建立每一棵决策树的过程中,有两点需要注意采样与完全分裂。
首先是两个随机采样的过程,random forest对输入的数据要进行行、列的采样。对于行采样,采用有放回的方式,也就是在采样得到的样本集合中,可能有重复的样本。假设输入样本为N个,那么采样的样本也为N个。这样使得在训练的时候,每一棵树的输入样本都不是全部的样本,使得相对不容易出现over-fitting。然后进行列采样,从M个feature中,选择m个(m << M)。
之后就是对采样之后的数据使用完全分裂的方式建立出决策树,这样决策树的某一个叶子节点要么是无法继续分裂的,要么里面的所有样本的都是指向的同一个分类。一般很多的决策树算法都一个重要的步骤——剪枝,但是这里不这样干,由于之前的两个随机采样的过程保证了随机性,所以就算不剪枝,也不会出现over-fitting。
随机森林和使用决策树作为基本分类器的(bagging)有些类似。以决策树为基本模型的bagging在每次bootstrap放回抽样之后,产生一棵决策树,抽多少样本就生成多少棵树,在生成这些树的时候没有进行更多的干预。而随机森林也是进行bootstrap抽样,但它与bagging的区别是:在生成每棵树的时候,每个节点变量都仅仅在随机选出的少数变量中产生。因此,不但样本是随机的,连每个节点变量(Features)的产生都是随机的。
一句话概要,朴素贝叶斯算法普遍用在文本处理中的垃圾邮件过滤,先计算联合概率分布,然后再利用贝叶斯公式计算给定某个样本数据后,被分到每个类别的概率分别是多少,然后取被分到概率最大的类别作为该样本数据的类别。朴素贝叶斯算法是生成方法,而前面讲过的两种算法是判别方法。
朴素贝叶斯算法的『朴素』在于这样一个假设,每个单词(特征)出现的可能性是完全独立的,和其他单词是否出现、出现在哪无关。朴素贝叶斯算法的另一个假设在于,每个单词(特征)对于判定整条文档的类型同等重要。这两个假设都是有瑕疵的,某些单词就是大多同时出现,判断一条文档的基本类别也不需要阅读整条文档的每一个单词,但即使这样,朴素贝叶斯算法在实际应用中的表现也是很好的。
什么是贝叶斯公式?
贝叶斯公式
贝叶斯公式是概率论中一定会讲到的内容,这里c
和x
均指『某种情况』,而p(c)
、p(x)
指发生这两种情况的概率,p(x|c)
指在已知c
情况发生的条件下x
情况发生的概率,p(c|x)
同理。
举个例子,我们有三个棋子、两个碗,第一个碗里一个黑子一个白子,第二个碗里只有一个白子,我们要计算已知取到白子的情况下,这个白子是在第一个碗里取出的概率,如果用贝叶斯公式计算,我们先算分母,取到白子的概率是3/4,再算分子,取到第一个碗的概率是1/2,在取到第一个碗的前提情况下,取到白子的概率是1/2,最后算出已知取到白子的情况下,这个白子是在第一个碗里取出的概率是1/3。想一想,是不是如果不断的抽棋,抽到的白子更多的来源于第二个碗,抽到第二个碗里的白子的情况已经占到所有情况的1/2了,剩下的1/2还要分一半给第一个碗里的黑子。
在朴素贝叶斯算法中,我们用到的贝叶斯公式是经过拓展的:
拓展后的贝叶斯公式
这里的w
替代了x
,w
与x
的区别在于w
是一个向量,而x
是一个值,w
是一系列情况,x
是一个情况。如果将w
展开,p(w|c)
=p(w0,w1,w2,w3···|c)
,又因为我们之前的『朴素』假设,每个特征(单词)的出现概率都是独立的,和其他特征(单词)的出现没有关系,所以我们的p(w0,w1,w2,w3···|c)
=p(w0|c)
x p(w1|c)
x p(w2|c)
x p(w3|c)
···,p(w)
、p(c|w)
同理。
在朴素贝叶斯分类算法中,我们通常用c
代指『文档属于某种类别』这种情况,用w
向量代指这个文档本身,w0
、w1
···这些用来表示文档中是否含有(或含有几个,是否含叫做词集模型,含有几个叫做词袋模型)某特定单词(在朴素贝叶斯算法中,所有的训练文档中出现过的所有单词去重的数量,就是w
所包含的维度个数,w
相当于一个单词表)。
以垃圾邮件过滤举例讲整个朴素贝叶斯算法的流程。
首先是建立单词表(也就是建立w
)和用单词表表示所有的训练文档。我们遍历所有的训练文档,把所有出现过的单词去重放进一个数组里面。然后用这个单词表w
表示我们所有的训练文档,每条训练文档被表示成和单词表数组等长的一个数组,如果是词集模型,就用0、1分别表示对应位置的单词在这条文档里是否出现,如果是词袋模型,就用对应位置的数字表示对应位置单词的出现次数,这个数组叫做这条文档的词向量。同时我们的朴素贝叶斯算法是监督学习算法,我们还需要有一个标注数组,这个数组的大小和训练文档的条数相同,用于记录这些训练文档哪几条是垃圾邮件,是的标0,不是的标1。
我们用p(c0|w)
和p(c1|w)
分别代表这个词向量所对应的文档属于垃圾邮件或正常邮件的概率,如果p(c0|w)
> p(c1|w)
那我们就认定其为垃圾邮件。
当接到新文档后,先将其转化为词向量,然后代入贝叶斯公式计算,根据贝叶斯公式,需要求出p(c0|w)
和p(c1|w)
,因为分母p(w)
对于该条文档来讲是个常数,与c
取c0
还是c1
无关,所以可以不计算,只需要计算分子p(c)
和p(w|c)
。p(c0)
、p(c1)
分别代表文档是垃圾邮件和正常邮件的概率,这个很好算,用前面的标注数组就能算出,也就是用训练文档是垃圾邮件和正常邮件的概率来代替。
然后我们只需要计算这个新文档的p(w|c0)
和p(w|c1)
,也就是c0
(垃圾邮件)和c1
(正常邮件)中出现该文档的概率(即该文档所包含的每个单词出现概率的乘积,文档中几次出现该单词,就乘以几次这个单词的出现概率),即可根据p(w|c)
乘p(c)
的大小判定该样本的类别。
新样本的p(w|c0)
和p(w|c1)
如何计算?上面说了,是用两种邮件的训练样本中每个词(包含在新样本中的每个词)出现概率的乘积求出,那两种邮件的训练样本每个词出现的概率怎么求?我们把之前的训练文档按照垃圾邮件和正常邮件分开处理,用每个词的出现次数(这里用词袋模型)除以总词数,即可得出垃圾邮件和正常邮件训练样本中所有单词的出现概率,然后根据单词在新样本中的出现次数,将其出现概率相乘,得到新文档的p(w|c0)
和p(w|c1)
,然后分别乘以p(c0)
、p(c1)
,比较其大小,即可得出新样本的类别。
朴素贝叶斯分类算法的思想如上文所述,但还存在着一些特殊情况需要处理,比如我们上面说计算新文档的p(w|c0)
和p(w|c1)
时,要分别用到新文档中包含的单词分别在垃圾邮件样本和正常邮件样本中所出现的概率,但要是新文档中有个单词在垃圾邮件(或正常邮件)中从来都没出现过怎么办,那概率就是0,再乘以其他单词的在垃圾邮件(或正常邮件)中的出现概率,最终结果一定是0,也就是这条文档已经被宣判不可能是垃圾邮件(或正常邮件)了,这样太过武断,所以我们做一下修改,在训练时,让每个单词的初始出现次数都设置为1,总出现次数初始设置为2,以避免上面提到的问题。
那要是有些单词在新文档里面出现次数为0怎么办?那就不乘进去。
还有个小问题就是因为乘的数都小于1,乘的次数又那么多,所以会出现下溢出,最后的结果四舍五入都变成0了,所以我们采用自然对数函数来解决这个问题,乘变成了加,乘方变成了直接相乘,如果出现次数为0,那一项就为0,不加进去,也就相当于不乘进去了,这里不再详细讲。
还有一点,如果某个特征取值是连续的怎么办,就不适宜按照某个特定值计算概率了,上例中的特征都是单词的出现次数,都是离散的,但是如果我想再增加考虑比如邮件的发送时间,时间是连续的,如果不是同一秒发送的邮件就被认为不同,那对于分类几乎没有帮助(可以理解为上例中我们的单词表里又增加了许多单词,但是这些单词不论在垃圾邮件还是正常邮件里出现的概率都极低,对于分类没有帮助),解决方法是我们按时间段划分,比如分为上午、下午、傍晚、深夜,即相当于在单词表中添加了四个单词,不同的文档都会包含这四个单词中的其中一个,如果垃圾邮件的发送时间绝大多数都在深夜,那在使用垃圾邮件训练样本训练时,深夜这个单词的出现概率就会非常高,如果新文档也是在深夜发送,就会显著提高这条新文档被认为是垃圾邮件的概率。
另外还有一点就是最开始概要的时候所提到的生成方法和判别方法,生成方法和判别方法是对监督学习算法的分类,前面讲到的kNN和决策树是判别方法,而这部分讲的朴素贝叶斯分类算法是生成方法,由判别方法学到的模型叫做判别模型,由生成方法学到的模型叫做生成模型。
判别方法由数据直接学习决策函数Y=f(X)或者条件概率分布P(Y|X)作为预测的模型,即判别模型。基本思想是有限样本条件下建立判别函数,不考虑样本的产生模型,直接研究预测模型。典型的判别模型包括k近邻,感知机,决策树,支持向量机等。
生成方法由数据学习联合概率密度分布P(X,Y),然后求出条件概率分布P(Y|X)作为预测的模型,即生成模型:P(Y|X)= P(X,Y)/ P(X)。基本思想是首先建立样本的联合概率概率密度模型P(X,Y),然后再得到后验概率P(Y|X),再利用它进行分类。
判别方法更多的关注各个类别之间的区别,而生成方法更多关注各个类别内部的相似度。判别方法画一条线,明确这种差别,线左边是类别A,线右边是类别B;生成方法拿样本去比较两个类别的已有数据,看看这个样本生成自哪个类别的可能性更大。
由生成模型可以得到判别模型,但由判别模型得不到生成模型。
一句话概要,我们被给予一堆X维的数据,我们希望通过一条直线将这堆数据正确的分为两类(不是所有的数据都能通过线性模型被正确分类)。我们建立了一个线性函数模型t=w*x
,w
与x
均为X维的向量。先将w
置为初始向量,输入训练数据x
后,将得到的t
带入Sigmoid函数,将0.5作为阈值,大于0.5的为一类,小于0.5的为另一类。训练过程为,先利用最大似然估计得到目标函数,再利用梯度上升算法优化目标函数,使得训练样本生成概率最大化。
虽然叫Logistic回归算法,不过它和之前三个算法一样都是分类算法,它将给定数据划分到两个类别之一,属于判定方法,监督学习算法。
Logistic回归算法的原理并不困难,但有几个点需要介绍,比如Sigmoid函数、梯度上升算法、随机梯度上升算法等,这些概念都广泛应用于深度学习之中。
什么是Sigmoid函数?
Sigmoid函数表达式
Sigmoid函数的图像是什么样的?
Sigmoid函数图像
我们可以看到Sigmoid函数是一个阶跃函数,不管输入什么样的值,输出的值都在0到1之间,在Logsitic回归算法之中,我们取0.5为阈值,大于0.5的为一类,小于0.5的为另一类(即属于某一类的概率大于0.5则归于这一类,小于0.5则归于另一类)。
我们通过Sigmoid函数得到数据类别,通过缩减其与标注结果的差距,来优化回归系数w
的值(实际上是通过优化w
的值来让模型输出与训练样本标注结果相同的概率尽可能大)。这个过程我们靠的是梯度上升算法,该算法与深度学习中使用广泛的梯度下降算法原理相同。
在介绍梯度上升算法之前,我们要先确定我们的目标函数是什么,用什么函数来表示Sigmoid函数输出与标注结果相同的概率,才能去优化它,让它尽可能大。
Logistic回归这部分还有些其他的东西,例如,当处理现实数据的时候,我们往往会遇到数据缺失问题,比如每个样本应该有50个特征,但有些特征的特征值我们是没有的(可能因为机器上的某个传感器损坏),那我们这些数据还能用吗,难道因为缺少几个特征值就丢到整个数据,这是不合理的。我们这里通常的做法有下面几种:
在Logistic回归之中,我们选择用实数0来替换所有缺失值,因为在Logistic回归中,若该特征值为零,则该特征值不会影响到系数w
的迭代优化,如果某样本中的某特征值为0,那么该特征的系数将不做更新。
上面讲的是特征值缺失,如果缺失的不是特征值,而是类别标签,那么我们的简单做法是将该条数据丢弃,因为类别标签与特征值不同,很难采用某个合适的值来替换。
关于Logisitic回归还有一些拓展内容:二元的最大熵模型就是Logistic回归模型,多元的Logistic回归模型就是最大熵模型。另外,在计算概率时,Logistic回归也用到了朴素贝叶斯的假设,用概率图模型的语言来说,Maximum Entropy Model(或者说Logistic Regression)和Naive Bayes形成一个discriminative- generative pair,区别仅仅在于一个是生成模型一个判别模型,其他都一样。
一句话概要,SVM希望通过N-1维的分隔超平面线性分开N维的数据,距离分隔超平面最近的点被叫做支持向量,我们利用SMO(SVM实现方法之一)最大化支持向量到分隔面的距离,这样当新样本点进来时,其被分类正确的概率也就更大。我们计算样本点到分隔超平面的函数间隔,函数间隔为正,分类正确,为负则分类错误。函数间隔的绝对值除以||w||
就是几何间隔,几何间隔始终为正,可以理解为样本点到分隔超平面的几何距离。若数据不是线性可分的,那我们引入核函数的概念,从某个特征空间到另一个特征空间的映射是通过核函数来实现的,我们利用核函数将数据从低维空间映射到高维空间,低维空间的非线性问题在高维空间往往会成为线性问题,再利用N-1维分割超平面对数据分类。
什么叫分隔超平面?如果数据的N维的,分隔超平面就是N-1维的,比如给出的数据点分布在二维平面之中,那分割超平面就是一条直线,如果数据点分布在三维空间之中,那分割超平面就是个平面,更高维同理。
我们的目的是最大化离分隔超平面最近的点(支持向量)与分隔超平面的距离,因为我们的训练数据有限,所以希望能给出足够大的犯错空间,当新样本进来时也能将其正确分类,让我们的分类器足够健壮。
我们上面讲的SVM只能处理线性可分的数据,但实际上生活中存在着大量线性不可分的数据,根据『低维空间的非线性问题在高维空间往往会成为线性问题』,我们利用核函数将低维度下的非线性可分的数据升维成高维度下线性可分的数据,再采用我们之前讲的方法去处理。
接下来我们讲核函数,核函数被用来实现从某个特征空间到另一个特征空间的映射,我们可以把核函数理解成类似于欧氏距离公式一样的距离计算的方法,只要是满足了Mercer条件的函数,都可以作为核函数,又因为SVM中所有的运算都可以写成内积的形式,我们可以直接把内积运算换成核函数,而不必做进一步的简化处理,核函数接受低维空间的输入值,却能算出高维空间的内积值。径向基核函数是SVM中常用的一个核函数,它采用向量作为自变量,能够基于向量距离运算输出一个标量。径向基核函数还有高斯版本,被称为高斯核函数。
对于核函数,这里还需要提一点,其实只处理低维下线性可分问题的SVM也是用了核函数的,只是使用的核函数不具备将低维数据映射到高维的功能,被称为线性核函数(Linear Kernel)。
用SVM同样可以实现我们在讲解kNN算法时所实现的那个手写数字识别,SVM的优势在于,它不用保留所用的训练样本用于计算,而只用保留那几个支持向量就够了,极大地减小了内存的占用,而效果却不差。
此外SVM这里还有很重要的一个点需要提,就是SVM与上一节的Logistic回归的异同点。
首先是第一点,Kernel不是SVM专有的,Kernel Logistic Regression(KLR)也很常见。
从目的和方法的角度讲:SVM只考虑支持向量,也就是和分类最相关的少数点,去训练分类器,然后希望最大化间隔与尽可能的正确分类样本点。而逻辑回归通过非线性映射Sigmoid函数,大大减小了离分类平面较远的点的权重,相对提升了与分类最相关的数据点的权重(Sigmoid函数的取值范围是(0,1),对距离进行了压缩,距离非常大时,它在损失函数中的贡献不会随着距离的增大线性增加),目的也在于尽可能的正确分类样本点。
从使用场景的角度,Andrew NG讲:
从效率与效果的角度讲:
训练数据量不是太大的话,用SVM,SVM得到的结果要优于LR,如果数据量太大,用LR,LR的运行速度会比SVM快得多。
从损失函数的角度来讲(重要):
SVM是用的是Hinge loss function,是需要最大化间隔的,而LR用的是最大似然估计,也就是log-likehood loss function(对数似然损失函数)。
Hinge loss 的标准形式其实就是我们上面提到过的:
最大化支持向量与分隔超平面的距离
那损失函数是什么?损失函数衡量的是模型预测错误的程度,也就代表了模型预测结果与训练样本标注结果的差别,我们希望最小化损失函数的函数值,损失函数的函数值越小,就相当于我们的预测结果与真实结果越相近。通常而言,损失函数由损失项(loss term)和正则项(regularization term)组成。
常见的损失函数有0-1损失函数、绝对值损失函数、平方损失函数(最小二乘法)、hinge loss function(SVM)、log loss function(LR)、指数损失函数(AdaBoost)等,这些损失函数用到了的时候会分别讲。在逻辑回归模型中,我们最大化似然函数和最小化log损失函数实际上是等价的。
对hinge loss,又可以细分出hinge loss(或简称L1 loss)和squared hinge loss(或简称L2 loss),这是因为其正则项的不同,正则项可分为L1正则项和L2正则项,简单来讲,添加正则项的意义在于防止过拟合(训练样本表现极好,而测试样本表现很差)。参数越多,模型越复杂,而越复杂的模型越容易过拟合。
一句话概要,AdaBoost(adaptive boosting)是元算法,通过组合多个弱分类器来构建一个强分类器。我们为训练数据中的每一个样本都赋予其一个权重,这些权重构成了向量D
,一开始,这些权重都初始化成相等值,然后每次添加一个弱分类器对样本进行分类,从第二次分类开始,将上一次分错的样本的权重提高,分对的样本权重降低,持续迭代。此外,对于每个弱分类器而言,每个分类器也有自己的权重,取决于它分类的加权错误率,加权错误率越低,则这个分类器的权重值α越高,最后综合多个弱分类器的分类结果和其对应的权重α得到预测结果,AdaBoost是最好的监督学习分类方法之一。
前面已经介绍了五种不同的分类算法,它们各有优缺点,我们可以将其组合起来,元算法(meta-algorithm)或者叫集成方法(ensemble method)可以集成不同算法,也可以是同一算法在不同设置下的集成,还可以是被数据集不同部分训练过的相同或不同的分类器的集成。
boosting和bagging都是集成学习(ensemble learning)领域的基本算法,boosting和bagging使用的多个分类器的类型是一致的。
bagging也叫自举汇聚法(bootstrap aggregating),比如原数据集中有N个样本,我们每次从原数据集中有放回的抽取,抽取N次,就得到了一个新的有N个样本的数据集,然后我们抽取S个N次,就得到了S个有N个样本的新数据集,然后拿这S个数据集去训练S个分类器,之后应用这S个分类器进行分类,选择分类器投票最多的类别作为最后的分类结果。
boosting与bagging的区别在于:
AdaBoost是boosting方法中最流行的版本。
起始状态,所有样本的权重都是相同的,我们采用第一个弱分类器(我们对弱分类器的要求是只要二分类正确率高于50%就可以了,比瞎猜准一点就可以)对其进行分类,然后计算其分类加权错误率:
之后为第一个弱分类器赋予权重:
分类器权重计算
计算出α之后,要对样本权重D
进行更新,如果该样本被正确分类,那我们降低其权重:
如果该样本被错误分类,那么我们提高其权重:
计算出新的权重之后,AdaBoost又开始进入下一轮迭代,不断重复迭代,直到训练的错误率为零或迭代次数达到用户的设置,当有新样本时,我们将所有分类器的分类结果与权重相乘后全部加和,如果结果大于0则是类别1,小于0则是类别-1(AdaBoost的类别标签为1和-1)。
这里我引用我自己总结的一个思考方法,对于一个机器学习算法:
AdaBoost是这篇文章里面讲的最后一个分类算法,在开始讲监督学习中的回归算法之前,还有一个问题需要讨论,就是非均衡分类问题。在前面的分类算法中,我们都假设所有类别的分类代价是一样的,但实际上并不是这样,就拿朴素贝叶斯算法的垃圾邮件过滤做例子,将垃圾邮件错分为正常邮件和将正常邮件错分为垃圾邮件的代价是不一样的。
还有一个是我们可以在机器学习中引入代价的概念,比如分出真阳和真阴的代价是0,甚至可以是负数,分出假阳和假阴的代价为正数,在实际应用中分错的代价越大,那它对应的正数值也就越大,将代价引入目标函数中一并优化,最后的目标是总代价最小。
另一点是欠抽样和过抽样,如果正例和反例的数量差距过于悬殊,我们倾向于对数量过多的类别进行欠抽样,只取其中一部分;而对数量过少的类别进行过抽样,比如复制样例或加入与样例相似的点。
前面讲的都是监督学习中的分类,训练出可以判断样本类别的模型,而回归的目的是预测数值型的目标值,最直接的办法是依据输入写出一个目标值的计算公式,将自变量代入后就能根据函数得到因变量的预测值。
先讲最简单的回归方法:最小二乘法。
我们被给予二维平面内的一系列点,我们希望画出一条直线,根据直线的方程(回归方程)能够以较小的误差预测点所在的位置。
仍然按照前面提到过的思考方法,最小二乘法模型的优化目标是什么?希望回归方程的预测目标值与真实目标值之差的平方和最小。那最小二乘法的损失函数的是什么?平方损失函数,表达式如下:
最小二乘法平方损失函数
那用什么方法去优化目标函数?我们先将目标函数改为矩阵表示,再对w
求导,令其导数为零,然后解得w
如下:
w的预估最优解
w
上方的小标记表示那是w
的最佳估计值,可能不是真实值。上面的公式中还用到了X
的逆矩阵,所以这个方程只在X
存在逆矩阵的时候适用。计算出w
就得到了回归直线,下图是示例:
最小二乘法回归示例
不过看上图的样本点似乎还有更好的拟合方式。最小二乘法这样纯粹的线性回归往往会出现欠拟合现象,所以我们期望在估计中引入一些偏差,从而降低预测的均方误差。
下面讲的是局部加权线性回归(LWLR),它的思想在于,我们给所有的样本点赋予一定权重,并且认为离待预测点更近的样本点所拥有的权重应该更高。
这样解出回归系数w
的形式如下:
式子中的W
是一个矩阵,为每个数据样本点赋予一定权重。那W
怎么确定?怎样实现离待预测点更近则权重越高呢,这里我们使用核函数,与SVM中的核函数类似,高斯核是比较常用的一种核,对应的权重公式如下:
高斯核权重公式
这样就满足了离待预测样本点越近,权重越高的要求,k
是需要我们设置的参数,它用来调节『权重值在近样本点的集中程度』:
k
越小,权重值就越集中在近的样本点。k
越大,权重分布就越分散。
通过最小二乘法和局部加权线性回归的回归系数w
求解公式可以发现我们都需要求X'X
的逆矩阵,如果训练样本的特征比样本数还多,或者某些列之间存在着线性相关关系,都会导致X
不再是列满秩矩阵,进而导致X'X
的行列式近乎为0,也即X'X
近乎为奇异矩阵、非满秩矩阵、不可逆矩阵,如果对这样的X'X
求逆矩阵,就会找不到最优解或者误差很大。为了解决这样的情况,我们引入几种缩减方法,第一个介绍『岭回归』。
岭回归就是在原来最小二乘法式子求逆之前先加上一个阶数与样本数相同的对角矩阵,也即加上一个正则项,使矩阵为奇异的风险大降低,损失了无偏性,来换取高的数值稳定性。计算公式如下:
岭回归回归系数计算公式
λ
是常数,I
是主对角线元素全为1的单位矩阵。在原有基础上加上正则项后,还可以在样本数过少的时候对系数进行惩罚,限制了所有w
之平方和(系数越大、模型越复杂,越容易过拟合),防止过拟合,提高了泛化能力。为什么说系数越大越容易过拟合,因为系数往往是函数求导后的式子中所包含的,系数越大,则整个函数的导数越大,导数越大,整个模型就越有可能做一些激烈的变化去拟合所有的点,我们控制系数大小,即控制了整个函数导数的大小,使得曲线相对平滑,防止了过拟合,也就有了更高的泛化能力。
所以当λ
比较小时,系数与普通回归一样,而λ
非常大时,所有回归系数缩减为0,我们在中间某处选择一个合适的λ
值,使得预测结果最好。
实际上,岭回归通过增加正则项,就是为最小二乘法增加了这样的约束条件:
除了岭回归,还有一种缩减方法叫做lasso,只不过它的约束条件是这样:
用绝对值取代了平方和,虽然变化非常细微,但计算复杂度却大大增加了,我们要介绍一个更简单的方法,叫做『前向逐步回归』。
前向逐步回归是一种贪心算法,一开始所有的系数的权重都为1,然后每一步都是对某个权重增加或减少一个很小的值。
首先固定其他特征,只看第一个特征,看系数值是增加好还是减小好,处理完成后再处理第二个特征,不断循环往复,处理完全部特征了再从第一个特征重新开始处理,一直到系数都稳定下来。
上一节介绍了多种线性回归算法,但是对于某些复杂的数据集,并不能建立全局的回归方程,所以我们希望结合树的思想,先将数据集进行分类,将数据集切分成很多份易建模回归的数据,然后再用前面的回归方法来求得回归方程。
前面我们讲过ID3决策树算法,在那里我们一次分类就要消耗一个特征,在后面的分类过程中,这个被消耗掉的分类就不再起作用,这样的分类有时候太过迅速,浪费了一些信息,而且ID3决策树也只能处理离散型的数据,如果要处理连续性数据需要先经过一步预处理,但是这种处理会破坏连续性数据原本的内在性质。
为了解决前面提到的问题,我们介绍CART树(分类回归树)构建算法,它利用二元切分法处理连续型变量,即每次把数据切为两份,分别进入左子树和右子树。基于CART可以构建回归树,也可以构建模型树。
回归树概要,加载数据集,随后选定最好的划分特征和划分特征值,将原数据集划分成左子树和右子树,随后不断迭代划分,直到满足停止条件。当回归树构建完成后,我们用每个叶子节点数据的均值来代表这个叶子节点下的所有数据。
构建回归树的过程与ID3算法构建树的过程非常相似,接下来需要确定的是两点,一个是在构建回归树的过程中怎样选定最好的划分特征和划分特征值,第二个是应该用什么作为提前停止条件。
在ID3算法中,我们每次选择让整个数据集香农熵减小最多(信息增益最大)的特征对数据集进行划分,而在回归树算法中因为要处理的是连续性的数值变量,直接采用总方差来度量分类的有效程度,遍历所有特征及其所有可能的取值,每次选择让整个数据集总方差减小最多的特征及划分特征值对数据进行划分。
回归树算法中需要提前设定两个参数以控制算法的停止时机,一个是容许的误差下降值,一个是切分的最少样本数。也就是如果这次最佳划分使总方差的下降值小于预定阈值,或划分后的两个子集存在某个子集大小小于预定阈值,则停止继续划分。
使用CART构建树时还会涉及到树剪枝的问题,一棵树如果节点过多,表示该模型可能对数据进行了过拟合,我们可以通过交叉验证来判断是否发生了过拟合,通过降低决策树复杂度来避免过拟合的过程称为剪枝,提前终止条件实际上就是预剪枝,另一种形式的剪枝需要使用训练集和测试集,称作后剪枝。
如果使用预剪枝,我们需要不断的修改停止条件,而后剪枝则不需要用户指定参数,但相对的,后剪枝不如预剪枝有效。
后剪枝需要在树构建完成后使用测试集,自上而下找到叶节点,然后尝试合并相邻的叶节点,如果合并叶节点后能够降低在测试集上的误差,那我们就合并掉两个叶节点。
接下来要讲的是模型树,模型树与回归树的区别在于,每个叶子节点下不再是常数,而是用线性函数来对数据做拟合,整棵模型树成为了一个分段线性函数。
比如上图这样的数据就相当适合采用模型树来建模,整个数据集会被分为两个叶子节点,每个叶子节点下是一个线性函数。
其划分的基本思想仍然是找让整个数据集总误差最小的划分方式,回归树中的方法不能再用,但是我们在上一节讲过了相当多的线性模型,也讲过了它们对应的计算误差的方式(平方误差),我们只要在每次尝试划分后对每个叶子节点下用线性模型去拟合该节点下的数据,然后分别计算误差值,选取使总误差最小的划分方式即可。
树回归在预测复杂数据集时会比简单的线性模型更有效。
前两部分讲的都是有监督学习,所做的大多是:『对于输入数据X能预测变量Y』,而无监督学习要回答的问题是:『从数据X中能发现什么』。
一句话概要,首先,选择k个初始点作为质心,然后为每个样本点找距其最近的质心,并将其分配给该质心所对应的簇,然后将每个簇的质心更新为该簇所有点的平均值,既然质心位置改变了,那对样本点的划分自然也要随之改变,如此不断迭代,直到对所有样本点的分类都不再改变,也即算法收敛。
既然存在质心的概念,就要使用某种距离度量方式计算,我们当然可以用欧式距离公式,也可以利用余弦距离,根据两者夹角的大小表示距离的大小。
这里我举一个利用K-均值聚类算法进行文本分类的例子,类似于前面的朴素贝叶斯算法,我们为每篇文档建立一个词向量,只不过用的既不是词袋模型也不是词集模型,首先去掉单词表中的所有的停用词,之后每个词的对应位置放置的,是这个词在这篇文档当中的TF-IDF值,若该词在该文档中所占比例越大,则其TF值越大,而若该词在所有文档中的出现比例越高,则其IDF值越小,最后计算其TF*IDF的值(TF-IDF值),作为该词表示所在文档主题的能力。这样我们就得到了每篇文档的词向量,随后走K-均值聚类算法的流程,先给出若干随机向量,对全部文档进行第一次分类,这里的距离度量方式采用的就是余弦距离,通过判断两个向量夹角的余弦值来描述两者间的距离关系,若其夹角为0度,则余弦值为1,若其夹角为180度,则余弦值为-1,认为夹角余弦值越大则两篇文档越相近,越小则两者越无关。
接下来我们要谈一下K-均值聚类算法所存在的问题,首先K值是由用户定义的,很多时候用户并不知道要将K设置成多少,而且又因为其初始质心的设置是依靠随机生成,所以K-均值算法会收敛到局部最小值而不是全局最小值。
我们通过SSE(误差平方和)来度量聚类效果,SSE值越小说明数据点越接近它们对应的质心,我们当然可以通过增加簇的个数来降低SSE,但这违背了我们聚类的目标,我们希望在保持簇数目不变的情况下提高簇的质量。
我们可以采用这样的后处理来提高K-均值聚类算法的聚类质量:首先将SSE值最大的簇拆分成两个簇,具体方法可以是对该簇内的数据运行K-均值聚类算法,同时将K设置为2,而且,为了保证总的簇数不变,我们还要将两个质心合并,我们可以选择合并两个最近的质心,或者合并两个使得SSE增幅最小的质心。
为了克服K-均值聚类算法可能会收敛到局部最小值的问题,有人提出了二分K-均值算法,一句话概要,该算法首先将所有点作为一个簇,然后将该簇一分为二,之后选择其中一个簇继续进行划分,选择哪个簇取决于对其划分是否可以最大程度降低SSE值(是不是与构建树的过程有些相似),上述基于SSE的划分过程不断重复,直到得到用户指定的簇数目为止。
一句话概要,Apriori算法首先根据所给数据构建只有一个元素的项集,然后判断每个项集的支持度,去掉支持度不足的项集,再组合一元素项集构建二元素项集,再去掉支持度不足的项集,如此不断迭代,直到不存在拥有更多元素的频繁项集。之后是发现关联规则,关联规则产生于频繁项集,一个频繁项集可以生成多条可能的关联规则,我们利用分级法,先生成右边只有一个元素的关联规则,然后判断每条规则的可信度,去掉可信度不足的规则,再将可信度足够的规则拆分子集,生成右边有两个元素的关联规则,再去掉可信度不足的规则,如此不断迭代,直到不存在右侧有更多元素的关联规则。
关联分析包括发现频繁项集和关联规则,频繁项集是经常出现在一块的物品的集合,关联规则暗示两种物品之间可能存在很强的关系,而且这种关系是有方向性的,A->B和B->A是两条不同的关联规则。
然后定义支持度与可信度,支持度用来描述频繁项集,可信度用来描述关联规则。一个项集的支持度被定义为数据集中包含该项集的记录所占的比例。如果一共有10条记录,5条记录中出现了A,那A的支持度就是1/2;如果3条记录中同时出现了AB,那AB的支持度就是3/10。可信度是针对由A->B这样的关联规则来定义的,可信度的计算基于支持度,上例中,A->B的可信度就是AB的支持度3/10除以A的支持度1/2,等于3/5;如果要计算B->A的支持度,那除以的就应该是B的支持度。
上面提到,我们只用支持度足够的一元素项集构建二元素项集,这里用到了一个简单的原理,如果这个一元素项集的支持度未达到阈值,那所有包含该元素的多元素项集的支持度也不可能达到阈值,这个很好理解,因为包含该元素的每个多元素项集的出现次数都不可能高于该元素的出现次数。
另外,如果某项集本身不是频繁项集,那由该项集生成出来的关联规则,在计算上确实是有可能有足够可信度的,比如A、B、AB均只出现了一次,那A->B,B->A的可信度都是100%,但我们不选择采信该关联规则,因为数据量太小。
上面还提到,我们只选择拆分可信度足够的关联规则来找更进一步的关联规则,这里同样用到一个原理,如果某条规则不满足最小可信度要求,那该规则的所有子集也不可能满足最小可信度的要求。
举个例子,我们找到一个频繁项集0123,首先它可以生成这样4条关联规则:123->0、023->1、013->2、012->3。如果012->3这条关联规则的可信度不够,则12->03、02->13、01->23这三条关联规则也不可能达到足够的可信度。因为如果012->3这条关联规则的可信度不够,那么表示0123的支持度/012的支持度已经不能满足可信度需求,而01、02、12的支持度必然大于012的支持度,这种条件下,可信度计算公式的分子不变而分母增大,总可信度必然是减小的,所以更不可能高于可信度的最小阈值。既然12->03、02->13、01->23不满足可信度要求,那就更不要说2->013、1->023、0->123了,证明同理。这种根据频繁项集找关联项集的方式也被叫做分级法。
一句话概要,FP指频繁项集(Frequent Pattern),FP-growth专门用来发现频繁项集,速度快于Apriori,只扫描数据集两次,一次构建FP树,一次从FP树中挖掘频繁项集。常被用来做输入联想,比如在百度搜索框里输入『为什么』,就会联想出一些有意思的东西。
FP-growth速度快于Apriori,因为Apriori对于每个潜在的频繁项集都会扫描一遍数据集来判定其支持度是否达到要求。FP-growth只扫描数据集两次,一次构建FP树,一次从FP树中挖掘频繁项集。
那什么是FP树?FP树通过链接来连接相似元素,被连起来的元素项可以看成一个链表,示例如下:
FP树
用于生成FP树的数据
同搜索树不同的是,一个元素项可以在一棵FP树中出现多次。FP树会存储项集的出现频率,而每个项集会以路径的方式存储在树中。存在相似元素的集合会共享树的一部分。只有当集合之间完全不同时,树才会分叉。树节点上给出集合中的单个元素及其所在序列中的出现次数,路径会给出该序列的出现次数。
上面的FP树就是由下面的数据集生成的,一点点来分析,z
一共出现了5次,其中zr
(不包括zxyrt)出现1次,zxyrt
出现1次,zxyst
出现2次,这样加起来,z
出现了4次,看数据,发现z
还单独出现了1次,所以一共5次。r
一共出现了3次,是将3条路径(zr
、zryrt
、xsr
)中的r
出现次数相加。其实我们还可以发现,原数据当中还有一些h
、j
、p
、v
、u
、o
、q
、e
、m
没有在FP树中出现,这里也同样引入了支持度的概念,数据集中出现次数小于3次的字母不被放入树中。
第一次遍历数据集会获得每个元素项的出现频率,接下来过滤掉不满足最小支持度的元素项,之后对数据集中的每条数据按照元素项的绝对出现频率来排序。在构建时,读入每个项集并将其添加到一条已经存在的路径中,如果该路径不存在,则创建一条新路径。除此之外,我们还要建立一个头指针表用来保持对每个满足最小支持度字母的引用。至此,就完成了FP树的构建。
之后要做的是从FP树中挖掘频繁项集,挖掘频繁项集分为三个步骤:从FP树中获取条件模式基、利用条件模式基构建一个条件FP树、迭代直到树包含一个元素项为止。
首先是查找条件模式基,条件模式基是以所查找元素为结尾的路径集合,通俗的来讲也就是前缀路径,一条前缀路径是介于所查找元素与树根节点之间的所有内容。我们可以先通过前面的头指针表找到每个频繁项每个元素项的位置,再向前上溯这棵树直到根节点为止,以此来找到所有的前缀路径,也就是条件模式基。
下面是每个频繁项的条件模式基实例:
大括号里面的,是该条前缀路径上的所有节点,z
前面没有别的节点,所以大括号中为空,大括号后面的数字代表了这条前缀路径的出现次数。
接下来我们要做的是根据条件模式基构建条件FP树,条件FP树的构建与FP树的构建非常相似,区别在于,条件FP树是针对某个频繁项来讲的,我们在上一步中已经找到了每个频繁项的条件模式基,构造该频繁项的条件FP树所使用的数据,就只是该频繁项所对应的条件模式基,也就是说构造初始FP树,我们用的是所有的数据,构建每个频繁项的条件FP树,我们只用这个频繁项的条件模式基。当然,构造条件FP树时,也需要先排序然后去掉不满足最低支持度的项,因为即便某项在全部的数据中是频繁项,但在某频繁项的条件模式基中却不一定是频繁项了。
接下来再对构建的条件FP树去抽取条件模式基,再迭代构建条件FP树,直到条件树中没有元素为止,如此我们就能得到所有的频繁项集。
PCA是主成分分析的简写,实际上就是将N维数据降维到最能代表数据集真实结构的K个正交维度上去(N>K),且这K个维度是重新构造而成的,而不是从原有N维中选取,这K维特征被称为主成分。其价值在于四点:使数据集更容易使用、降低很多算法的计算开销、去除噪声、使结果易懂。
PCA对数据进行降维,我们要把高维度的数据去除噪声,只保留最重要的N个维度,那怎么确定需要保留的维度呢?第一个维度选择的是原始数据中方差最大的方向,通俗的讲,就是给定大量数据点,我们画出一条直线,尽可能的经过这些点,这条直线的方向就是方差最大的方向(下面会给出示例图)。接下来要找第二个维度,对第二个维度有这样的要求,它需要与第一个维度正交,我们要在与第一个坐标轴正交的所有坐标轴里找到方差最大的方向作为第二个坐标轴,第三个坐标轴同理,它需要与前两个坐标轴均正交。
PCA方法降维
原理如上文所讲,那具体如何处理呢?这里会涉及到协方差矩阵的概念,首先,方差和标准差是用来描述一维数据的,而如果我们想要处理多维数据,发现两维数据之间的相关关系,就要用到协方差矩阵,我们依照方差公式类比推得协方差公式。
方差公式
协方差公式
若协方差的结果为正值,则说明两者正相关;若为负值,则说明两者负相关;为零则说明不相关,相互独立。
上面的协方差公式只能处理二维问题,那我们要处理多维之间的相关关系,那自然该想到使用矩阵表示,由协方差组成的协方差矩阵。
三维数据下的协方差矩阵示例
接下来,我们求这个协方差矩阵的特征值,选择保留K个最大的特征值,这K个特征值所对应的特征向量也就给出了K个最重要的真实结构,而且协方差矩阵是对称阵,其特征值对应的特征向量都是相互正交的,满足作为相互独立坐标轴的条件,我们可以通过将原数据乘以这K个特征向量将其转化到新空间。
而且我们其实还发现了一点,PCA方法中特征值最大的那个特征向量的方向(投影到该坐标轴后数据集总方差最大的方向),实际上也就是我们用最小二乘法对数据集进行拟合所得到的线性回归直线的方向,这个是可以证明的,最小二乘法目标函数的优化目标实际上就是找到数据集协方差矩阵(X'X
)的最大特征值,而最大特征值对应的特征向量也就是最小二乘法的回归直线。
PCA将N个特征降维到K个,所以可以用来进行数据压缩,例如100维的向量最后可以用10维来表示,那么压缩率为90%。
SVD是奇异值分解的简称,SVD同样是将高维数据降低到低维,或者理解成在噪声数据中抽取相关特征。
SVD的应用非常广,其中一个就是隐性语义索引,SVD可以抽取文档和词的概念,也就是可以识别拥有同一主题的文章以及同义词。举个例子,如果我们要根据某个关键词找出包含它的文章,如果文档中的该词包含了错别字,或者使用的是该词的同义词,只基于词语存在与否的搜索是无法找到这样的文章的,但是使用SVD就可以做到。
SVD的另一个应用就是推荐系统,简单的推荐系统直接用余弦距离等计算项或者人之间的相似度,更先进的方法则先利用SVD从数据中构建出一个主题空间,然后再在该空间下计算相似度。对于原始数据矩阵进行SVD处理就能将数据压缩到若干概念中去。
接下来先讲SVD的推导过程,再根据原理更深入的讲应用过程,推导过程有些复杂。
在推理SVD之前,先做一步EVD推理,SVD是奇异值分解,EVD是特征值分解,这里我们选择一种特殊的矩阵,也就是对称阵,前面我们也提到过对称阵有种性质,就是它的特征向量相互正交,或者讲可以构成一组正交基。
首先假设我们有一个满秩对称阵A
,它的特征值是λ
,相应的单位特征向量是x
,假设一共有m
个特征值。则根据特征值、特征向量的定义,下式成立:
将上式以矩阵形式表示:
两侧同时右乘U
的逆矩阵得(因为U
为正交阵,其逆矩阵等于其转置):
假设我们现在要将一个新的向量x
转化到A
所在的列空间之中,也即如下式:
由于上文中讲,A
为对称阵,x
为它的单位特征向量(旧x
),所以x
为一套正交基,所以我们就可以把新x
这个向量用旧x
这套正交基表示:
所以得到下式:
紧接着,中间的对角阵与右边的a
(也就是A
的特征向量们)相乘,实际上就是对a
在各个维度上进行拉伸或压缩:
由上图,如果A
不满秩,也就是A
存在为零的特征值,那么中间的对角阵对角线上就存在零元素,这时候就会导致维度退化,映射后的向量会落在m维空间的子空间之中。
最后一个变换就是U
对拉伸或压缩后的向量做变换,由于U
和U'
是互为逆矩阵,所以U
变换是U'
变换的逆变换。
因为U
和U'
里面的是A
的特征向量们,是一组正交基,对其拉伸压缩后,向量之间仍然正交,所以实际上,A
可以起到将一组正交基转化到另一组正交向量的作用。
接下来要分析的是,对于任意一个M*N的矩阵A
,A
矩阵将N维空间中的向量映射到K(K<=M)维空间中(K是矩阵A
的秩),现在的目标是,找到这样一组正交基,经过A
变换后仍然是正交的。假设,已经找到这样一组v
:
经过A
映射后,将其映射为:
如果要使它们两两正交,即:
根据假设,存在:
所以如果我们将v
选择为A'A
的特征向量的话,因为A'A
是对称阵,所以v
之间两两正交,λ
是A'A
的特征值,那么:
所以我们就找到了一组正交基,经过A
变换之后仍然是正交的。
接下来我们将其单位化,因为:
所以:
单位化:
可得:
接下来:
从而:
即得:
SVD分解公式
SVD的核心原理,就是任意一个M*N的矩阵A
,都能被拆分成M*M的正交阵U
、M*N的对角阵Σ
、N*N的正交阵V'
的乘积。V
是A'A
的特征向量矩阵,Σ
是A'A
的奇异值矩阵,至于U
,每个Ui
都是由A*Vi
并单位化(除以对应奇异值)后得出的。
而且如果A
不满秩,那利用矩阵分块乘法就能对式子进行化简,就能找到A
对应的满秩分解,A=XY
,X
是M*K,Y
是K*N,K为A
的秩。
前面讲了原理,下面讲SVD的应用,其实SVD除了基础应用之外还有拓展出来的RSVD与SVD++,这里不讲。
SVD的第一个用途是用来简化数据(或者讲去除噪声),前面说的满秩分解实际上就是将M*N的Σ
对角阵中对角线上的零元素分块出来与U
、V'
K列/行之后的元素相乘使其总结果为零,这样就只剩下了M*K的X
和K*N的Y
。这样既然有些维度可以因为对应奇异值为零被完全去掉而不影响结果,那么我们也可以将一些对应奇异值小的维度去掉,只保留拥有高奇异值的维度,从而减少了大量维度但只损失很少的信息。
SVD的第二个用途是在自然语言处理中,我在《数学之美》这本书上读到。我们用A
矩阵来描述成千上万篇文章和几十上百万个词的关联性,A
里面每一列是一篇文章,每一行代表一个词,对应位置上是这个词的加权词频(比如TF-IDF值),然后我们对A
进行奇异值分解,分成这样:A=XBY
,这里和前面的:A=XY
的关联性在于,两式的X
相同,第二式的Y
等于第一式中的BY
,X
是M*K,B
是K*K,Y
是K*N。
第一个矩阵X
是对词分类的结果,它的每一行表示一个词,每一列表示一个同义词类,对应位置的值表示该词和该同义词类的相关性大小。
第三个矩阵Y
是对文章分类的结果,它的每一列对应一篇文章,每一行表示一个主题,对应位置的值表示该文章和该主题的相关性大小。
第二个矩阵则展示了不同同义词类和不同文章主题的相关性大小。
SVD的第三个用途是用在推荐系统中,同样是用在推荐系统中,我在CSDN博客上看到了与《机器学习实战》里面不一样的用法,《机器学习实战》里面,是根据我前面讲的SVD的第一个用途,对用户评分数据进行简化,然后在简化过的数据上运行相似度算法,所谓相似度算法也就是计算欧氏距离、余弦距离或者皮尔逊相关系数等。而我在博客中看到的用法如下:
前面我们证明了任意一个矩阵A
都能被我们满秩分解,那么现在我们有个评分矩阵R
:
我们将其分解:
上图中的U表示用户数,I表示商品数。然后就是利用R中的已知评分训练P
和Q
使得P
和Q
相乘的结果最好地拟合已知的评分,那么未知的评分也就可以用P
的某一行乘上Q
的某一列得到了:
我们还是采用之前的方法,先列损失函数(目标函数)再优化,这里采用平方误差函数:
优化这个的方法用梯度下降就可以了,前面详细讲过。这个式子在梯度下降的时候,很容易让人产生一个疑惑,x
在哪?自变量在哪?好像只有w
没有x
,的确,普通的式子中,都是将w
与x
进行某种计算得到估计值,进而得到每个样本的估计误差值,但是在这个式子中,x
实际上是一种对w
的选取逻辑,也就是行号和列号,根据x
选择相应w
进行计算,得到估计值,计算误差,梯度下降优化w
,提高拟合效果。这是这个目标函数与其他使用梯度下降方法进行优化的目标函数不同的地方。