r-基于单个if条件突变多个列



我有一个示例df:

df <- data.frame(
var1 = c("A", "B"),
var2 = c("C", "D"),
var3 = c("E", "F"),
var4 = c("G", "H"),
var5 = c("I", "J"),
var6 = c("K", "L"),
var7 = c("M", "N"),
var8 = c(NA, "P"))

df2是我想要的输出:


df2 <- data.frame(
var1 = c("I", "B"),
var2 = c("Z", "D"),
var3 = c("M", "F"),
var4 = c("G", "H"),
var5 = c("I", "J"),
var6 = c("K", "L"),
var7 = c("M", "N"),
var8 = c(NA, "P"),
inputed_flag = c("Y","N"))

基本逻辑如下:


df3 <- df %>%
mutate(var1 = ifelse(is.na(var8), var5, var1),
var2 = ifelse(is.na(var8), "Z", var2),
var3 = ifelse(is.na(var8), var7, var3),
imputed_flag = ifelse(is.na(var8), "Y", "N"))

但在R中,是否有一种基于单个if条件的更简单/更紧凑的方法来改变列?这种情况下的条件是,如果缺少var8,则为其他变量估算某些值。如果没有一堆具有相同条件的ifelse语句,我不知道还有什么方法可以做到这一点。

在sas中,我们可以做一些类似的事情


if missing(var8) then do;
var1 = var5;
var2 = "Z";
var3 = var7;
imputed_flag = "Y";
end;
if not missing(var8) then imputed_flag = "N";

其中,如果满足单个if条件,则可以在一个if语句中对多个变量进行突变。

如果可能的话,我正在寻找一个像这样的优雅的R解决方案。

我认为在基R中的简单子集分配在这里是合理的:

i <- is.na(df$var8)
df[i, 1:3] <- data.frame(var1 = df$var5[i], var2 = "z", var3 = df$var7[i])
cbind(df, imputed_flag = i)
#>   var1 var2 var3 var4 var5 var6 var7 var8 imputed_flag
#> 1    I    z    M    G    I    K    M <NA>         TRUE
#> 2    B    D    F    H    J    L    N    P        FALSE

创建于2022-08-17由reprex包(v2.0.1(

看起来Map将是更简洁的

nm1 <- paste0("var", 1:3)
i1 <- is.na(df$var8)
df[nm1] <- Map(function(x, y) ifelse(i1, y, x), 
df[nm1], c(df['var5'], 'Z', df['var7']))
df$imputed_flag <- c("N", "Y")[1 + i1]

-检查

> names(df2)[length(df2)] <- "imputed_flag"
> all.equal(df, df2)
[1] TRUE

或者另一个选项(灵感来自@Allan Cameron的帖子(将是在"df"中创建一个临时列,然后使用行索引和列名重新排序来更新值

nm1 <- paste0("var", 1:3)
i1 <- is.na(df$var8)
df$z <- "Z"
df[i1, nm1] <- df[i1, c("var5", "z", "var7")]
df$imputed_flag <- c("N", "Y")[1 + i1]
df$z <- NULL

使用across2(来自dplyover(,我们可以进行

library(dplyover)
library(dplyr)
library(stringr)
df %>% 
mutate(z = 'Z',
across2(var1:var3, c(var5, z, var7),  
~ case_when(is.na(var8)~ .y, TRUE ~ .x), 
.names_fn = ~ str_remove(.x, "_.*")), 
imputed_flag = c("N", "Y")[1 + is.na(var8)])
var1 var2 var3 var4 var5 var6 var7 var8 z imputed_flag
1    I    Z    M    G    I    K    M <NA> Z            Y
2    B    D    F    H    J    L    N    P Z            N

最新更新