在文本处理中,比如商品评论挖掘,有时需要了解每个评论分别和商品的描述之间的相似度,以此衡量评论的客观性。
文本相似度计算的需求始于搜索引擎,搜索引擎需要计算“用户查询”和爬下来的众多“网页”之间的相似度,从而把最相似的排在最前,返回给用户。
一、基本概念
TF-IDF
- TF:term frequency,词频
$$ 词频(TF) = 某个词在文章中的出现次数 $$
$$ 词频(TF) = \frac{某个词在文章中的出现次数}{文章的总次数} $$
$$ 词频(TF) = \frac{某个词在文章中的出现次数}{该文出现次数最多的词的出现次数} $$
- IDF:inverse document frequency,逆文档频率
$$ IDF = log(\frac{语料库的文档总数}{包含该词的文档数+1}) $$
- TF-IDF
$$ TF-IDF = 词频(TF) \times逆文档频率(IDF) $$
主要思想是:如果某个词或短语在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF计算步骤
第一步:把每个网页文本分词,称为词包(bag of words)
第二步:统计网页(文档)总数M
第三步:统计第一个网页次数N,计算第一个网页第一个词在该网页中出现的次数n,再找出该词在所有文档中出现的次数m。
则该词的tf-idf为:
$$ \frac{\frac{n}{N}}{\frac{m}{M}} $$
第四步:重复第三步,计算出一个网页所有词的tf-idf值。
第五步:重复第四步,计算出所有网页每个词的tf-idf值。
SVD,奇异值分解(Singular value decomposition)
奇异值分解是一个有着明显的物理意义的一种方法,它可以将一个比较复杂的矩阵用更小更简单的几个子矩阵的相乘来表示,这些小矩阵描述的是矩阵的重要的特性。就像是描述一个人一样,给别人描述说这个人长得浓眉大眼,方脸,络腮胡,而且带个黑框的眼镜,这样寥寥的几个特征,就让别人脑海里面就有一个较为清楚的认识,实际上,人脸上的特征是有着无数种的,之所以能这么描述,是因为人天生就有着非常好的抽取重要特征的能力,让机器学会抽取重要的特征,SVD是一个重要的方法。
LSI,浅层语义索引(Latent Semantic Indexing)
潜在语义索引,指的是通过海量文献找出词汇之间的关系。当两个词或一组词大量出现在一个文档中时,这些词就可以被认为是语义相关的。
潜在语义索引是一种用SVD(Singular Value Decomposition)奇异值分解方法获得在文本中术语和概念之间关系的索引和获取方法。该方法的主要依据是在相同文章中的词语一般有类似的含义。该方法可以从一篇文章中提取术语关系,从而建立起主要概念内容。
余弦相似度 (cosine similiarity)
$$ cos\theta=\frac{a^2+b^2-c^2}{2ab} $$
二、相似度计算步骤
1,处理用户查询
第一步:对用户查询进行分词
第二步: 根据网页库(文档)的数据, 计算用户查询中每个词的tf-idf值。
2,相似度的计算
使用余弦相似度来计算用户查询和每个网页之间的夹角。夹角越小,越相似。
三、gensim介绍
Gensim是一个相当专业的主题模型Python工具包。是一个用于主题建模、文档索引以及使用大规模语料数据的相似性检索。相比RAM,它能处理更多的输入数据。作者称它是“根据纯文本进行非监督性建模最健壮、最有效的、最让人放心的软件。”
gensim安装: pip install gensim
四、实现步骤
1,中文分词
以数据库中关于美联储的新闻6000条,为例。
首先对标题和内容进行分词。
标题分词的结果如下:
Python代码
1 | self.df 为pandas 的DataFrame结构 |
2,去掉频率为1的词
1 | def remove_low_freq_word(self, texts, times=1): |
3,建立LSI模型
通过上一步的texts抽取一个“词袋(bag of words),将文档的token映射为id。
1 | dictionary = corpora.Dictionary(texts) |
接下来用字符串表示的文档转换为用id表示的文档向量.
1 | corpus = [dictionary.doc2bow(text) for text in texts] |
例如,最后一列的(123,1)表示第二篇文档中id为123的单词出现了1次。
接下来基于这个“训练文集”计算TF-IDF模型:
1 | tfidf = models.TfidfModel(corpus) |
有了tf-idf值的文档向量,接下来开始训练LSI模型:
1 | lsi = models.LsiModel(corpus_tfidf, id2word=self.dictionary, num_topics=10) |
lsi最核心的意义是将训练文档向量组成的矩阵SVD分解,并做了一个秩为2的近似SVD分解。
有了LSI模型,建立索引:
1 | index = similarities.MatrixSimilarity(lsi[corpus]) |
4,计算相似度
1 | # 计算某一篇文档的相似度 |
第10篇的为它自己,相似度为1,完全相似;与第12篇的相似度为0.74等等。
五、进阶
计算出文章的相似度,就可以对相似度设定一个阈值,高于阈值的文章算是重复文章。这样就引出了另外一个用途,文章去重!
本文的应用背景是将多个资讯平台的文章汇总,很有可能出现不同的平台报道同样的内容,这是大概率事件,所以,为了保证内容的唯一性,需要对汇总的文章去重处理。
Python实现代码
1 | #coding:utf-8 |
参考