我有一个示例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