繁体   English   中英

用另一个 data.table 的相关值替换 data.table 列中的向量值的最有效方法是什么?

[英]What is the most efficient way to replace a vector's values in a data.table's column with correlating values from another data.table?

这是我的问题的缩小样本。 我有一个 data.table ,其中有一列以矢量形式存在的多个 ID。 这些 ID 都对应另一个 data.table 中的单词。

ID.table <- data.table(IDs = list(c(4, 5, 6), c(2, 3, 4)))
word.table <- data.table(ID = c(1, 2, 3, 4, 5, 6), word = c("This", "is", "a", "test", "sentence", "."))

产生

     IDs
1: 4,5,6
2: 2,3,4

   ID     word
1:  1     This
2:  2       is
3:  3        a
4:  4     test
5:  5 sentence
6:  6        .

我需要将 ID.table 中的所有 ID 转换为 word.table 中的相应单词,如下所示。

               IDs
1: test,sentence,.
2:       is,a,test

我知道我可以使用 for 循环并遍历 ID.table 中的每个向量来做到这一点,但我的实际表有数千行,这意味着它运行非常缓慢。

row <- 1
for(ID.row in ID.table[, IDs]){
  word.row <- word.table[ID %in% ID.row]$word
  ID.table[row] <- word.row
  
  row <- row + 1
}

有没有更有效的方法来做到这一点?

编辑:我在 word.table 中列出从 1 开始的顺序 ID 是一个错误。 ID.table 和 word.table 看起来更像这样。

           IDs
1: 608,609,610
2: 606,607,608

     ID     word
1:  605     This
2:  606       is
3:  607        a
4:  608     test
5:  609 sentence
6:  610        .

其中 ID.table 的每一行将是一个不从 1 开始的序列号向量,并且 word.table 的 ID 列将具有不总是不从 1 开始的序列号。

您可以使用match

library(data.table)

ID.table[, IDs := lapply(IDs,function(x) word.table$word[match(x,word.table$ID)])]
ID.table

#               IDs
#1: test,sentence,.
#2:       is,a,test

如果您可以使用tidyverse函数,另一种选择是word.table IDs并使用unnest加入。

library(dplyr)

ID.table %>%
  mutate(row = row_number()) %>%
  tidyr::unnest(IDs) %>%
  left_join(word.table, by = c('IDs' = 'ID')) %>%
  group_by(row) %>%
  summarise(Ids = list(word)) %>%
  select(-row)

我们可以传递一个命名向量来匹配和替换,方法是遍历列表列“IDs”并将( := )output 分配回 IDs

ID.table[, IDs := lapply(IDs, function(x) 
       setNames(word.table$word, word.table$ID)[as.character(x)])]

如果 ID 是按顺序排列的,则更容易,即使用 ID 作为数字索引来替换“word”列中的相应值

ID.table[, IDs := lapply(IDs, function(x) word.table$word[x])]
ID.table
#              IDs
#1: test,sentence,.
#2:       is,a,test

最好不要通过unlist循环执行一次,替换值,然后重新relist

ID.table[, IDs := relist(word.table$word[unlist(IDs)], skeleton= IDs)]

注意:这两种方法都更简单,更直接和高效


或使用紧凑的 tidyverse 方法

library(purrr)
library(dplyr)
ID.table %>% 
      mutate(IDs = map(IDs, ~ word.table$word[.x]))
#              IDs
#1: test,sentence,.
#2:       is,a,test

这不会改变data.table的原始属性结构

基准

在稍大的数据集上

ID.table1 <- ID.table[rep(seq_len(.N), 1e6)]
ID.table2 <- copy(ID.table1)
ID.table3 <- copy(ID.table1)
ID.table4 <- copy(ID.table1)

system.time(ID.table1[, IDs := lapply(IDs, function(x) 
       setNames(word.table$word, word.table$ID)[as.character(x)])])
#user  system elapsed 
# 29.971   0.492  30.264 
       
system.time(ID.table2[, IDs := lapply(IDs, function(x) word.table$word[x])])
#user  system elapsed 
#  8.079   0.086   8.097 

system.time(ID.table3[, IDs := relist(word.table$word[unlist(IDs)], skeleton= IDs)])
# user  system elapsed 
# 14.085   0.109  14.081 

system.time(ID.table4 %>% 
      mutate(IDs = map(IDs, ~ word.table$word[.x])))
#user  system elapsed 
#  3.724   0.018   3.734 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM