在 R 中的自定义 ifelse() 中调用数据变量

Calling a data variable within a custom ifelse() in R

我正在尝试编写一个我想传递给 dplyr::mutate(across()) 的专用 ifelse() 函数。该函数应将 across() 中指定的列中的 NA 值替换为类似名称的列中的值。

例如在下面的虚构数据中,我想用y_var1替换缺失的x_var1,用y_var2替换缺失的x_var2

x <- tribble(~x_var1, ~x_var2, ~y_var1, ~y_var2,
             5, 2, 0, 0,
             NA, 10, 8, 0,
             3, NA, 0, 5,
             NA, NA, 7, 9)   

我试过构建以下函数:

ifelse_spec <- function(var) {
  new_var = paste("y_", str_remove(cur_column(), "x_"), sep = "")
 
  # print(new_var) # just to check new_var is correct 

  ifelse(is.na(var), !!sym(new_var) , var)  # how to call new_var?
}

x %>%
  mutate(across(c(x_var1, x_var2),
                ~ ifelse_spec(.)))

但是好像不行。

但是,如果我 运行 这个单变量案例直接使用 ifelse,我会得到预期的结果。

x %>% 
  mutate(across(c(x_var1),
                ~ifelse(is.na(.), !!sym("y_var1"), .)))

如何构建允许我调用数据变量的自定义 ifelse 语句?

编辑:我得到了以下适用于多变量情况的方法,但仍在使用 ifelse 而不是其他函数。

x %>% 
  mutate(across(c(x_var1, x_var2),
                ~ifelse(is.na(.), eval(sym(paste("y_", str_remove(cur_column(), "x_"), sep = ""))), . )))

coalesce()就是针对这个问题设计的(从其他列中填充缺失值)。您可以通过使用它而不是 ifelse:

来简化单变量案例
library(dplyr, warn.conflicts = FALSE)
library(stringr)
library(purrr)

x <- tribble(~x_var1, ~x_var2, ~y_var1, ~y_var2,
             5, 2, 0, 0,
             NA, 10, 8, 0,
             3, NA, 0, 5,
             NA, NA, 7, 9)

x %>% 
  mutate(x_var1 = coalesce(x_var1, y_var1))
#> # A tibble: 4 x 4
#>   x_var1 x_var2 y_var1 y_var2
#>    <dbl>  <dbl>  <dbl>  <dbl>
#> 1      5      2      0      0
#> 2      8     10      8      0
#> 3      3     NA      0      5
#> 4      7     NA      7      9

然后您可以使用 select() 将其概括为合并具有相似名称的列:

x %>% 
  mutate(x_var1 = do.call(coalesce, select(., ends_with("var1"))))
#> # A tibble: 4 x 4
#>   x_var1 x_var2 y_var1 y_var2
#>    <dbl>  <dbl>  <dbl>  <dbl>
#> 1      5      2      0      0
#> 2      8     10      8      0
#> 3      3     NA      0      5
#> 4      7     NA      7      9

最后,使用map_dfc将这个函数应用到每一列,使用模式匹配提取它所属的“列组”:

x %>% 
  colnames() %>% 
  str_extract("var[0-9]") %>% 
  set_names(colnames(x)) %>% 
  map_dfc(~do.call(coalesce, select(x, ends_with(.))))
#> # A tibble: 4 x 4
#>   x_var1 x_var2 y_var1 y_var2
#>    <dbl>  <dbl>  <dbl>  <dbl>
#> 1      5      2      5      2
#> 2      8     10      8     10
#> 3      3      5      3      5
#> 4      7      9      7      9

您需要调整 str_extract()ends_with() 以适应您的真实数据中的列名称,但我认为这应该推广到任何合理的命名方案。如果将自定义函数应用于您的真实数据而不是 coalesce() 很重要,那么也应该可以重写 map_dfc() 来使用它。