【问题标题】:tokens_compound() in quanteda changes the order of featuresquanteda 中的 tokens_compound() 改变了特征的顺序
【发布时间】:2021-02-18 08:44:19
【问题描述】:

我在 quanteda 中发现 tokens_compound() 会更改不同 R 会话中令牌的顺序。也就是说,即使种子值是固定的,每次重新启动会话后结果都会有所不同,尽管它不会在单个会话中改变。

这是复制过程:

  1. 查找搭配、复合标记并保存它们。
library(quanteda)

set.seed(12345)

data(data_corpus_inaugural)

toks <- data_corpus_inaugural %>% 
  tokens(remove_punct = TRUE,
         remove_symbol = TRUE, 
         padding = TRUE) %>% 
  tokens_tolower()

col <- toks %>% 
  textstat_collocations()

toks.col <- toks %>%
  tokens_compound(pattern = col[col$z > 3])

write(attr(toks.col, "types"), "col1.txt")
  1. 结束并重新启动 R 会话并再次运行上述代码,将“col1.txt”替换为“col2.txt”。

  2. 比较两组token,发现它们是不同的。

col1 <- read.table("col1.txt")
col2 <- read.table("col2.txt")

identical(col1$V1, col2$V1) # This should return FALSE.

col1$V1[head(which(col1$V1 != col2$V1))]
col2$V1[head(which(col1$V1 != col2$V1))]

这在很多情况下都无关紧要,但 LDA(通过 {topicmodels})的结果会在不同的会话中发生变化。我猜是这样,因为如果我将tokens 中的功能顺序重置为as.list(),然后as.tokens()dfm_sort() 不适用于此),LDA 的结果是不变的。

我想知道这是否只发生在我身上(Ubuntu 18.04.5、R 4.0.4 和 quanteda 2.1.2),并且很高兴听到另一个(更简单的)解决方案。

2 月 20 日更新

例如,LDA的输出不复现。

lis <- list()
for (i in seq_len(2)) {
  set.seed(123)
  lis[[i]] <- tokens_compound(toks, pattern = col[col$z > 3]) %>% 
    dfm() %>% 
    convert(to = "topicmodels") %>% 
    LDA(k = 5,
        method = "Gibbs",
        control = list(seed = 12345,
                       iter = 100))
}

head(lis[[1]]@gamma)
head(lis[[2]]@gamma)

【问题讨论】:

  • 我还看到identical(col1$V1, col2$V1) 在 Windows 10 计算机 quanteda 2.1.2 上返回 FALSE。我认为您可能需要编辑您的标题和帖子。你问的是tokens_compound() 还是text_compound()
  • 谢谢。这是我的错字(应该是tokens_compound())。

标签: r quanteda


【解决方案1】:

一个有趣的调查,但这既不是错误也不是什么值得关注的。在 quanteda 令牌对象中,在处理步骤(例如 textstat_compound())之后,类型不是按顺序确定的。这是因为这个函数在 C++ 中是并行化的,这些线程的操作方式并没有被 R 中的set.seed() 固定。但这不会影响重要的部分,即类型集或任何关于令牌本身的内容。如果您希望提取的类型的顺序相同,则应在提取时对其进行排序。

library("quanteda")
## Package version: 2.1.2

toks <- data_corpus_inaugural %>%
  tokens(
    remove_punct = TRUE,
    remove_symbol = TRUE,
    padding = TRUE
  ) %>%
  tokens_tolower()
col <- quanteda.textstats::textstat_collocations(toks)

事实证明,您不需要保存输出或重新启动 R - 这发生在单个会话中。

# types are differently indexed, but are the same set
lis <- list()
for (i in seq_len(2)) {
  set.seed(123)
  toks.col <- tokens_compound(toks, pattern = col[col$z > 3])
  lis <- c(lis, list(types = types(toks.col)))
}
dframe <- data.frame(lis)

sum(dframe$types != dframe$types.1)
## [1] 19898
head(dframe[dframe$types != dframe$types.1, ])
##                                            types              types.1
## 8897                              at_this_second   my_fellow_citizens
## 8898 to_take_the_oath_of_the_presidential_office            no_people
## 8899                                    there_is             on_earth
## 8900                                occasion_for cause_to_be_thankful
## 8901                                 an_extended         this_is_said
## 8902                                   there_was            spirit_of

但是(无序的)类型集是相同的:

# but
setequal(dframe$types, dframe$types.1)
## [1] TRUE

更重要的是,当我们比较每个有序标记的值时,它们是相同的:

# tokens are the same
lis <- list()
for (i in seq_len(2)) {
  set.seed(123)
  toks.col <- tokens_compound(toks, pattern = col[col$z > 3])
  lis <- c(lis, list(toks = as.character(toks.col)))
}
dframe <- data.frame(lis)
all.equal(dframe$toks, dframe$toks.1)
## [1] TRUE

reprex package (v1.0.0) 于 2021-02-18 创建

此分析强调了其重要性的附加评论:我们强烈反对直接访问对象属性。如上所述使用types(x),而不是attr(x, "types")。前者将永远有效。后者依赖于我们对对象的实现,这可能会随着我们对包的改进而改变。

【讨论】:

  • 感谢您的详细解释,我明白为什么会发生(也感谢您对使用attr() 的警告)。我知道令牌和频率是相同的,但 LDA 的结果不同可能是因为 dfm 对象继承了 tokens 对象中令牌的顺序(我将代码添加到问题中)。关于这一点我能问一下你的意见吗?
  • 您与LDA() 的不同结果是因为它的结果是不确定的。您可以通过在转换之前在您的 dfm 上运行 dfm_sort() 来测试这一点,您会看到对于相同的 dfm,两次运行的 LDA 不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 2019-01-27
  • 1970-01-01
  • 2016-08-12
  • 2020-02-10
  • 1970-01-01
  • 2021-07-28
相关资源
最近更新 更多