从单个 table 中查找多列

Lookup multiple column from a single table

假设我有以下数据

df <- structure(list(car_model = c(301, 302, 303, 304), colour = c(501, 
502, 503, 504), sales = c(182, 191, 302, 101)), row.names = c(NA, 
-4L), class = c("tbl_df", "tbl", "data.frame"))

我有一个查找 table,我将在其中获取文本以替换列 car_modelcolour.

中的代码
tbl1 <- structure(list(txt = c("A", "B", "C", "Y"), cod = c(301, 302, 
303, 304), var = c("car_model", "car_model", "car_model", "car_model"
)), row.names = c(NA, -4L), class = c("tbl_df", "tbl", "data.frame"
))
tbl2 <- structure(list(txt = c("black", "green", "red", "white"), cod = c(501, 
502, 503, 504), var = c("colour", "colour", "colour", "colour"
)), row.names = c(NA, -4L), class = c("tbl_df", "tbl", "data.frame"
))

结合我拥有的两个 table

tbl <- rbind(tbl1,tbl2)
# A tibble: 8 x 3
  txt     cod var      
  <chr> <dbl> <chr>    
1 A       301 car_model
2 B       302 car_model
3 C       303 car_model
4 Y       304 car_model
5 black   501 colour   
6 green   502 colour   
7 red     503 colour   
8 white   504 colour   

有没有一种方法可以使用这种查找 table 来替换主 df 中的所有列(通过列 var 和 [ 中的值匹配列名=18=]) 或者我需要制作单独的 tables,每个变量一个?我的另一个疑问是,在具有约 1000 万行、30 个或更多变量和总大小约 5000 行的查找 table 的数据集中执行此操作是否合理。

编辑:关于代码可以在不同的变量中使用相同的代码。

EDIT2:我正在寻找一种快速且内存高效的解决方案。也许 data.table

的一些解决方案

这是 tidyverse

的一种方式
  1. 循环 across 在 'tbl'
  2. 的 'var' 列的 unique 值中找到的列
  3. 获取带cur_column()的循环列的列名,在'tbl'的'var'列上创建逻辑表达式('i1')
  4. 使用match获取列值与'tbl'
  5. 的'cod'列的子集匹配的位置索引
  6. 根据'i1'
  7. 从子集中提取'tbl'对应的'txt'列
library(dplyr)
df <- df %>% 
    mutate(across(all_of(unique(tbl$var)),
     ~ {i1 <- tbl$var == cur_column()
       tbl$txt[i1][match(., tbl$cod[i1])]}))

-输出

df
# A tibble: 4 x 3
  car_model colour sales
  <chr>     <chr>  <dbl>
1 A         black    182
2 B         green    191
3 C         red      302
4 Y         white    101

或者用data.table,我们可以用同样的方法

  1. 从 'tbl' ('nm1')
  2. 创建了一个命名向量
  3. 将 'data.frame' 转换为 'data.table' (setDT)
  4. 从 'var'
  5. unique 元素指定 .SDcols 中感兴趣的列
  6. 通过 Map 循环执行 match 并将输出分配 (:=) 回原始列
library(data.table)
nm1 <- setNames(tbl$txt, tbl$cod)
un1 <- unique(tbl$var)
setDT(df)[, (un1) := Map(function(x, y) 
     nm1[tbl$var == y][as.character(x)], .SD,  un1), .SDcols = un1]

-输出

df
   car_model colour sales
1:         A  black   182
2:         B  green   191
3:         C    red   302
4:         Y  white   101

或者可以使用base R

lst1 <- with(tbl, split(setNames(txt, cod), var))
df[un1] <- Map(function(x, y)  y[as.character(x)], df[un1], lst1)

一个data.table选项

cbind(unstack(setDT(tbl)[melt(
  setDT(df)[, .(car_model, colour)], ,
  variable.name = "var",
  value.name = "cod"
), .(txt, var), on = .(var, cod)]), df[, .(sales)])

给予

  car_model colour sales
1         A  black   182
2         B  green   191
3         C    red   302
4         Y  white   101

您可以重塑数据并执行连接。

library(dplyr)
library(tidyr)

df %>%
  pivot_longer(cols = -sales) %>%
  left_join(tbl, by = c('name' = 'var', 'value' = 'cod')) %>%
  select(-value) %>%
  pivot_wider(names_from = name, values_from = txt)

#  sales car_model colour
#  <dbl> <chr>     <chr> 
#1   182 A         black 
#2   191 B         green 
#3   302 C         red   
#4   101 Y         white