- 1 TF-IDF
- 2 LDA
- 3 BERTopic
- 3.1 Seq2Seq
- 3.2 Attention
- 3.3 Transformer
- 3.4 BERT
- BERTopic实例
- 4 参考
常用于挖掘文本关键词:
- TF(词频) = 词在本文的出现次数/文章的总词数
- IDF(逆文档频率) = log(语料库的文档总数/包含该词的文档数+1)
- 对于某一篇文章,计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词,即为本文关键词
import jieba
import numpy as np
texts=[
'...',
'...',
'...',
'...'
]
# sklearn
# 对于中文文档,需要提前使用jieba进行分词
x_train = [" ".join(jieba.cut(text)) for text in texts[:3]]
x_test = [" ".join(jieba.cut(text)) for text in texts[3:]]
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
vectorizer = CountVectorizer()
tf_idf_transformer = TfidfTransformer()
x_train_tf_idf = tf_idf_transformer.fit_transform(vectorizer.fit_transform(x_train))
x_test_tf_idf = tf_idf_transformer.transform(vectorizer.transform(x_test))
x_train_weight = x_train_tf_idf.toarray()
x_test_weight = x_test_tf_idf.toarray()
words = vectorizer.get_feature_names()
for w in x_train_weight:
loc = np.argsort(-w)
for i in range(5):
print('{}: {} {}'.format(str(i + 1), words[loc[i]], w[loc[i]]))
print('n')
# gensim
x_train = [jieba.lcut(text) for text in texts[:3]]
x_test = [jieba.lcut(text) for text in texts[3:]]
from gensim import corpora
from gensim import models
# 建立词表
dic = corpora.Dictionary(x_train)
# 建立id2count
x_train_bow = [dic.doc2bow(sentence) for sentence in x_train]
tfidf = models.TfidfModel(x_train_bow)
tfidf_vec = []
for sentence in x_test:
word_bow = dic.doc2bow(sentence.lower())
word_tfidf = tfidf[word_bow]
tfidf_vec.append(word_tfidf)
# 输出 词语id与词语tfidf值
print(tfidf_vec)
# jieba
import jieba.analyse
# idf使用jieba默认的,也可以自行指定
keywords = jieba.analyse.extract_tags(texts[0], topK=5)
对于大规模文本,还可使用spark实现tf-idf:Spark MLlib TF-IDF – Example
2 LDA常用于本文主题分析。
词汇的分布来表达主题,主题的分布来表达文章。
LDA生成文档的过程如下:
- 从狄利克雷分布 α alpha α中取样生成文档 i i i的主题分布 θ i theta_i θi
- 从主题的多项式分布 θ i theta_i θi中取样生成文档 i i i第 j j j个词的主题 z i , j z_{i,j} zi,j
- 从狄利克雷分布 β beta β中取样生成主题 z i , j z_{i,j} zi,j对应的词语分布 ϕ z i , j phi_{z_{i,j}} ϕzi,j
- 从词语的多项式分布 ϕ z i , j phi_{z_{i,j}} ϕzi,j中采样最终生成词语 w i , j w_{i,j} wi,j
进行LDA的参数估计时,常用变分EM算法(MAP)或gibbs采样(贝叶斯估计)
from gensim import corpora, models, similarities
import jieba
docs = [
'...',
'...',
...,
'...'
]
documents = [' '.join(jieba.lcut(i)) for i in docs]
with open('stop_words.txt',encoding='UTF-8')) as f:
stoplist = [i.strip() for i in f.readlines()]
texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in documents]
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
num_topics = 10
# model = models.LsiModel(corpus, id2word = dictionary, num_topics = num_topics)
model = models.LdaModel(corpus, id2word = dictionary, num_topics = num_topics)
# model = models.RpModel(corpus, num_topics = num_topics)
# model = models.HdpModel(corpus, id2word = dictionary)
doc = "..."
vec_bow = dictionary.doc2bow(jieba.lcut(doc))
vec_lsi = model[vec_bow]
index = similarities.MatrixSimilarity(model[corpus])
# index = similarities.Similarity(output_prefix='Similarity',corpus=model[corpus],num_features=500)
sims = index[vec_lsi]
# sims = sorted(enumerate(sims),key=lambda item:-item[1])
# print(sims)
result = [(docs[i[0]],i[1]) for i in enumerate(sims)]
result = sorted(result ,key = lambda x: -x[1])
print(result)
同样地,Spark MLlib也提供了LDA的支持,Topic modelling using Latent Dirichlet Condition in Apache Spark MLlib
3 BERTopicGitHub - UKPLab/sentence-transformers
GitHub - MaartenGr/BERTopic
BERTopic是一个基于sentence-BERT实现的主题模型工具,可以轻松地实现主题的抽取、计算,同时可以替换不同的预训练模型。
sbert.net - Pretrained Models
Sentence-BERT使用了孪生神经网络结构,将两个不同的句子输入BERT,然后进行pooling,得到输出向量,最后计算向量相似度,得到句子相似度。
而BERT需要参考如下的学习路线
3.1 Seq2SeqSeq2Seq -> Attention -> Transformer -> BERT
有一些NLP任务的输入输出序列都是长度可变的,例如机器翻译、对话机器人等,为了解决这类问题,常见的解决方案是使用编码器-解码器架构,利用编码器将不定长的输入序列编码成一个向量,称为context,解码器对context进行解码,得到输出序列。
编码器、解码器常用多层循环神经网络来实现。
3.2 Attention编码器-解码器架构存在一些问题:
- 输入序列很长时,通过循环网络产生的context向量很难表达整句的信息,而是偏向于表达离序列结尾近的信息
- 解码器仅依赖编码器最后一个隐藏层状态,信息利用率较低
因此一个可行的优化就是利用编码器所有的隐藏层状态:
from bertopic import BERTopic
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
import jieba
def tokenize_zh(text):
words = jieba.lcut(text)
return words
docs = [
'...',
'...',
...,
'...'
]
vectorizer = CountVectorizer(tokenizer=tokenize_zh)
# 初始化Bertopic模型
model = BERTopic(language='chinese (simplified)', vectorizer_model=vectorizer)
topics, probs = model.fit_transform(docs)
topic2doc = pd.DataFrame({'topic': topics, 'doc': docs})
print(model.get_topic_info())
print(topic2doc)
4 参考
Spark MLlib TF-IDF – Example
通俗理解LDA主题模型
GitHub - MaartenGr/BERTopic


![[自然语言处理]文本主题相关(TF-IDF/LDA/Sentence-BERT) [自然语言处理]文本主题相关(TF-IDF/LDA/Sentence-BERT)](http://www.mshxw.com/aiimages/31/976783.png)
