我们将涉及以下几点
使用LDA进行主题建模
使用pyLDAvis可视化主题模型
使用t-SNE可视化LDA结果
相关视频:文本挖掘:主题模型(LDA)及R语言实现分析游记数据
文本挖掘:主题模型(LDA)及R语言实现分析游记数据
时长12:59
In [1]:
from scipy import sparse as sp
Populating the interactive namespace from numpy and matplotlib
In [2]:
docs = array(p_df\['PaperText'\]) 预处理和矢量化文档
In [3]:
from nltk.stem.wordnet import WordNetLemmatizer
from nltk.tokenize import RegexpTokenizer
def docs_preprocessor(docs):
tokenizer = RegexpTokenizer(r'\\w+')
for idx in range(len(docs)):
docs\[idx\] = docs\[idx\].lower() # Convert to lowercase.
docs\[idx\] = tokenizer.tokenize(docs\[idx\]) # Split into words.
# 删除数字,但不要删除包含数字的单词。
docs = \[\[token for token in doc if not token.isdigit()\] for doc in docs\]
# 删除仅一个字符的单词。
docs = \[\[token for token in doc if len(token) > 3\] for doc in docs\]
# 使文档中的所有单词规则化
lemmatizer = WordNetLemmatizer()
docs = \[\[lemmatizer.lemmatize(token) for token in doc\] for doc in docs\]
return docs
In [4]:
docs = docs_preprocessor(docs) 计算双字母组/三元组:
主题非常相似,可以区分它们是短语而不是单个单词。
In [5]:
from gensim.models import Phrases
# 向文档中添加双字母组和三字母组(仅出现10次或以上的文档)。
bigram = Phrases(docs, min_count=10)
trigram = Phrases(bigram\[docs\])
for idx in range(len(docs)):
for token in bigram\[docs\[idx\]\]:
if '_' in token:
# Token is a bigram, add to document.
docs\[idx\].append(token)
for token in trigram\[docs\[idx\]\]:
if '_' in token:
# token是一个二元组,添加到文档中。
docs\[idx\].append(token)
Using TensorFlow backend.
/opt/conda/lib/python3.6/site-packages/gensim/models/phrases.py:316: UserWarning: For a faster implementation, use the gensim.models.phrases.Phraser class
warnings.warn("For a faster implementation, use the gensim.models.phrases.Phraser class")删除
In [6]:
from gensim.corpora import Dictionary
# 创建文档的字典表示
dictionary = Dictionary(docs)
print('Number of unique words in initital documents:', len(dictionary))
# 过滤掉少于10个文档或占文档20%以上的单词。
dictionary.filter\_extremes(no\_below=10, no_above=0.2)
print('Number of unique words after removing rare and common words:', len(dictionary))
Number of unique words in initital documents: 39534
Number of unique words after removing rare and common words: 6001
清理常见和罕见的单词,我们最终只有大约6%的词。
矢量化数据:
第一步是获得每个文档的单词表示。
In [7]:
corpus = \[dictionary.doc2bow(doc) for doc in docs\]
In [8]:
print('Number of unique tokens: %d' % len(dictionary))
print('Number of documents: %d' % len(corpus))
Number of unique tokens: 6001
Number of documents: 403
通过词袋语料库,我们可以继续从文档中学习我们的主题模型。
训练LDA模型
In [9]:
from gensim.models import LdaModel
In [10]:
%time model = LdaModel(corpus=corpus, id2word=id2word, chunksize=chunksize, \
alpha='auto', eta='auto', \
iterations=iterations, num\_topics=num\_topics, \
passes=passes, eval\_every=eval\_every)
CPU times: user 3min 58s, sys: 348 ms, total: 3min 58s
Wall time: 3min 59s如何选择主题数量?
LDA是一种无监督的技术,这意味着我们在运行模型之前不知道在我们的语料库中有多少主题存在。 主题连贯性是用于确定主题数量的主要技术之一。
但是,我使用了LDA可视化工具pyLDAvis,尝试了几个主题并比较了结果。 四个似乎是最能分离主题的最佳主题数量。
In [11]:
import pyLDAvis.gensim
pyLDAvis.enable_notebook()
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
In [12]:
Out[12]:
我们在这看到什么?
左侧面板,标记为Intertopic Distance Map,圆圈表示不同的主题以及它们之间的距离。类似的主题看起来更近,而不同的主题更远。图中主题圆的相对大小对应于语料库中主题的相对频率。
如何评估我们的模型?
将每个文档分成两部分,看看分配给它们的主题是否类似。 =>越相似越好
将随机选择的文档相互比较。 =>越不相似越好
In [13]:
from sklearn.metrics.pairwise import cosine_similarity
p_df\['tokenz'\] = docs
docs1 = p_df\['tokenz'\].apply(lambda l: l\[:int0(len(l)/2)\])
docs2 = p_df\['tokenz'\].apply(lambda l: l\[int0(len(l)/2):\])
领取专属 10元无门槛券
私享最新 技术干货