关于 r:为什么 LDA 预测不正确

Why are LDA predictions incorrect

步骤1

我正在使用 R 和"topicmodels"包从 4.5k 文档语料库构建 LDA 模型。我做了通常的预处理步骤(停用词、削减低/高词频、词形还原),最终得到一个我很满意的 100 个主题模型。事实上,它几乎是满足我需求的完美模型。

1
justlda <- LDA(k=100, x=dtm_lemma, method="Gibbs", control=control_list_gibbs)

第2步

然后我使用与上述相同的过程对一个新的(模型不可见的)300 个文档语料库进行预处理,然后将其转换为文档术语矩阵,然后使用同一包的"后验"函数进行预测关于新数据的主题。该语料库来自同一作者,与训练集非常相似。

我的问题

我得到的预测(后验概率)是完全错误的。
这是我用来获取后验的代码:

1
topics = posterior(justlda, dtm_lemma, control = control_list_gibbs)$topics
  • justlda 是在步骤 1 中使用整个语料库构建的模型。
  • dtm_lemma 是新数据的预处理文档术语矩阵。
  • 控制是 lda 参数(两者相同)。

我觉得不仅预测错误,主题权重也很低。没有什么是主导话题。 (对于这 100 个主题模型,大多数主题都是 0.08,我很幸运得到一个甚至不相关的 0.20 权重......)

我在 NLP/LDA 和 R 语言方面获得了不到一年的经验。我觉得我可能在某个可以解释错误预测的地方犯了一个非常业余的错误?

这样的结果正常吗?我可能做错了什么?


我不是 100% 确定您所说的"错误"是什么意思。我做了一个快速测试,看看 posterior 是否适用于新数据。首先,我使用 AssociatedPress 数据集的所有文档运行一个模型:

1
2
3
library(topicmodels)
data("AssociatedPress")
ap_lda <- LDA(AssociatedPress, k = 5, control = list(seed = 1234))

根据您的问题,我怀疑您正在查看此处每个文档最可能的主题。为了保持可比性,我建立了自己的方式来在这里找到这些,基于一些整洁的包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
library(tidytext)
library(dplyr)
library(tidyr)
ap_documents <- tidy(ap_lda, matrix ="gamma")
ap_documents %>%
  group_by(document) %>%
  top_n(1, gamma) %>% # keep only most likely topic
  arrange(document)
# A tibble: 2,246 x 3
# Groups:   document [2,246]
   document topic gamma
      <int> <int> <dbl>
 1        1     4 0.999
 2        2     2 0.529
 3        3     4 0.999
 4        4     4 0.518
 5        5     4 0.995
 6        6     2 0.971
 7        7     1 0.728
 8        8     2 0.941
 9        9     4 0.477
10       10     5 0.500
# ... with 2,236 more rows

现在我再次运行相同的 LDA,但保留前 10 个文档:

1
2
3
4
AssociatedPress_train <- AssociatedPress[11:nrow(AssociatedPress), ]
AssociatedPress_test <- AssociatedPress[1:10, ]

ap_lda <- LDA(AssociatedPress_train, k = 5, control = list(seed = 1234))

我使用 posterior 来获取每个文档的 gamma 值,并再次保留最有可能的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
posterior(object = ap_lda, newdata = AssociatedPress_test)$topics %>%
  as_tibble() %>%
  mutate(document = seq_len(nrow(.))) %>%
  gather(topic, gamma, -document) %>%
  group_by(document) %>%
  top_n(1, gamma) %>% # keep only most probable topic
  arrange(document)
# A tibble: 10 x 3
# Groups:   document [10]
   document topic gamma
      <int> <chr> <dbl>
 1        1 4     0.898
 2        2 2     0.497
 3        3 4     0.896
 4        4 4     0.468
 5        5 4     0.870
 6        6 2     0.754
 7        7 1     0.509
 8        8 2     0.913
 9        9 4     0.476
10       10 2     0.399

除了文档 10 之外的所有文档都具有与以前相同的最可能主题。所以一切似乎都很好!所以我没有看到你的代码有直接的问题。

我没有测试过的一件事是,如果训练集和测试集的 DTM 具有不同的列,会发生什么情况。我怀疑这会是个问题。

这里有一个简单的例子来说明你如何处理这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
text1 <- tibble(doc = 1, word = LETTERS[1:10])
text2 <- tibble(doc = 1, word = LETTERS[2:11])
dtm1 <- text1 %>%
  count(doc, word) %>%
  arrange(word) %>%
  cast_dtm(doc, word, n)

dtm2 <- text2 %>%
  count(doc, word) %>%
  arrange(word) %>%
  cast_dtm(doc, word, n)

all.equal(dtm1$dimnames$Terms, dtm2$dimnames$Terms)
[1]"10 string mismatches"

我制作了两个 DTM,其中第二个有一个额外的术语,而另一个缺少一个术语。因此,dimnames 是不同的。我们可以通过将 DTM 恢复为整洁的格式来使它们相等,删除多余的术语并在再次转换 DTM 之前添加缺失的术语:

1
2
3
4
5
6
7
8
9
10
dtm2_clean <- tidy(dtm2) %>%
  filter(term %in% dtm1$dimnames$Terms) %>%
  rbind(tibble(document = 1,
               term = dtm1$dimnames$Terms, # adding term but no counts
               count = 0)) %>%
  arrange(term) %>%
  cast_dtm(document, term, count)

all.equal(dtm1$dimnames$Terms, dtm2_clean$dimnames$Terms)
[1] TRUE

您现在可以将其用作后验的新数据。