这是我问题的缩小示例。我有一个数据表,其中包含矢量形式的多个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
函数,另一种选择是unnest
IDs
并使用word.table
连接。
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)
我们可以通过循环列表列"ID"来传递一个命名向量进行匹配和替换,并将输出分配(:=
(回ID。
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
ing,替换值,然后relist
来执行此操作一次而不
ID.table[, IDs := relist(word.table$word[unlist(IDs)], skeleton= IDs)]
注意:两种方法都很简单,更直接,更有效
<小时 />或使用紧凑的整洁方法
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