Text2Vec:简单的文本向量化工具
代码在 https://github.com/crownpku/text2vec
文本向量化,顾名思义就是将一段文字(一篇文章,一个段落或者是一个句子)变成一个向量。在尽可能不丢失原始文本信息的情况下,将文本变成可以计算的向量,可以帮助后续的文本聚类、分类、相似度匹配等等的诸多任务。
手头的一个小项目要对英文短文本进行20个标签左右的分类。标注数据量只有几千条,尝试了几种深度学习方法结果都很一般,最后发现简单用TF-IDF做特征和Linear SVM做分类器就给出了最好的结果。
对于这种标注数据量比较少的短文本分类任务,用词向量做输入接BiLSTM之类的深度学习模型就有点大炮打蚊子的感觉了。更好的Baseline方法可能是将这些短文本向量化,然后用一个简单的如Linear SVM的分类器来做分类。对于这种将批量短文本向量化的需求,我在网上找了一圈,有很多博客、Stackoverflow的讲解和介绍,却没有一个简单称手的文本向量化的工具。于是我基于spacy和gensim写了一个文本向量化的小工具,包装起来供自己的短文本分类项目直接调用使用。
这个项目的名字叫做text2vec,其中包含了一系列文本集向量化的方法,以及几种计算向量相似度和距离的方法。
安装
将项目clone下来,核心文件是text2vec.py。
git clone https://github.com/crownpku/text2vec
项目需要安装spacy和gensim这两个包,其中spacy要安装最新的2.0版本,并下载对应的英文语言模型:
python -m spacy download en
文本向量化
短文本向量化的方式,有在gensim的文档中提到的几个:
-
Term Frequency x Inverse Document Frequency, Tf-Idf
-
Latent Semantic Indexing, LSI (or sometimes LSA)
-
Random Projections, RP
-
Latent Dirichlet Allocation, LDA
-
Hierarchical Dirichlet Process, HDP
这5个都是比较传统的向量化方式,这里就不再展开了。有兴趣的读者可以去自行阅读gensim的文档或寻找相关资料研究。
除去这5个之外,我们也不能缺了用word embedding词向量来做文本向量化的方法。最简单又据称效果很好的方法,是直接把文本中出现的所有的词对应的词向量叠加做平均,作为表示该文本的向量。 利用spacy自带的glove embedding,这个任务在代码中很容易实现:
nlp = spacy.load('en')
def _document_vector(self, doc, docs_dict, nlp):
doc_vector = [nlp(word).vector for word in doc if word in docs_dict.token2id]
return np.mean(doc_vector, axis=0)
而另一个方式,是利用TF-IDF作为词的权重,对文本中的词向量进行加权平均的方式来计算文本向量。这种方式会使代表每个文本特性的词汇占据更大权重,从而让加权平均的文本向量更好地代表该文本本身。
def tfidf_weighted_wv(self):
#tf-idf
docs_vecs = self._get_tfidf(self.docs, self.docs_dict)
#Load glove embedding vector for each TF-IDF term
tfidf_emb_vecs = np.vstack([self.nlp(self.docs_dict[i]).vector for i in range(len(self.docs_dict))])
#To get a TF-IDF weighted Glove vector summary of each document,
#we just need to matrix multiply docs_vecs with tfidf_emb_vecs
docs_emb = np.dot(docs_vecs, tfidf_emb_vecs)
return docs_emb
于是我们可以很方便使用text2vec.text2vec
来计算一个代表文本集的文本列表doc_list
对应的向量集。
import text2vec
t2v = text2vec.text2vec(doc_list)
# Use TFIDF
docs_tfidf = t2v.get_tfidf()
# Use Latent Semantic Indexing(LSI)
docs_lsi = t2v.get_lsi()
# Use Random Projections(RP)
docs_rp = t2v.get_rp()
# Use Latent Dirichlet Allocation(LDA)
docs_lda = t2v.get_lda()
# Use Hierarchical Dirichlet Process(HDP)
docs_hdp = t2v.get_hdp()
# Use Average of Word Embeddings
docs_avgw2v = t2v.avg_wv()
# Use Weighted Word Embeddings wrt. TFIDF
docs_emb = t2v.tfidf_weighted_wv()
得到的矩阵的每一行即是对应原先文本集中一个文本的向量。由此我们就可以用向量化的文本来做文本聚类、文本分类以及文本相似度的计算了。
文本相似度/距离
这里主要参考taki0112/Vector_Similarity,其中提供了以下几种相似度/距离的计算方式:
-
Cosine Similarity
-
Euclidean Distance
-
Triangle’s Area Similarity (TS)
-
Sector’s Area Similairity (SS)
-
TS-SS
以上几种相似度/距离的计算方式详细介绍可以参考这里.总体来讲原作者推荐使用TS-SS这种方式来计算向量之间的相似度。
text2vec项目中提供了text2vec.simical
的方法,可以很方便计算向量间不同种类的相似度/距离。
我们假设要计算上面 Weighted Word Embeddings wrt. TFIDF 即t2v.tfidf_weighted_wv()
方法计算出的文本集向量docs_emb
中前两个文本的相似度:
# Initialize
import text2vec
sc = text2vec.simical(docs_emb[0], docs_emb[1])
# Use Cosine
simi_cos = sc.Cosine()
# Use Euclidean
simi_euc = sc.Euclidean()
# Use Triangle's Area Similarity (TS)
simi_ts = sc.Triangle()
# Use Sector's Area Similairity (SS)
simi_ss = sc.Sector()
# Use TS-SS
simi_ts_ss = sc.TS_SS()
未来工作
-
一个显而易见的事情是把
text2vec.text2vec
推广到中文文本向量化。这里需要做的是将spacy的模型读取替换成中文word embedding的读取,同时要留意中文tokenize的这一步。 -
现在的
text2vec.simical
是计算两个向量的相似度。未来可以在这个基础上开发一个多线程的相似度匹配的方法,方便进行聚类或者寻找最相似文档的任务,在chatbot问题匹配或是无标注数据的非监督任务中会有用处。 -
可以包装进SVM等几个常用分类器,来对有标签的标注数据进行监督学习的文本分类。
-
现在的方式,用户可以对
text2vec.text2vec
提供的向量化方法结果进行组合叠加产生新的文本向量;未来期望加入更多的更创新的短文本向量化的方法,如已经实现的词向量的TF-IDF加权平均的方法。