理解 LDA/主题建模——主题重叠太多

Understanding LDA / topic modelling -- too much topic overlap

我是主题建模/Latent Dirichlet Allocation 的新手,无法理解如何将这个概念应用到我的数据集(或者它是否是正确的方法)。

我有少量文学文本(小说),想使用 LDA 提取一些一般主题。

我正在使用 Python 中的 gensim 模块以及一些 nltk 功能。为了进行测试,我将我的原始文本(只有 6 个)分成 30 个块,每个块 1000 个单词。然后我将这些块转换为文档术语矩阵和 运行 算法。这是代码(虽然我认为这与问题无关):

# chunks is a 30x1000 words matrix

dictionary = gensim.corpora.dictionary.Dictionary(chunks)
corpus = [ dictionary.doc2bow(chunk) for chunk in chunks ]
lda = gensim.models.ldamodel.LdaModel(corpus = corpus, id2word = dictionary,
    num_topics = 10)
topics = lda.show_topics(5, 5)

然而,结果与我见过的任何例子都完全不同,因为主题充满了可以在 all 源文档中找到的无意义的单词,例如"I"、"he"、"said"、"like"、...示例:

[(2, '0.009*"I" + 0.007*"\'s" + 0.007*"The" + 0.005*"would" + 0.004*"He"'), 
(8, '0.012*"I" + 0.010*"He" + 0.008*"\'s" + 0.006*"n\'t" + 0.005*"The"'), 
(9, '0.022*"I" + 0.014*"\'s" + 0.009*"``" + 0.007*"\'\'" + 0.007*"like"'), 
(7, '0.010*"\'s" + 0.009*"I" + 0.006*"He" + 0.005*"The" + 0.005*"said"'), 
(1, '0.009*"I" + 0.009*"\'s" + 0.007*"n\'t" + 0.007*"The" + 0.006*"He"')]

我不太明白为什么会发生这种情况,或者为什么我看到的示例不会发生这种情况。如何让 LDA 模型找到重叠更少且更具特色的主题?是不是先过滤掉比较常用的词?如何调整模型运行的次数?是不是原文数量太少了?

LDA 极度依赖于语料库中使用的词以及它们出现的频率。你看到的词都是停用词——无意义的词,是一种语言中最常见的词,例如"the"、"I"、"a"、"if"、"for"、"said"等,由于这些词出现频率最高,会产生负面影响模型。

我会使用 nltk 停用词语料库来过滤掉这些词:

from nltk.corpus import stopwords
stop_words = stopwords.words('english')

然后确保您的文本不包含 stop_words 列表中的任何单词(通过您使用的任何预处理方法)- 下面是一个示例

text = text.split() # split words by space and convert to list
text = [word for word in text if word not in stop_words]
text = ' '.join(text) # join the words in the text to make it a continuous string again

您可能还想删除标点符号和其他字符(“/”、“-”)等),然后使用正则表达式:

import re
remove_punctuation_regex = re.compile(r"[^A-Za-z ]") # regex for all characters that are NOT A-Z, a-z and space " "
text = re.sub(remove_punctuation_regex, "", text) # sub all non alphabetical characters with empty string ""

最后,您可能还想过滤语料库中最频繁或最不频繁的单词,您可以使用 nltk 来完成:

from nltk import FreqDist
all_words = text.split() # list of all the words in your corpus
fdist = FreqDist(all_words) # a frequency distribution of words (word count over the corpus)
k = 10000 # say you want to see the top 10,000 words
top_k_words, _ = zip(*fdist.most_common(k)) # unzip the words and word count tuples
print(top_k_words) # print the words and inspect them to see which ones you want to keep and which ones you want to disregard

那应该去掉停用词和多余的字符,但仍然留下了主题建模的巨大问题(我不会在这里尝试解释,但会留下一些提示和链接)。

假设您对主题建模有所了解,让我们开始吧。 LDA 是词袋模型,意味着词序无关紧要。该模型为每个文档分配一个主题分布(预定数量的主题 K),并为每个主题分配一个词分布。一个非常有洞察力的 high level video explains this here. If you want to see more of the mathematics, but still at an accessible level, check out this video. The more documents the better, and usually longer documents (with more words) also fair better using LDA - this paper 表明 LDA 在短文本(少于 ~20 个单词)上表现不佳。 K 由您选择,并且实际上取决于您的文档语料库(它有多大,涵盖了哪些不同的主题等)。通常一个好的 K 值在 100-300 之间,但这同样取决于你的语料库。

LDA 有两个超参数,alpha 和 beta(gemsim 中的 alpha 和 eta)——较高的 alpha 意味着每个文本将由更多的主题表示(因此自然较低的 alpha 意味着每个文本将由较少的主题表示)。高 eta 意味着每个主题由更多的单词表示,而低 eta 意味着每个主题由较少的单词表示 - 因此,如果 eta 低,主题之间的 "overlap" 就会更少。

使用 LDA 可以获得很多见解

  1. 语料库中的主题是什么(命名主题可能对您的应用程序无关紧要,但如果需要,可以像上面那样通过检查主题中的单词来完成)

  2. 哪些词对主题贡献最大

  3. 语料库中哪些文档最相似(使用similarity metric

希望这对您有所帮助。几个月前我是 LDA 的新手,但我很快就使用 Whosebug 和 youtube 加快了速度!