主题模型
传统判断两个文档相似性的方法是通过查看两个文档共同出现的单词的多少,如TF-IDF等,这种方法没有考虑到文字背后的语义关联,可能在两个文档共同出现的单词很少甚至没有,但两个文档是相似的。
主题模型(Topic Model)是用来在一系列文档中发现抽象主题的一种统计模型。直观来讲,如果一篇文章有一个中心思想,那么一定存在一些特定词语会出现的比较频繁。比方说,如果现在一篇文章是在讲苹果公司的,那么“乔布斯”和“IPhone”等词语出现的频率会更高一些;如果现在一篇文章是在描述微软公司的,那么“Windows”和“Microsoft”等词语出现的频率会更高一些;但真实情况下,一篇文章中通常包含多种主题,而且每个主题所占的比例各不相同,比如一篇文章中10%和苹果公司有关,90%和微软公司有关,那么和微软有关的关键字出现的次数应该是苹果关键字出现次数的9倍。
主题模型就是一种自动分析每个文档,统计文档内词语,根据统计的信息判断当前文档 包含哪些主题以及各个主题所占比例各为多少。
主题模型是对文本中隐含主题的一种建模方法,每个主题其实是词表上单词的概率分布;
主题模型是一种生成模型,一篇文章中每个词都是通过“以一定概率选择某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到的;
主题模型克服了传统信息检索中文档相似度计算方法的缺点,并且能够在海量的 数据中找出文字间的语义主题。主题模型在自然语言和给予文本的搜索上起到了重要的作用。
SVD的特性
对于奇异值,它跟我们特征分解中的特征值类似,在奇异值矩阵中也是按照从大到小排列,而且奇异值的减少特别的快,在很多情况下,前10%甚至1%的奇异值的和就占了全部的奇异值之和的99%以上的比例。也就是说,我们也可以用最大的k个的奇异值和对应的左右奇异向量来近似描述矩阵。
由于可以使用小矩阵来近似的描述样本信息的这个重要特性,SVD可以常用于PCA降维、推荐系统以及主题模型等场景中。
LSA
潜在语义分析(Latent Semantic Analysis, LSA),也叫做Latent Semantic Indexing, LSI.是一种常用的简单的主题模型。LSA是基于奇异值分解(SVD)的方 法得到文本主题的一种方式。
总结:我们输入的有m个文本,每个文本有n个词。而Aij则对应第i个文本的第j个词的特征值。k是我们假设的主题数,一般要比文本数少。SVD分解后,Uil对应第i个文本和第l个主题的相关度。Vjm对应第j个词和第m个词义的相关度。Σlm 对应第l个主题和第m个词义的相关度。
余弦相似度
通过SVD矩阵分解我们可以得到文本、词与主题、语义之间的相关性,但是这个时候计算出来的内容存在负数,我们比较难解释,所以我们可以对LSI得到文本主题矩阵使用余弦相似度计算文本的相似度的计算。最终我们得到第一个和第三个文档比较相似,和第二个文档不太相似。(备注:这个时候直接在文本主题矩阵的基础上直接应用聚类算法即可)
余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫”余弦相似性”。
上图两个向量a,b的夹角很小可以说a向量和b向量有很高的的相似性,极端情况下,a和b向量完全重合。如下图:
如上图可以认为a和b向量是相等的,也即a,b向量代表的文本是完全相似的,或者说是相等的。如果a和b向量夹角较大,或者反方向,可以说a向量和b向量有很低的的相似性,或者说a和b向量代表的文本基本不相似。
向量a和向量b的夹角 的余弦计算如下:
扩展,如果向量a和b不是二维而是n维,上述余弦的计算法仍然正确。假定a和b是两个n维向量,a是 ,b是 ,则a与b的夹角 的余弦等于:
如下举例说明利用余弦计算句子相似度
句子A:这只皮靴号码大了。那只号码合适
句子B:这只皮靴号码不小,那只更合适
怎样计算上面两句话的相似程度?
基本思路是:如果这两句话的用词越相似,它们的内容就应该越相似。因此,可以从词频入手,计算它们的相似程度。
第一步,分词。
句子A:这只/皮靴/号码/大了。那只/号码/合适。
句子B:这只/皮靴/号码/不/小,那只/更/合适。
第二步,列出所有的词。
这只,皮靴,号码,大了。那只,合适,不,小,更
第三步,计算词频。(下面程序用的jieba分词工具所以结果不一样但不影响计算)
句子A:这只1,皮靴1,号码2,大了1。那只1,合适1,不0,小0,更0
句子B:这只1,皮靴1,号码1,大了0。那只1,合适1,不1,小1,更1
第四步,写出词频向量。
句子A:(1,1,2,1,1,1,0,0,0)
句子B:(1,1,1,0,1,1,1,1,1)
第五步,利用上述公式计算
python代码实现
# -*- coding: utf-8 -*- """ Created on Mon Jul 30 09:35:54 2018 @author: Administrator """ import jieba import numpy as np def get_word_vector(): """ w = np.ones((3,4)) q = np.ones((3,4")) print(w) print(np.sum(w * q)) """ s1 = input("句子1:") s2 = input("句子2:") cut1 = jieba.cut(s1) cut2 = jieba.cut(s2) list_word1 = (','.join(cut1)).split(',') list_word2 = (','.join(cut2)).split(',') print(list_word1) print(list_word2) key_word = list(set(list_word1 + list_word2))#取并集 print(key_word) word_vector1 = np.zeros(len(key_word))#给定形状和类型的用0填充的矩阵存储向量 word_vector2 = np.zeros(len(key_word)) for i in range(len(key_word)):#依次确定向量的每个位置的值 for j in range(len(list_word1)):#遍历key_word中每个词在句子中的出现次数 if key_word[i] == list_word1[j]: word_vector1[i] += 1 for k in range(len(list_word2)): if key_word[i] == list_word2[k]: word_vector2[i] += 1 print(word_vector1)#输出向量 print(word_vector2) return word_vector1, word_vector2 def cosine(): v1, v2 = get_word_vector() return float(np.sum(v1 * v2))/(np.linalg.norm(v1) * np.linalg.norm(v2)) print(cosine())
View Code
import numpy as np A = np.array([[1,1,1],[0,1,1],[1,0,0],[0,1,0],[1,0,0],[1,0,1],[1,1,1],[1,1,1],[1,0,1],[0,2,0],[0,1,1]]) U,gamma,V_T = np.linalg.svd(A) # print(np.round(np.dot(np.dot(U,np.vstack((np.diag(gamma),np.zeros((8,3))))),V_T))) # print(A) def sim(a,b): return np.sum(a*b)/(np.sqrt(np.sum(np.square(a)))*np.sqrt(np.sum(np.square(b)))) U_k = U[:,:2] gamma_k = np.diag(gamma[:2]) V_k = V_T[:2].T d1 = V_k[0] d2 = V_k[1] d3 = V_k[2] print('d1和d2的相似度:{}'.format(sim(d1,d2))) print('d1和d3的相似度:{}'.format(sim(d1,d3))) print('d2和d3的相似度:{}'.format(sim(d2,d3)))
LSA主题模型总结
除非数据规模比较小,而且希望快速的粗粒度的找出一些主题分布关系,否则我 们一般不会使用LSA主题模型。
优点: 原理简单,一次SVD分解即可得到主题模型,可以同时解决词义的问题。
缺点:
- SVD分解的计算非常耗时,对于高维度矩阵做SVD分解非常困难; 主题模型数量的选取对于结果的影响非常大,很难选择合适的k值;
- LSA模型不是概率模型,缺乏统计基础,结果难以直观的解释。
https://scikit-learn.org/0.19/modules/generated/sklearn.decomposition.TruncatedSVD.html
from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import TruncatedSVD # 加载数据 with open('./1.txt', 'r', encoding='utf-8') as f1: res1 = f1.read() with open('./2.txt', 'r', encoding='utf-8') as f2: res2 = f2.read() with open('./3.txt', 'r', encoding='utf-8') as f3: res3 = f3.read() contents = [res1, res2, res3] print(contents) # 将文本数据转换为向量的形式(词袋法) 要求给定的数据中单词是以空格隔开的 cntVector = CountVectorizer() cnt = cntVector.fit_transform(contents) print(cnt.shape) print(cnt.toarray()) # LSA模型(即SVD) svd = TruncatedSVD(n_components=2) docs = svd.fit_transform(cnt) # 打印文档和主题之间的相关性 print(docs) # 打印主题和词之间的相关性 print(svd.components_)
View Code
NMF
非负矩阵分解(Non-negative Matrix Factorization, NMF)是一种常用的矩阵分解方式,常用于矩阵分解、降维、主题模型等应用场景。
NMF虽然和SVD一样都是矩阵分解,但是NMF不同的是:它的目标希望是将矩阵分解成为两个子矩阵,两个子矩阵中所有的值均大于等于0。
参考:https://www.csie.ntu.edu.tw/~cjlin/papers/pgradnmf.pdf
在NMF中求解出来的W和H,分别体现的是文本和主题的概率相关度,以及词和主题的概率相关度;
NMF的期望是找到两个W、H矩阵,使得WH的矩阵乘积结果和对应的原矩阵V对应位置的值相比误差尽可能的小。
为了防止过拟合,也可以在NMF的目标函数的基础上添加一个正则化项。
但是当加入L1正则项后,由于没法求解出正常的导函数出来(导函数不是连续的),也就没法使用梯度下降法和拟牛顿法求解参数,此时一般采用坐标轴下降法来进行参数的求解。
https://scikit-learn.org/0.19/modules/generated/sklearn.decomposition.NMF.html
from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import NMF # 加载数据 with open('./1.txt', 'r', encoding='utf-8') as f1: res1 = f1.read() with open('./2.txt', 'r', encoding='utf-8') as f2: res2 = f2.read() with open('./3.txt', 'r', encoding='utf-8') as f3: res3 = f3.read() contents = [res1, res2, res3] print(contents) # 将文本数据转换为向量的形式(词袋法) 要求给定的数据中单词是以空格隔开的 cntVector = CountVectorizer() cnt = cntVector.fit_transform(contents) print(cnt.shape) print(cnt.toarray()) # NMF主题模型构建 nmf = NMF(n_components=2, solver='cd') docs = nmf.fit_transform(cnt) # 打印文档和主题之间的相关性 print(docs) # 打印主题和词之间的相关性 print(nmf.components_)
View Code
坐标轴下降法
坐标轴下降法(Coordinate Descent, CD)是一种迭代法,通过启发式的方法一步步的迭代求解函数的最小值,和梯度下降法(GD)不同的时候,坐标轴下降法是沿着坐标轴的方向去下降,而不是采用梯度的负方向下降。
坐标轴下降法利用EM算法的思想,在参数更新过程中,每次均先固定m-1个参数值,求解剩下的一个参数的局部最优解;然后进行迭代式的更新操作。
坐标轴下降法的核心思想是多变量函数F(X)可以通过每次沿着一个方向优化来获取最小值;
其数学依据是:对于一个可微凸函数f(θ),其中θ为n*1的向量,如果对于一个解θ=(θ1 ,θ2 ,…,θn ),使得f(θ)在每一个坐标轴θi(i=1,2,..,n)上都能达到最小值,则θ=(θ1 ,θ2 ,…,θn )就是的f(θ)全局的最小值点。
坐标轴下降法算法过程
给θ向量随机选取一个初值,记做θ0; 2. 对于第k轮的迭代,从θ1k开始计算,θnk到为止,计算公式如下:
检查θk和θk-1向量在各个维度上的变化情况,如果所有维度的变化情况都比较小的话,那么认为结束迭代,否则继续k+1轮的迭代。或者以函数J的变化值作为收敛条件。
备注:在求解每个参数局部最优解的时候可以求导的方式来求解。
坐标轴下降法和梯度下降法的区别
坐标轴下降法在每次迭代中,计算当前点处沿一个坐标方向进行一维搜索 ,固定其它维度的坐标方向,找到一个函数的局部极小值。而梯度下降总是沿着梯度的负方向求函数的局部最小值;
坐标轴下降优化方法是一种非梯度优化算法。在整个过程中依次循环使用不同的坐标方向进行迭代,一个周期的一维搜索迭代过程相当于一个梯度下降的迭代;
梯度下降是利用目标函数的导数来确定搜索方向的,该梯度方向可能不与任何坐标轴平行。而坐标轴下降法法是利用当前坐标方向进行搜索,不需要求目标函数的导数,只按照某一坐标方向进行搜索最小值;
两者都是迭代算法,且每一轮迭代都需要O(mn)的计算量(m为样本数,n为维度数)
概率知识回顾
先验概率:在事情尚未发生前,对该事件发生概率的估计。利用过去历史资料计算出来得到的先验概率叫做客观先验概率;凭主观经验来判断而得到的先验概率叫做主观先验概率。
后验概率:通过调查或其它方式获取新的附加信息,利用贝叶斯公式对先验概率进行修正后,而得到的概率。
似然函数:给定模型参数θ的条件下,样本数据服从这一概率模型的相似程度。
先验分布:反映在进行统计试验之前根据其他有关参数知识得到的分布;也就是说在观测获取样本之前,人们对θ已经有一些知识,此时这个θ的分布函数为H(θ),θ的密度函数为h(θ),分别称为先验分布函数和先验密度函数,统称先验分布。
后验分布:根据样本X的分布以及θ的先验分布π(θ),使用概率论中求解条件概率的方式可以计算出来已知X的条件下,θ的条件分布π(θ|x)。因为该分布是在获取样本x之后计算出来的,所以称为后验分布。
共轭分布:如果先验分布和后验分布具有相同的形式,那么先验分布和似然函数被称为共轭分布。
二项分布
多项分布
Beta分布
Beta分布和二项分布
Dirichlet分布
LDA
隐含狄利克雷分布(Latent Dirichlet Allocation, LDA)是一种基于贝叶斯算法模型,利用先验分布对数据进行似然估计并最终得到后验分布的一种方式。LDA是一种比较常用的主题模型。
LDA假设文档主题是多项分布,多项分布的参数(先验分布)是服从Dirichlet分布, 其实LDA是一种三层的贝叶斯模型。
共有M篇文档,每个文档有Nm个单词,一共涉及到K个主题;
每篇文档都有各自的主题,主题分布是多项式分布,该多项式分布的参数服从Dirichlet分布,该Dirichlet分布的参数为α;
每个主题都有各自的词分布,词分布为为多项式分布,该多项式分布的参数服从Dirichlet分布,该Dirichlet分布的参数为η;
对于某篇文档d中的第n个词,首先从该文档的主题分布中采用一个主题,然后再这个主题对应的词分布中采用一个词,不断重复该操作,直到m篇文档全部完成上述过程。
LDA详细解释
词汇表中共有V个term(不可重复);
语料库中共有m篇文档d1 ,d2 ,..,dm;对于文档di,是由Ni个word组成的(word可重复);语料库共有K个主题T1 ,T2 ,…,Tk ;
α和η是先验分布(Dirichlet分布)的参数;
θ是每篇文档的主题分布,是一个K维的向量;
对于第i篇文档di,在主题分布θi下,可以确定一个具体的主题zij=k;
β是每个主题的词分布,是一个V维的向量;
由zij选择βzij(单词概率),表示由词分布βzij确定term,即可得到最终的观测值wij。
LDA在进行文本的主题模型构建的时候,对于D个文档,K个主题的模型构建流程如下所示:
- 对于每一个Topick,计算出β的值:
- 对于每一个Documentd,计算出θ的值:
- 对于Documentd中的wordi:
- 计算所属的topicz值;
- 计算出观测到的单词w;
对于θ、β、z的参数估计,基于贝叶斯算法可以得到如下公式:
https://scikit-learn.org/0.19/modules/generated/sklearn.decomposition.LatentDirichletAllocation.html
from sklearn.feature_extraction.text import CountVectorizer # 词袋法 from sklearn.decomposition import LatentDirichletAllocation # 加载数据 with open('./1.txt', 'r', encoding='utf-8') as f1: res1 = f1.read() with open('./2.txt', 'r', encoding='utf-8') as f2: res2 = f2.read() with open('./3.txt', 'r', encoding='utf-8') as f3: res3 = f3.read() contents = [res1, res2, res3] print(contents) # 将文本数据转换为向量的形式(词袋法) 要求给定的数据中单词是以空格隔开的 cntVector = CountVectorizer() cnt = cntVector.fit_transform(contents) print(cnt.shape) print(cnt.toarray()) # LDA主题模型构建 # learning_method:指定一部分一部分的文档进行模型的学习 lda = LatentDirichletAllocation(n_topics=2, learning_method='batch', random_state=28) docs = lda.fit_transform(cnt) # 打印文档和主题之间的相关性 print(docs) # 打印主题和词之间的相关性 print(lda.components_)
View Code
今天的文章主题模型_LDA主题分析用什么软件分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/48892.html