文本相似度计算方案
- TF-IDF
- 基本概念
TF-IDF是Term Frequency-Inberse Document Frequency的缩写,即‘词频-逆序文本频率’。它由两部分组成,TF和IDF
TF:词频,文本中各个词的出现频率,并作为文本特征
IDF:IDF反映了一个词再所有文本中出现的频率,如果一个词在很多文本中出现过,那么它的IDF值应该很低。而反过来如果一个词在比较少的文本中出现,那么它的IDF值比较高。一个极端的情况就是,如果一个词在所有文本中都出现,那么他的IDF值应该是0.
其中count(w)为关键词w出现的次数,为文档中所有词的数量
- 相似度
求TF-IDF向量的余玄相似度,值越大越相似
- 实例:
from gensim import corpora, models, similarities
raw_documents = [
'0无偿居间介绍买卖毒品的行为应如何定性',
'1吸毒男动态持有大量毒品的行为该如何认定',
'2如何区分是非法种植毒品原植物罪还是非法制造毒品罪',
'3为毒贩贩卖毒品提供帮助构成贩卖毒品罪',
'4将自己吸食的毒品原价转让给朋友吸食的行为该如何认定',
'5为获报酬帮人购买毒品的行为该如何认定',
'6毒贩出狱后再次够买毒品途中被抓的行为认定',
'7虚夸毒品功效劝人吸食毒品的行为该如何认定',
'8妻子下落不明丈夫又与他人登记结婚是否为无效婚姻',
'9一方未签字办理的结婚登记是否有效',
'10夫妻双方1990年按农村习俗举办婚礼没有结婚证 一方可否起诉离婚',
'11结婚前对方父母出资购买的住房写我们二人的名字有效吗',
'12身份证被别人冒用无法登记结婚怎么办?',
'13同居后又与他人登记结婚是否构成重婚罪',
'14未办登记只举办结婚仪式可起诉离婚吗',
'15同居多年未办理结婚登记,是否可以向法院起诉要求离婚'
]
import jieba
texts = [[word for word in jieba.cut(document, cut_all=True)] for document in raw_documents]
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(line) for line in texts] ## 用于统计词频
num_features = max(dictionary.token2id.values()) ## 将每一句话转化为[(单词,词频),(单词,词频)...]
tfidf = models.TfidfModel(corpus)##构建模型
idx = similarities.SparseMatrixSimilarity(tfidf[corpus],num_features=num_features)##初始化相似度查询接口
##测试
sentense = jieba.lcut('9一方未签字办理的结婚登记是否有效')
vec = dictionary.doc2bow(sentense)
sim=idx[tfidf[vec]]
使用sklearn自带的tf-idf模型
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
raw_documents = [
'0无偿居间介绍买卖毒品的行为应如何定性',
'1吸毒男动态持有大量毒品的行为该如何认定',
'2如何区分是非法种植毒品原植物罪还是非法制造毒品罪',
'3为毒贩贩卖毒品提供帮助构成贩卖毒品罪',
'4将自己吸食的毒品原价转让给朋友吸食的行为该如何认定',
'5为获报酬帮人购买毒品的行为该如何认定',
'6毒贩出狱后再次够买毒品途中被抓的行为认定',
'7虚夸毒品功效劝人吸食毒品的行为该如何认定',
'8妻子下落不明丈夫又与他人登记结婚是否为无效婚姻',
'9一方未签字办理的结婚登记是否有效',
'10夫妻双方1990年按农村习俗举办婚礼没有结婚证 一方可否起诉离婚',
'11结婚前对方父母出资购买的住房写我们二人的名字有效吗',
'12身份证被别人冒用无法登记结婚怎么办?',
'13同居后又与他人登记结婚是否构成重婚罪',
'14未办登记只举办结婚仪式可起诉离婚吗',
'15同居多年未办理结婚登记,是否可以向法院起诉要求离婚'
]
texts = [ ' '.join(jieba.cut(document, cut_all=True)) for document in raw_documents]
cv = CountVectorizer()
cv_fit=cv.fit_transform(texts)
'''
结果展示:
(0, 50) 1##第一列表示文档序号,第二列表示token在字典中的序号,第三列表示在本sentences中的词频数
(0, 45) 1
(0, 89) 1
(0, 73) 1
(0, 14) 1
(0, 16) 1
(0, 53) 1
(0, 62) 1
'''
tfidf_transformer = TfidfTransformer()
tfif_matrix = tfidf_transformer.fit_transform(cv_fit)
tfif_matrix[0].todense()
或者直接使用
from sklearn.feature_extraction.text import TfidfVectorizer
tfidfVecorizer = TfidfVectorizer()#可自己设置解析方法
tfidf_matrix = tfidfVecorizer.fit_transform(texts)
tfidf_matrix[1].todense()
- word2vec
- 将原始的训练语料转换成一个sentence的迭代器
- 训练word2vec模型,生成word2vec向量,可以指定模型训练的参数,例如采用的模型(skip-gram或使cbow);负例采样的个数;embedding向量的维数等
- 其有两种方案:
a. 把目标句子的各个词的向量进行相加取平均,然后进行相似度比较
b. 使用WMD模型(词移距离模型)对模型向量化后的句子进行以下操作:
其中代表欧式距离
- 实例
from gensim.test.utils import common_texts,get_tmpfile
from gensim.models import Word2Vec
model = Word2Vec(size=20,window=5,min_count=1,iter=2)
model.build_vocab(common_texts)
train = model.train(common_texts,total_examples=58,epochs=2)
model.wv.vectors##获取隐层向量
model.most_similar('computer',topn=2)##获取最相似的两个词
model.similarity('computer','tree')##计算两个次的相似度
- doc2vec
import gensim
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = []
for k,v in enumerate(common_texts):
document = TaggedDocument(words = v,tags = [k])
documents.append(document)
model = Doc2Vec(size=300,min_count =1,iter=10)
model.build_vocab(documents)
model.train(documents=documents,total_examples=model.corpus_count,epochs=model.epochs)
## 推测文本向量
model.random.seed(0
infer_vector = model.infer_vector(['hello','i','am','wang'],steps=6)
model.docvecs.most_similar([infert],topn=2)## 获取最相近的句子