比较 R 数据框中的列集并从每组两列中保留一个值

compare sets of columns in R dataframe and keep one value from each set of two columns

基本上,我有一个包含许多不同变量的大型数据集。数据是成对排序的(2019 年和 2020 年),对于某些年份的变量,某些变量仅适用于 2019 年,有些仅适用于 2020 年。我希望 2020 年的数据 'override' 2019 年的数据,但前提是它可在 2020 年和 2019 年获得。如果没有任何一年的数据可用,则数据应该保持缺失。我现在使用一些辅助函数来执行此操作,但这应该更具可扩展性,以便我可以为 200 多个列对执行此操作。 mutate(across(....),)

我错过了什么

# Create data
mydf <- tibble(ID = 1:5,
               var1_2019 = c(9, NA, 3, 2, NA),
               var1_2020 = c(NA, NA, 3, 2, 4),
               var2_2019 = c("A", "B",NA, "D", "C"),
               var2_2020 = c(NA, "B",NA, "R", NA),
               var3_2019 = c(T, F, NA, NA, NA),
               var3_2020 = c(NA, NA, NA, NA, F))

# create little helper function. this is good because
# it could be made more complex in the future, 
# for example for numeric variables keeping the larger of the two
which_to_keep_f <-
  function(x, y) {
    if (is.na(x) && is.na(y)) {
      output <- NA
    }
    if (is.na(x) && !is.na(y)) {
      output <- y
    }
    if (!is.na(x) && is.na(y)) {
      output <- x
    }
    if (!is.na(x) && !is.na(y)) {
      output <- y
    }
    output
  }
# vectorize it
which_to_keep_f_vec <- Vectorize(which_to_keep_f)

# use function inside mutate

mydf %>% 
  mutate(var1 = which_to_keep_f_vec(var1_2019, var1_2020)) %>% 
  mutate(var2 = which_to_keep_f_vec(var2_2019, var2_2020)) %>% 
  mutate(var3 = which_to_keep_f_vec(var3_2019, var3_2020)) %>% 
  select(-contains("_20"))

解决方案

感谢 TarJae 和 micahkimel,我得到了 99% 的解决方案。这是完整的解决方案(包括删除不再需要的变量并将变量重命名为所需的格式)

mydf %>%
  mutate(across(ends_with('_2019'), 
                ~(which_to_keep_f_vec(.,
                                      get(stringr::str_replace(cur_column(), "_2019$", "_2020"))))) %>% 
           unnest(cols=c()))%>% 
  select(-contains("_2020")) %>%
  rename_all(~ stringr::str_replace(., regex("_2019$", ignore_case = TRUE), ""))

更新:感谢 micahkimel 删除 list 以不重复数据:

这就是您要找的吗?在这里,我们将您的函数应用于成对集合:

library(dplyr)
library(stringr)
mydf %>%
  mutate(across(ends_with('_2019'), 
                ~(which_to_keep_f_vec(.,
                                          get(str_replace(cur_column(), "_2019$", "_2020"))))) %>% 
  unnest(cols=c())
       ID var1_2019 var1_2020 var2_2019 var2_2020 var3_2019 var3_2020
  <int>     <dbl>     <dbl> <chr>     <chr>     <lgl>     <lgl>    
1     1         9        NA A         NA        TRUE      NA       
2     2        NA        NA B         B         FALSE     NA       
3     3         3         3 NA        NA        NA        NA       
4     4         2         2 R         R         NA        NA       
5     5         4         4 C         NA        FALSE     FALSE   

这是一种方法,可以为输入中的每对变量生成一个变量 table。首先,使用 pivot_longer() 将对折叠成单个变量,并将 year 添加为一列(观察值是原来的两倍)。

mydf_long = mydf %>%
  pivot_longer(cols = matches("_20"), names_to = c(".value", "year"),
               names_sep = "_")
      ID year   var1 var2  var3 
   <int> <chr> <dbl> <chr> <lgl>
 1     1 2019      9 A     TRUE 
 2     1 2020     NA NA    NA   
 3     2 2019     NA B     FALSE
 4     2 2020     NA B     NA   
 5     3 2019      3 NA    NA   
 6     3 2020      3 NA    NA   
 7     4 2019      2 D     NA   
 8     4 2020      2 R     NA   
 9     5 2019     NA C     NA   
10     5 2020      4 NA    FALSE

接下来,使用 fill() 用较早的非缺失值填充较晚的 NA 值。然后我们可以过滤到最近的一年(2020 年)。对于每个变量,那一年如果以前有的话,那一年将有自己的值;否则,它将结转上一年的价值。

mydf_long %>%
  group_by(ID) %>%
  fill(var1, var2, var3) %>%
  filter(year == 2020)
     ID year   var1 var2  var3 
  <int> <chr> <dbl> <chr> <lgl>
1     1 2020      9 A     TRUE 
2     2 2020     NA B     FALSE
3     3 2020      3 NA    NA   
4     4 2020      2 R     NA   
5     5 2020      4 C     FALSE