基于查找表的data.table中的重新连接值

时间:2017-11-24 09:47:39

标签: r data.table lookup

我试图在一个非常大的数据集(~25M行,~3000 cols)上实现重新查找,基于大的查找表(~15M行) 我只需要更改匹配的值并保持不匹配不变

这是一个数据样本

查找表

source  target
A       1
B       2
C       3
D       4
...     ...

源数据(在我的表加载之前,我不知道cols计数)

col1    col2    col3    ...     coln
B       C       A       ...     ...
78      A       D       ...     ...
A       B       24      ...     ...
...     ...     ...     ...     ...

预期结果

col1    col2    col3    ...     coln
2       3       1       ...     ...
78      1       4       ...     ...
1       2       24      ...     ...
...     ...     ...     ...     ...

我已经能够使用嵌套循环实现这一点,但是:

  1. 这很慢
  2. 我知道R比那更聪明
  3. 我发现一些帖子存在同等问题,但在我的情况下似乎没有一个解决方案可行。

    有什么建议吗?

    由于

    (尝试了解释herehere的不同解决方案但没有成功)

1 个答案:

答案 0 :(得分:2)

使用dplyrtidyr的解决方案。我们的想法是从宽格式重塑数据帧,然后根据数据框和查找表中的值执行连接,然后将格式转换回来。

library(dplyr)
library(tidyr)

dt2 <- dt %>%
  mutate(ID = 1:n()) %>%
  gather(Column, Value, -ID) %>%
  left_join(dt_lookup, by = c("Value" = "source")) %>%
  mutate(target = as.numeric(ifelse(is.na(target), Value, target))) %>%
  select(-Value) %>%
  spread(Column, target) %>%
  select(-ID)
dt2
#   col1 col2 col3
# 1    2    3    1
# 2   78    1    4
# 3    1    2   24

或者您也可以使用相同策略的data.table方法。 dt4是最终输出。

library(data.table)

# Convert the data frame to data table
setDT(dt, keep.rownames = TRUE) 
setDT(dt_lookup)

# Reshape the data table from wide to long
dt2 <- melt(dt, id.vars = "rn")
# Set the key for the join operation
setkey(dt2, value)
setkey(dt_lookup, source)
# Perform join and replace the values
dt3 <- dt_lookup[dt2][, target := as.numeric(ifelse(is.na(target), source, target))]
# Reshape the data table from long to wide
dt4 <- dcast(dt3, rn ~ variable, value.var = "target")[, rn := NULL]

数据

dt_lookup <- read.table(text = "source  target
A       1
                        B       2
                        C       3
                        D       4",
                        header = TRUE, stringsAsFactors = FALSE)

dt <- read.table(text = "col1    col2    col3
B       C       A   
                 78      A       D 
                 A       B       24",
                 header = TRUE, stringsAsFactors = FALSE)