r语言 - 在dplyr中,源列和替换列都是动态if else



我有这个表:

df <- data.frame(value_2022 = c(1, NA, 3), 
volume_2022 = c(NA, 2, 3), 
value_2022_replacement = c(1.5, 2.5, 3.5),
volume_2022_replacement = c(0.5, 1.5, 2.5))
df
#>   value_2022 volume_2022 value_2022_replacement volume_2022_replacement
#> 1          1          NA                    1.5                     0.5
#> 2         NA           2                    2.5                     1.5
#> 3          3           3                    3.5                     2.5

我想通过across以编程方式将每个2022列的NA值替换为相应的_replacement列,我的代码如下所示:

df %>% 
mutate(across(matches("^v.+2022$"), (x) ifelse(is.na(x), 
{replacewithcorresponding "_replacement" variable}, 
x)))

我想知道是否有任何方法来代替{replacewithcorresponding "_replacement" variable}的东西,允许我这样做的无限数量的列匹配{same name}_2022_replacement模式。

使用coalesce

library(dplyr) # version >= 1.1.0
library(stringr)
df %>%
mutate((across(matches("\d{4}$"), ~ coalesce(.x,
pick(str_c(cur_column(), '_replacement'))[[1]]))))

与产出

value_2022 volume_2022 value_2022_replacement volume_2022_replacement
1        1.0         0.5                    1.5                     0.5
2        2.5         2.0                    2.5                     1.5
3        3.0         3.0                    3.5                     2.5

我们可以使用{dplyover}包。免责声明:我是维护人员,软件包不在CRAN上。

简单的方法是across2,它要求列按顺序排列:

library(dplyr)
library(dplyover)

df %>% 
mutate(across2(ends_with("_2022"), # below .x
ends_with("_2022_replacement"), # below .y
~ ifelse(is.na(.x), .y, .x),
.names = "{xcol}"
)
)
#>   value_2022 volume_2022 value_2022_replacement volume_2022_replacement
#> 1        1.0         0.5                    1.5                     0.5
#> 2        2.5         2.0                    2.5                     1.5
#> 3        3.0         3.0                    3.5                     2.5

更安全但更详细的选项是dplyover::over()。在这里,我们首先使用cut_names()提取变量茎,然后使用.("").fns中构造和计算函数中的字符串变量名:

df %>% 
mutate(over(cut_names("_replacement"), # extracts c("value_2022","volume_2022")
~ ifelse(is.na(.("{.x}")),
.("{.x}_replacement"),
.("{.x}")),
.names = "{x}"
)
)
#>   value_2022 volume_2022 value_2022_replacement volume_2022_replacement
#> 1        1.0         0.5                    1.5                     0.5
#> 2        2.5         2.0                    2.5                     1.5
#> 3        3.0         3.0                    3.5                     2.5

数据来自OP


df <- data.frame(value_2022 = c(1, NA, 3), 
volume_2022 = c(NA, 2, 3), 
value_2022_replacement = c(1.5, 2.5, 3.5),
volume_2022_replacement = c(0.5, 1.5, 2.5))

创建于2023-03-30 with reprex v2.0.2

下面是一个使用cur_data()cur_column()函数的dplyr解决方案。我的mutate语句的间距通常不是我格式化它的方式,但我认为这使得它更容易阅读,用于演示目的。

df <- data.frame(value_2022 = c(1, NA, 3), 
volume_2022 = c(NA, 2, 3), 
value_2022_replacement = c(1.5, 2.5, 3.5),
volume_2022_replacement = c(0.5, 1.5, 2.5))
df %>% 
mutate(
across(
matches("^v.+2022$"),
(x) ifelse(is.na(x), cur_data()[[paste(cur_column(), 'replacement', sep = '_')]], x)
)
)
value_2022 volume_2022 value_2022_replacement volume_2022_replacement
1        1.0         0.5                    1.5                     0.5
2        2.5         2.0                    2.5                     1.5
3        3.0         3.0                    3.5                     2.5

最新更新