当索引变量与 r 中的另一个数据框匹配时,替换数据框中各列的值

replace values across columns in a dataframe when index variable matches to another dataframe in r

我有一个包含大约 40 列的数据集 (df1),其中包括一个 ID 变量,该变量的值可以在数千行观测值中有多个观测值。假设我有另一个数据集 (df2),其中只有大约 4 列和几行数据。 df2 中的列名可在 df1 中找到,并且 ID 变量与 df1 中的一些观察结果相匹配。每当 df1 的 ID 值与 df2 的 ID 值匹配时,我想用 df2 的值替换 df1 中的值。

这是一个例子: (为了简单起见,我在 df1 中省略了所有 40 列)



df1 <-  data.frame(ID = c('a', 'b', 'a', 'd', 'e', 'd', 'f'), 
                   var1 = c(40, 22, 12, 4, 0, 2, 1),
                   var2 = c(75, 55, 65, 15, 0, 2, 1),
                   var3 = c(9, 18, 81, 3, 0, 2, 1),
                   var4 = c(1, 11, 21, 61, 0, 2, 1),
                   var5 = c(-1, -2, -3, -4, 0, 2, 1),
                   var6 = c(0, 1, 0, 1, 0, 2, 1))

df2<- data.frame(ID = c('a', 'd', 'f'), 
                 var2 = c("fish", "pig", "cow"),
                 var4 = c("pencil", "pen", "eraser"),
                 var5 = c("lamp", "rug", "couch"))

我想要结果 df:

   ID var1  var2  var3 var4    var5  var6
1  a   40   fish  9    pencil  lamp   0
2  b   22   55    18   11      -2     1
3  a   12   fish  81   pencil  lamp   0
4  d    4   pig   3    pen     rug    1
5  e    0   0     0    0        0     0
6  d    2   pig   2    pen      rug   2
7  f    1   cow   1    eraser   couch 1

我认为有一个使用 mutate acrosscase_when 的 tidyverse 解决方案,但我不知道该怎么做。任何帮助将不胜感激。

library(tidyverse)
df1 %>% 
  mutate(row = row_number(), .before = 1) %>%       # add row number
  pivot_longer(-c(ID, row)) %>%                     # reshape long
  mutate(value = as.character(value)) %>%           # numbers as text like df2
  left_join(df2 %>%                                 # join to long version of df2
    pivot_longer(-ID), by = c("ID", "name")
  ) %>%
  mutate(new_val = coalesce(value.y, value.x)) %>%  # preferentially use df2 val
  select(-value.x, -value.y) %>%
  pivot_wider(names_from = name, values_from = new_val)  # reshape wide again

结果

# A tibble: 7 × 8
    row ID    var1  var2  var3  var4   var5  var6 
  <int> <chr> <chr> <chr> <chr> <chr>  <chr> <chr>
1     1 a     40    fish  9     pencil lamp  0    
2     2 b     22    55    18    11     -2    1    
3     3 a     12    fish  81    pencil lamp  0    
4     4 d     4     pig   3     pen    rug   1    
5     5 e     0     0     0     0      0     0    
6     6 d     2     pig   2     pen    rug   2    
7     7 f     1     cow   1     eraser couch 1 

一个选项也是循环 across df1match、'ID' 和 coalesce 中 'df2' 的列名称原始列值

library(dplyr)
df1 %>% 
   mutate(across(any_of(names(df2)[-1]),
     ~ coalesce(df2[[cur_column()]][match(ID, df2$ID)], as.character(.x))))

-输出

  ID var1 var2 var3   var4  var5 var6
1  a   40 fish    9 pencil  lamp    0
2  b   22   55   18     11    -2    1
3  a   12 fish   81 pencil  lamp    0
4  d    4  pig    3    pen   rug    1
5  e    0    0    0      0     0    0
6  d    2  pig    2    pen   rug    2
7  f    1  cow    1 eraser couch    1