向量化短文本及相似度的计算


两篇中文文本,如何计算相似度?相似度是数学上的概念,自然语言肯定无法完成,所有要把文本转化为向量。转化为向量之后便可以使用欧式距离、余弦距离等计算相似度,或者通过Softmax网络(或基于Hierarchical Softmax的模型或基于Negative Sampling的模型)计算属类概率。

【转】 python文本相似度计算

步骤

  1. 分词、去停用词
  2. 词袋模型向量化文本
  3. TF-IDF模型向量化文本
  4. LSI模型向量化文本
  5. 计算相似度

理论

如何向量化:

词袋模型

最简单的表示方法是词袋模型。把一篇文本想象成一个个词构成的,所有词放入一个袋子里,没有先后顺序、没有语义。
例如:
John likes to watch movies. Mary likes too.
John also likes to watch football games.
这两个句子,可以构建出一个词典,key为上文出现过的词,value为这个词的索引序号
{“John”: 1, “likes”: 2,”to”: 3, “watch”: 4, “movies”: 5,”also”: 6, “football”: 7, “games”: 8,”Mary”: 9, “too”: 10}
那么,上面两个句子用词袋模型表示成向量就是:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
[1, 1,1, 1, 0, 1, 1, 1, 0, 0]
相对于英文,中文更复杂一些,涉及到分词。准确地分词是所有中文文本分析的基础,本文使用结巴分词,完全开源而且分词准确率相对有保障。

TF-IDF模型

词袋模型简单易懂,但是存在问题。中文文本里最常见的词是“的”、“是”、“有”这样的没有实际含义的词。一篇关于足球的中文文本,“的”出现的数量肯定多于“足球”。所以,要对文本中出现的词赋予权重。
一个词的权重由TF * IDF 表示,其中TF表示词频,即一个词在这篇文本中出现的频率;IDF表示逆文档频率,即一个词在所有文本中出现的频率倒数。因此,一个词在某文本中出现的越多,在其他文本中出现的越少,则这个词能很好地反映这篇文本的内容,权重就越大。
回过头看词袋模型,只考虑了文本的词频,而TF-IDF模型则包含了词的权重,更加准确。文本向量与词袋模型中的维数相同,只是每个词的对应分量值换成了该词的TF-IDF值。

LSI模型

TF-IDF模型足够胜任普通的文本分析任务,用TF-IDF模型计算文本相似度已经比较靠谱了,但是细究的话还存在不足之处。实际的中文文本,用TF-IDF表示的向量维数可能是几百、几千,不易分析计算。此外,一些文本的主题或者说中心思想,并不能很好地通过文本中的词来表示,能真正概括这篇文本内容的词可能没有直接出现在文本中。
因此,这里引入了Latent Semantic Indexing(LSI)从文本潜在的主题来进行分析。LSI是概率主题模型的一种,另一种常见的是LDA,核心思想是:每篇文本中有多个概率分布不同的主题;每个主题中都包含所有已知词,但是这些词在不同主题中的概率分布不同。LSI通过奇异值分解的方法计算出文本中各个主题的概率分布,严格的数学证明需要看相关论文。假设有5个主题,那么通过LSI模型,文本向量就可以降到5维,每个分量表示对应主题的权重。

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import warnings
warnings.filterwarnings(action='ignore',category=UserWarning,module='gensim')
import jieba.posseg as pseg
import codecs
from gensim import corpora, models, similarities
from gensim.models import word2vec

import os

# 遍历获取所有样本
path = r'resource\sougou_data_all'
filenames = []
for dirpath, dirnames, filenames in os.walk(path):

for file in filenames:
fullpath = os.path.join(dirpath,file)
filenames.append(fullpath)
# print(fullpath)

# 构建停用词表
stop_words = "resource/stop_words.txt"
stopwords = codecs.open(stop_words,'r',encoding='utf8').readlines()
stopwords = [ w.strip() for w in stopwords ]

# 结巴分词后的停用词性 [标点符号、连词、助词、副词、介词、时语素、‘的’、数词、方位词、代词]
stop_flag = ['x', 'c', 'u','d', 'p', 't', 'uj', 'm', 'f', 'r']

# 对一篇文章分词、去停用词
def tokenization(filename):
result = []
with open(filename, 'r') as f:
text = f.read()
words = pseg.cut(text)
for word, flag in words:
if flag not in stop_flag and word not in stopwords:
result.append(word)
return result


# 建立词袋模型-begin
corpus = []
for each in filenames:
# print(tokenization(each))
corpus.append(tokenization(each))
# print (corpus[0])
dictionary = corpora.Dictionary(corpus)
# print(dictionary)

doc_vectors = [dictionary.doc2bow(text) for text in corpus]
# print (len(doc_vectors))
# print (doc_vectors)

# 建立词袋模型-end

# 建立TF-IDF模型-begin
tfidf = models.TfidfModel(doc_vectors)
tfidf_vectors = tfidf[doc_vectors]

# print (len(tfidf_vectors))
# print (len(tfidf_vectors[0]))

# 建立TF-IDF模型-end

# 测试
testfile = 'resource/sougou_data_all/财经/999.txt'

query = tokenization(testfile)

query_bow = dictionary.doc2bow(query)

# 输出测试样本与训练样本的相似度
index = similarities.MatrixSimilarity(tfidf_vectors)
sims = index[query_bow]
print (list(enumerate(sims)))

# 构建LSI模型,设置主题数为9
lsi = models.LsiModel(tfidf_vectors, id2word=dictionary, num_topics=9)
lsi_vector = lsi[tfidf_vectors]

for vec in lsi_vector:
print(vec)# 维度相等


# 输出测试样本与训练样本的相似度
query_lsi = lsi[query_bow]
index = similarities.MatrixSimilarity(lsi_vector)
sims = index[query_lsi]
print (list(enumerate(sims)))
-------------本文结束感谢您的阅读-------------

本文标题:向量化短文本及相似度的计算

文章作者:ChengXiao

发布时间:2018年04月21日 - 21:04

最后更新:2018年04月23日 - 10:04

原始链接:http://chengxiao19961022.github.io/2018/04/21/向量化短文本及相似度的计算/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

你的鼓励是我前进的动力~