几年前我写过一个Service Ticket自动归类程序。根据现成的指导写一个程序容易,而搞明白其背后的算法原理,用了好久。算法
不过想明白以后发现,不只对这一个模型,并且对于Machine Learning的通常方法的理解,都有了提高。数据库
在工做中学习Machine Learning,这种问题->模型->算法->数学原理(公式)的认知过程至关高效。微信
需求
当时的任务很简单:把内容相近的Service Ticket放到一块儿(造成一个“簇”),每簇中的元素数量最好不要超过某个预约义的阈值。
ide
没有事先定义“簇”的类型,可见这是一个典型的聚类的问题。函数
说到聚类,最多见的模型固然是KMeans。学习
不过若是使用KMeans的话,须要指定K的值,也就是要在训练前指定最后的结果被分为几“簇”。而同时KMeans的结果并不能保证每簇中的个体数量低于某个量值。spa
所以,KMeans并不符合这个任务的要求。.net
那应该用什么模型呢?通过一通Google,以及请教公司内部的数据科学家,肯定了使用:基于图切割的谱聚类(Spectral Clustering)。3d
算法实现
肯定了模型就好办,根据《A Tutorial on Spectral Clustering》和专家意见,按照如下步骤实现了这个程序:orm
【步骤1】 将每一个Service Ticket转化为一个词袋,并通过normalization和去停用词操做。
【步骤2】生成一张图G = <V,E>,每一个词袋是其中一个顶点(vertex),每两个顶点之间的边则是这两个词袋之间的Jaccard距离:
Jaccard_Distance = 1 – (|A ∩ B|/ |A U B|)
这样一张图用矩阵 C = (cij) 存储; 其中:
cij =Jaccard_Distance(wordbag_i, wordbag_j)
【步骤3】肯定距离阈值threshold_C, 将全部cij > threshold_C的两个顶点 i 和 j 视为断开。据此将完整的G分割为若干连通图{G1, G2, … , Gn}。
计算每个子图的radius (最远边缘节点到中心节点的距离) 和size(包含顶点数)。
若是(cluster_radius<= threshold_radius) && (cluster_size <= threshold_size), 则该连通图自己就是一个独立的簇,不然,对该簇进行下一个步骤。
【步骤4】图切割:
4.1 将待切割图G切割为2个子图Gs1 和Gs2, 达到Gs1和Gs2之间距离尽可能大而两个子图内部个节点间距离尽可能小的目的。具体切割过程以下:
4.1.1 构造一个和C同等大小的矩阵W = (wij)
wij = exp(-||xi - xj||2/σ2) ; 这里用到了高斯类似度函数(Gaussian similarity function),其中σ 是一个用来控制变换速度的参数。
具体到本例子, ||xi-xj||就用wordbag_i和wordbag_j的Jaccard_distance来计算便可。也就是说||xi-xj|| = cij。
4.1.2 构造一个对角矩阵D:
对角项 di = Σj wij
4.1.3 令 L = D - W,构造等式:
Lv = (D-W)v = λv,其中λ为常数,v为向量。
4.1.4 计算上述等式的倒数第二小的特征值所对应特征向量f。
设被分割图 G一共包含n个顶点,则其由一个nxn矩阵表达,所以得出的特征向量f也是n维向量。f中的每一维表明一个顶点(即一个service ticket)。
f = (f1, f2, …, fn);
IF fi >= 0 THEN vertex_i 属于 Gs1
IF fi < 0 THEN vetex_i 属于 Gs2
这样就把G分红了两部分:Gs1和Gs2。
4.2 计算Gs1和Gs2的大小和半径,而后
IF ((cluster_radius > threshold_radius) && (cluster_size > threshold_size))
THEN
重复 4.1,直到全部被分割的结果知足上述条件为止。
【步骤5】将【步骤4】运用到全部【步骤3】中全部连通图{G1, G2, … , Gn}上。
运行结果
当时这个程序是用内嵌R的PostgreSQL编写的,由于全部Training Data都存储在数据库里,因此要用一种可以方便操做数据库的语言。
并且总共只有40多万条(平均每条不超过1K),用SQL+R也并非很慢。
R的矩阵运算功能使得整个程序编写至关容易,将threshold_size设为2000,threshold_radius设为50以后,总体运行结果还不错。最后获得了17个簇,人工看结果也比较reasonable。
被质疑的算法
不过在团队内部分享算法实现的时候,有同事说:这不就是算词频嘛。态度颇为不屑。
当时的感受是有些无言以对。
词袋模型(用词袋来表示Service Ticket)自己确实是没有考虑单词出现顺序对文档含义的影响,并且采用Jaccard Distance计算的是两个词袋之间单词交集和并集的比例,也确实和词语出现的次数相关。
可是若是说谱聚类就是算词频,则相差太远了。
但是具体差在哪里呢?好像又有点说不清楚。只是朦胧的以为,若是不是采用了类似度矩阵,若是不是进行了矩阵运算,则根本得不出“簇”的结果——
要算单个文档(service ticket)的词频或者整体词频都很容易。可是若是不是矩阵运算,又怎么可能把这些文档归为若干簇,使得每个簇内文档相互之间的距离尽可能小,而簇之间的距离尽可能大呢?
模模糊糊有如上这样的想法。可是,其实本身并不明白,即便采用了谱聚类,又是怎么能作到不一样的簇高内聚低耦合的。
还有,为何要作那么一大堆奇怪的矩阵变换?为何要把一个好好的类似度矩阵扭曲成很奇怪的样子?这样作究竟是为何呢?
算法原理
回头从理论层面看谱聚类的数学原理,才对上述的疑问有了一点点感悟。
【基本原理】
谱聚类的目的就是要找到一种合理的分割,使得分割后造成若干子图,链接不一样的子图的边的权重尽量低,即“截”最小,同一子图内的边的权重尽量高。
【构造矩阵】
步骤 4.1.1 中根据对称阵C构造的矩阵W,也是一个对称阵。它描述了G中各节点间的类似度。
NOTE 1: 在步骤 2中构造的矩阵 C = (cij) 中,cij表示点 i 到点 j 的距离,cij值越大说明距离越远。可是到了矩阵W中的节点:wij = exp(-(cij)2/σ2)。cij 越大,则wij越小。也就是说W中的节点wij 的数值越小,它所表示的对应的两个点之间的距离也就越大。
步骤 4.1.2 则是构造了W的对角矩阵D。
步骤 4.1.3 中,由类似度矩阵W和其对角矩阵D,咱们构造了一个新的矩阵:
L= D-W
L是一个拉普拉斯(Laplacian)矩阵,称做非规范化的拉普拉斯矩阵(Unnormalized Laplacian Matrix)。
【拉普拉斯矩阵性质】
因拉普拉斯矩阵性质得知:
(i) L是对称半正定矩阵;
(ii) Laplacian矩阵L的最小特征值是0,相应的特征向量是I;
(iii) Laplacian矩阵L有n个非负实特征值:0 = λ1 <= λ2 <= … <= λn
又由于L = D - W,对于任一实向量f,均可以作以下计算:
所以,对于任一实向量f都有下面的式子成立:
【图分割和矩阵运算的关系】
如今咱们回过头来,看图切割这件事情。
假设咱们把L所对应的原图进行图切割,成两个新的图:A和。
也就是说,以前n x n矩阵L所对应的n个顶点被分为了两部分,一部分属于A,另外一部分属于它的补。
到底哪些点被分给了A,哪些店被分给了它的补呢?咱们能够用一个向量来表示。
假设存在一个向量f = (f1, f2, ..., fn)', 其中不一样维度的值能够指示该维度对应的顶点属于新分出来的哪一个子图。具体以下:
将f带入到上面(iii)中的公式:,又由于当i,j同属于A或者
时,fi – fj 为0。
所以,f'Lf 就能够被转化为以下形式:
<式子1>
取出上面<式子1>中的后一部分:
其中:k表示不一样类别的个数,这里k=2。表示子图A和
之间连通边的权重。
这里的定义的Cut函数,又能够被称为“截函数”。
当一个图被划分红为两个子图时,“截”即指子图间的链接密度。即被切割后的子图之间,本来是连通状态(但在切割时被截断)的边的值加权和。
咱们要找到一种分割,使得分割后,链接被分割出来的两个子图的边的权重尽量低,即“截”最小。
所以,Cut函数就是咱们求取图切割方法的目标函数。
由于在这个例子里面,Cut函数中的值是就是wij (顶点i 位于A, 顶点 j 位于)。根据前面的NOTE 1可知wij 越小,则对应的两点间的距离越大。
咱们既然要让切割出来的结果是两个子图之间的加权距离尽可能大,那么天然,咱们就要让的值尽可能小。
由此可知,咱们要作的就是最小化Cut函数。
咱们再将Cut函数带回到<式子1>中,获得结果以下:
其中|V|表示的是顶点的数目,对于肯定的图来讲是个常数。
由上述的推导可知,由f’Lf推导出了RatioCut函数。到此,咱们得出了:
由于Cut函数和RatioCut函数相差的是一个常数,所以求Cut的最小值就是求RatioCut的最小值。
又由于|V|是常数,所以咱们求RatioCut函数的最小值就是求f’Lf的最小值。
到此时,图切割问题,就变成了求f’Lf的最小值的问题。
【经过求f’Lf的最小值来切割图】
假设λ是Laplacian矩阵L的特征值,f是特征值λ对应的特征向量,则有:Lf = λf
在上式的两端同时左乘f’,获得:
f’Lf = λf’f
已知 ||f|| = n1/2 则 f’f = n,上式能够转化为:f’Lf = λn
既然咱们的目标是求 ,那么咱们只需求得最小特征值λ。
由Laplacian矩阵的性质可知,Laplacian矩阵的最小特征值为0,相应的特征向量是I。
向量I中全部维度 都为1,没法将对应顶点分为两份。所以咱们用L第二小的特征值(也就是最小的非零特征值)来近似取RatioCut的最小值。(本天然段描述纯为笔者的理解,此处背后实际的理论依据是Rayleigh-Ritz理论。)
咱们先求出L第二小的特征矩阵f,再经过以下变换,将f转化为一个离散的指示向量:
对于求解出来的特征向量f = (f1,f2,…, fn)’ 中的每个份量fi,根据每一个份量的值来判断对应的点所属的类别:
这也就是步骤4.1.4中描述的内容。
【从切割成2份到切割成k份的推演】
若是不是要一次将图切成2份,而是要切成k份,那么就要先求L的前k小个特征向量。
若前k个特征向量为,这样便由特征向量构成以下的特征向量矩阵:
将特征向量矩阵中的每一行做为一个样本,利用K-Means聚类方法对其进行聚类。
即对n个k维向量进行聚类,将其聚为k个簇。聚类完成以后,若是特征矩阵中的第i个k维向量被汇集到了第j个簇中,则本来图中的第i个点就被汇集到了第j个簇中。
以上,就是根据非规范化拉普拉矩阵进行基于图切割的谱聚类的算法原理。
【规范化拉普拉斯矩阵】
L 也能够被规范化,D-1/2L D-1/2 就是L的规范化形式。
L' = D-1/2L D-1/2 又称为规范化的拉普拉斯矩阵(Normalized Laplacian Matrix)。
对于规范化的拉普拉斯矩阵,不能直接求其特征值和特征向量来作图切割。不过大致过程和思路与非规范化拉普拉斯矩阵一致,在此不赘述。
本文分享自微信公众号 - 悦思悦读(yuesiyuedu)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。