这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记
14. 推荐系统技术之文本相似性计算(一、二、三)
14.1 引子
假如我们有以下6个文档
- 用Golang写一个搜索引擎
- 搜索引擎的实现
- 推荐系统的技术要点
- 常用的推荐算法总结
- 广告系统是一个搜索引擎和推荐引擎的组合
- 计算广告中都有哪些数学原理
有个一个小朋友,他叫小明,但是他还在上学前班,你让他来说这些文章中哪几篇比较相似,他现在字都认不全,更别说理解这些文章中的概念了,如果他特别聪明,那么他很可能说1和5比较相似,因为都有个长得一样的东西一个搜索引擎。
又过了一些年,小明已经读初中了,你再让他来看哪几篇比较相似,他可能会告诉你1和2比较相似,然后和5也比较相似,因为他现在已经学会了主谓宾定状补的语法,知道第一条的主要表述的是搜索引擎,第二篇主要表述的也是搜索引擎,第五篇虽然主要不是说的搜索引擎,但宾语的定语也是搜索引擎,也是相关的。所以会给出1和2相似,5和他们也比较相似。
再过一些年,小明已经大学毕业了,学的就是计算机专业,这时候你再来看,他会给出6个都比较相似,因为他已经知道了搜索,推荐,广告三个领域的基础技术都差不多,如果对一个感兴趣,那么对另外的主题也会比较感兴趣,只不过相似性有高有低而已。
上面的三个阶段,实际上也是文本相似性计算发展的三个阶段,从最开始的字面的匹配相似,到第二阶段的词汇的匹配相似,再到第三阶段的语义的相似, 我们一个一个来说说每个阶段使用的数学方法和原理,每个阶段都会有数学原理,但我们对数学公式不做深入讨论,感兴趣的可以自己查阅具体的数学原理。
名词解释:BOW词袋模型:
通俗的说就是把一个文档进行分词,给每个词都分配一个唯一termId,得到的一堆termId放到一个袋子里,用这个袋子来表示这个文档,这是一种简化的文本描述方法。这种表现方式不考虑文法以及词的顺序
14.2 第一阶段:字面匹配相似
我们其实不关心这篇文章到底讲什么,用计算机的理解就是,分词完成以后,我们找到一种方法,来计算各个词袋之间的相似性就行了。
14.2.1 JaccardSimilarity方法
S和T两个词袋的相似度=S和T的交集/S和T的并集
14.2 第二阶段:词汇匹配相似
14.2.1 数学化
14.2.2 向量化
14.3 第三阶段:语义相似
首先前两阶段不能解决的问题是因为我们只是机械的计算了词的向量,并没有任何上下文的关系,所以思想还停留在机器层面,还没有到更高的层次上来,正因为这样才有了自然语言处理这门课程了。
14.3.1 主题模型
LDA主题模型
*P(W(词)|D(文章))=P(W(词)|T(主题))P(T(主题)|D(文章))
P(W(词)|D(文章))我们可以轻易统计
P(W(词)|T(主题)是模型的一部分
我们要求的是P(T(主题)|D(文章),最终求得这篇文章是属于哪个主题的概率
有新来的文章我们要对这篇文章进行分类的话,先统计出P(W(词)|D(文章)),然后用P(W(词)|D(文章))去除以P(W(词)|T(主题)) ,就得到了这篇文章所属的每个主题的概率了。
我们先定义下一个场景,有3篇文档,每个文档有2个词,设定有2个主题,这三篇文档和词分别是:
1 :你好 世界
2 :你好 中国
3 :搜索 你好
那么词就是:你好,世界,中国,搜索 四个
主题定义为:T1,T2
我们先看看机器怎么来求出这个P(W(词)|T(主题))吧
- 首先随机指定每个词属于某个主题,那么假设设定完了以后P(W|T)的矩阵就是
| 主题 | 你好 | 世界 | 中国 | 搜索 |
|---|---|---|---|---|
| T1 | 0.0 | 1.0 | 0.0 | 0.0 |
| T2 | 0.33 | 0.0 | 0.33 | 0.33 |
- 然后随机的指定每个主题对应的文档概率,P(T|D)的矩阵就是
| 文档 | 主题1概率 | 主题2概率 |
|---|---|---|
| 文档1 | 0.5 | 0.5 |
| 文档2 | 0.5 | 0.5 |
| 文档3 | 0.5 | 0.5 |
- 然后拿第一篇文章的第一个词出来,统计出来他在这篇文章出现的概率,也就是0.5,再给他随机拍一个主题,比如T1
- 用上述的计算出来的话
0.0*0.5=0.0,而我们统计出来是0.5啊,这不对,我们再试试别的主题,比如T2,这么算出来0.33*0.5=0.165,也不对啊,但比T1好像要靠谱一点,那我们按照这个调整一下上面两个表格的数字吧,比如把那个0.0改成0.2之类的(具体怎么调?呵呵呵,靠说人话我说不出来了,看后面的链接吧)。 - 这么一个一个词下来,上面两个表格就在不断更新,然后我们一遍一遍的循环迭代,直到上面两个表格能满足所有文档所有词要求了就结束了。放心,不会死循环的。
这么一轮下来,就得到了两个表格了。这两个表格就是我们的LDA模型了。
- 新来的文章我们要对这篇文章进行分类的话,先统计出P(W(词)|D(文章)),然后用P(W(词)|D(文章))去除以P(W(词)|T(主题)) ,就得到了这篇文章所属的每个主题的概率了。
- 然后我们还可以把新文章也放进模型中继续训练,然后又得到一个更新了的表格,这样不断有文章进来,表格就不断变化了。
主题模型除了LDA还有很多其他的,比如LSI,虽然最后结果也比较靠谱,但是他的可解释性就不强了,我也没法用说人话的方式描述出来了。
主题模型这种东西是基于大规模的语料的情况下才有效果,而且主题的设定个数也是个经验值,据传说300个主题是个比较合适的值,但是具体合适不合适需要根据你自己的情况是测试,然后找到一个你认为合适的主题数。
14.3.2 词向量
word2vector,本公众号没提到如何实现它
可用于发现词与词之间的关系
词向量也就是用一个向量来表示一个词,比如一个词北京,还有三个维度分别是大学,北方,首都,我们把北京用向量表示成[0,9,0.5,1],那么这个词有3个维度,这三个维度的意义是什么呢?可以解释成北京这个词啊是大学的概率是0.6,他在北方的概率是0.5,他是首都的概率是1
14.4 工程实践
14.4.1 工具准备
python的 gensim 工具包,jieba分词,NumPy 1.3,SciPy 0.7。后两个是python的科学计算的包
14.4.2 数据准备
py爬虫
14.4.3 数据清洗
可用py的bs4包,将网页响应的html数据转化为我们想要的数据,结构如下
ID(实际上是url) TITLE(标题) CONTENT(文章详情)
14.4.4 训练数据,创建模型
①使用jieba分词对数据分词
②对分词后的数据建立词典(一个词对应一个id)
③生成数字语料
使用二维数组,每一行表示一个文档的每个词的编号和词频,每一行像这样
[(1,2),(2,4),(5,2)....] 表示编号为1的词出现了2次,编号为2的词出现了4次....
④创建TF-IDF模型
使用py的gensim包,将数字语料转化为TF-IDF模型,每一行格式如下
[(1,0.98),(2,0.23),(5,0.56)....] (词id, TF-IDF值)
⑤创建LDA主题模型
使用py的gensim包,使用TF-IDF向量生成LDA模型,每一行的P(W词|T主题)格式如下
#38 (0.020): 0.003新奇 + 0.003骏 + 0.002途安 + 0.002配备 + 0.002都市 + 0.001除 + 0.001*昂科威
14.4.5 各个文件
user_dic.txt,自定义的分词表
./data/all.txt,存放所有原始文档,一行代表一个文档
all.dic,词典,即一个词对应一个id
all.cps,数字语料,格式是:每一行表示一个文档的每个词的id和词频
all.info,存放所有原始文档,一行代表一个文档,每行的格式为 ID(实际上是url) TITLE(标题) CONTENT(文章详情)
allTFIDF.mdl,TF-IDF模型,每一行代表一个文档,每一行格式如下 [(1,0.98),(2,0.23),(5,0.56)....] (词id, TF-IDF值)
allTFIDF.idx,基于TF-IDF向量的文档相似度索引,每一行代表一个文档,每一行含其他文档与当前文档的相似度
allLDA50Topic.mdl,LDA模型,每一行代表一个主题,每一行表示P(W词|T主题),格式如下,#38 (0.020): 0.003新奇 + 0.003骏 + 0.002途安 + 0.002配备 + 0.002都市 + 0.001除 + 0.001*昂科威
allLDA50Topic.idx,基于LDA向量的文档相似度索引,每一行代表一个文档,每一行含其他文档与当前文档的相似度
14.4.6 验证两个模型的效果
①对于TF-IDF模型
对于TFIDF模型,在现有数据集(12000篇文章)的情况下,推荐结果强相关,让人觉得推荐结果很靠谱,这也是TFIDF这种算法简单有效的地方,他把文章中的关键词很好的提取出来了,所以推荐的结果让人觉得强相关,但是他也有自己的问题。
- 对于比较短的文章(比如微博这类的),由于文本太短了,TFIDF比较难提取出重要的关键词或者提取得不对,导致推荐结果不靠谱。
- 单纯以词频来说明这个词的重要性感觉不全面,比如这篇文章,人类来看的话应该是
文本相似性最重要,但有可能按TFIDF算出来是模型这个词最重要。
对于纯文本的推荐系统来说,这种文本相关性的推荐可能比较适合垂直类的网站,比如像SegmentFault这种,看某篇文章的人很可能希望看到类似的文章,更深入的了解这个领域,这种算法比较靠谱,不过据我观察,SegmentFault是使用的标签推荐,这种推荐效果更好,但人为因素更多点,要是写文章的时候随便打标签就比较麻烦了。
②对于LDA主题模型
LDA主要用在文本聚类上,而且他的基础是主题,如果把他作为推荐系统的算法来使用,要看具体场景,他的推荐结果在数据样本不太够的情况下,可能看上去不太靠谱(即便样本大可能也看上去不太好),显得粒度很粗,但正因为很粗,所以比较适合做内容发现,比如我对数码新闻感兴趣,这种感兴趣不仅仅是只对iphone感兴趣,只要是数码这个主题的我都感兴趣,所以用LDA可以很好的给我推荐数码这个主题下的东西,这比正在看iphone的文章,下面全是iphone的文章要靠谱多了。