实战_用TF/IDF算法对比相似度

原理

TF/IDF方法于1983年题出,它先计算每个单词出现的频率,然后适当归一化。利用TF-IDF方法将任意长度的文档缩减为固定长度的数字列表,然后对比文本相似度,gensim工具包提供该方法。

简单复习一下具体算法:

词频TF
t f i , j = n i , j ∑ k n k , j tf_{i,j}=\frac{n_{i,j}}{\sum_kn_{k,j}} tfi,j=knk,jni,j
其中n是句中词,i是词的索引号,j是文章索引号,k是文章中所有词,上式计算的是词i在本篇出现的比率。请注意:在短文本的情况下,绝大多数词只出现一次,tf就只和文章长短有关了。

逆向文档频率IDF
i d f i = l o g ∣ D ∣ ∣ j : t i ∈ d j ∣ idf_{i}=log \frac{|D|}{|j:t_i\in d_j|} idfi=logj:tidjD
其中分母是文章总数,分子是包含词i的文章数。

TF/IDF
t f i d f i , j = t f i , j × i d f i tfidf_{i,j}=tf_{i,j} \times idf_{i} tfidfi,j=tfi,j×idfi
tfidf值反映的是每个词在文档中的重要程度。请注意:这是一种基于计数的方法,不直接使用词义。

该算法的优点在于算法简单,计算量小;而缺点在于无法处理对同一概念的不同描述,另外,它是词袋类模型,不考虑词的先后顺序和关系。

详见TF-IDF逆文本频率指数

流程

计算文本相似度,指的是从多个文档中找到与句子相似度最高的文档,常用于实现搜索,匹配,文本标准化等功能。具体流程如下:

  • 用待搜语料训练TFIDF
  • 将待搜语料转成包含的关键字及关键字对应评分 M
  • 将搜索文本转换成关键字和评分 K
  • 逐条计算M中内容与K的相似度评分
  • 选最相近的前N条

代码分析

from jieba import lcut
from gensim.similarities import SparseMatrixSimilarity
from gensim.corpora import Dictionary
from gensim.models import TfidfModel

data = ['古典生物型霍乱',
 '霍乱,由于O1群霍乱弧菌,埃尔托生物型所致',
 '埃尔托生物型霍乱',
 '霍乱暴发型',
 '伤寒']

texts = [lcut(s) for s in data]
'''
此时 texts中每个元素是一个句子,句子又由词组成
[['古典', '生物', '型', '霍乱'],
 ['霍乱', ',', '由于', 'O1', '群', '霍乱弧菌', ',', '埃尔托', '生物', '型', '所致'],
 ['埃尔托', '生物', '型', '霍乱'],
 ['霍乱', '暴发型'],
 ['伤寒']]
'''

dictionary = Dictionary(texts)
'''
dictionary 结构类似字典,包含索引号和词的关系
{0: '古典', 1: '型', 2: '生物', 3: '霍乱', 4: 'O1', 5: '埃尔托', 6: '所致',
 7: '由于', 8: '群', 9: '霍乱弧菌', 10: ',', 11: '暴发型', 12: '伤寒'}
'''

corpus = [dictionary.doc2bow(text) for text in texts]
'''
corpus 语料库,结构同texts,但每个子元素不是字,而是id及其在本句中出现的次数
[[(0, 1), (1, 1), (2, 1), (3, 1)],
 [(1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 2)],
 [(1, 1), (2, 1), (3, 1), (5, 1)],
 [(3, 1), (11, 1)],
 [(12, 1)]]
'''

tfidf = TfidfModel(corpus) # 用语料库训练模型
tf_texts = tfidf[corpus] # 将语料库作为被搜索数据
sparse_matrix = SparseMatrixSimilarity(tf_texts, len(dictionary)) # 构建工具类的实例
'''
sparse_matrix.index内容如下:
  (0, 0)	0.9050976
  (0, 1)	0.28727236
  (0, 2)	0.28727236
  (0, 3)	0.12548897
  (1, 1)	0.10273404
  (1, 2)	0.10273404
  (1, 3)	0.044877227
  ...
此时sparse_matrix中存储的是各句中包含的关键字及其tfidf值
'''

keyword = '埃尔托生物霍乱'
kw_vector = dictionary.doc2bow(lcut(keyword))
'''
转换待搜索字符串,返回包含的关键字id及其出现次数
kw_vector: [(2, 1), (3, 1), (5, 1)]
'''
tf_kw = tfidf[kw_vector]
'''
获取关键词对应的的tfidf值
tf_kw: [(2, 0.476), (3, 0.208), (5, 0.854)]
'''

similarities = sparse_matrix.get_similarities(tf_kw)
for e, s in enumerate(similarities):
    print('与 %d 相似度为:%.2f' % (e, s))
'''
计算搜索串与被搜索数据中每一项的相似度
与 0 相似度为:0.16
与 1 相似度为:0.22
与 2 相似度为:0.90
与 3 相似度为:0.03
与 4 相似度为:0.00
'''

完整代码

封装一下,以便拿来就用

from jieba import lcut
from gensim.similarities import SparseMatrixSimilarity
from gensim.corpora import Dictionary
from gensim.models import TfidfModel
import numpy as np

class TFIDFSimilarity:
    def __init__(self):
        pass

    def train(self, data):
        '''
        训练模型,需转入待匹配列表
        '''
        texts = [lcut(s) for s in data]
        self.dictionary = Dictionary(texts)
        corpus = [self.dictionary.doc2bow(text) for text in texts]
        self.tfidf = TfidfModel(corpus)
        tf_texts = self.tfidf[corpus]
        num_features = len(self.dictionary.token2id)
        self.sparse_matrix = SparseMatrixSimilarity(tf_texts, num_features)

    def get_similarities(self, string, topN = 3):
        '''
        从模型中找最相近的 topN 个匹配项,返回其索引号和近似度
        '''
        text = lcut(string)
        kw_vector = self.dictionary.doc2bow(text)
        tf_kw = self.tfidf[kw_vector]
        similarities = self.sparse_matrix.get_similarities(tf_kw)
        index = np.argsort(similarities)[:-topN-1:-1]
        return [(i,s) for i,s in zip(index,similarities[index])]

data = ['霍乱,由于O1群霍乱弧菌,霍乱生物型所致', 
        '古典生物型霍乱', 
        '霍乱,由于O1群霍乱弧菌,埃尔托生物型所致']

s_tools = TFIDFSimilarity()
s_tools.train(data)
s_tools.get_similarities('埃尔托生物霍乱',3)

技巧

  • 生成词典可以选择以词为单位,以字为单位,或拆分成所有可能的词…
  • 可去掉停用词和与主题无关的词
  • 可加入其它的语料训练TFIDF,以学习词的重要性(不加入候选集即可)
  • 如果搜索句子中的词未出现在字典中,将自动忽略该词
  • 如包含英文,请注意大小写
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值