我有一个这样的数据帧:
df <- data.frame(
Metric = c('WI', NA, 'MN', NA, 'CO', NA),
Eval = c('WI', NA, 'AK', NA, 'CO', NA),
colA = c(30, 'ABC', 45, 'DEF', 2, 'XYZ'),
colB = c(25, 'BEC', 23, 'FED', 50, 'HIJ')
)
我想评估Metric
列和Eval
列是否相等,如果相等,用NA填充Metric
列右侧的所有内容,结果如下:
df_desired <- data.frame(
Metric = c('WI', NA, 'MN', NA, 'CO', NA),
Eval = c(NA, NA, 'AK', NA, NA, NA),
colA = c(NA, 'ABC', 45, 'DEF', NA, 'XYZ'),
colB = c(NA, 'BEC', 23, 'FED', NA, 'HIJ')
)
使用R,最好是使用tidyverse
函数,最好的方法是什么?我试着使用mutate
/across
,但在这里定义条件让我很失望
创建一个逻辑向量,并根据行/列索引/名称进行赋值(base R
更直接(
i1 <- with(df, Metric == Eval & !is.na(Metric) & !is.na(Eval))
df[i1, -1] <- NA
-输出
> df
Metric Eval colA colB
1 WI <NA> <NA> <NA>
2 <NA> <NA> ABC BEC
3 MN AK 45 23
4 <NA> <NA> DEF FED
5 CO <NA> <NA> <NA>
6 <NA> <NA> XYZ HIJ
或者使用dplyr
,创建一列逻辑向量('i1'(,将across
列的'Eval'循环为'colB',使用case_when/ifelse/if_else/replace
根据'i1'将值更改为NA
,并通过分配给NULL
来移除临时列
library(dplyr)
df %>%
mutate(i1 = Metric == Eval,
across(Eval:colB, ~ case_when(i1 ~ NA_character_, TRUE ~ .)),
i1 = NULL)
-输出
Metric Eval colA colB
1 WI <NA> <NA> <NA>
2 <NA> <NA> ABC BEC
3 MN AK 45 23
4 <NA> <NA> DEF FED
5 CO <NA> <NA> <NA>
6 <NA> <NA> XYZ HIJ
使用mutate()
和if_else()
有条件地替换值:
df |>
mutate(colA = if_else(Metric == Eval, NA_character_, colA, missing = colA))
#> Metric Eval colA colB
#> 1 WI WI <NA> 25
#> 2 <NA> <NA> ABC BEC
#> 3 MN AK 45 23
#> 4 <NA> <NA> DEF FED
#> 5 CO CO <NA> 50
#> 6 <NA> <NA> XYZ HIJ
注意,我们不能只使用NA
,我们必须将它与现有的列类型相匹配。在您的示例中,colA
和colB
是字符向量,因此它是NA_character_
。我们必须指定missing
来处理NA == NA
的情况。
要在多个列中推广这一点,请使用across()
并将if_else()
包装在一个匿名函数中:
df |>
mutate(across(Eval:colB, ~if_else(Metric == Eval, NA_character_, ., missing = .)))
#> Metric Eval colA colB
#> 1 WI <NA> <NA> <NA>
#> 2 <NA> <NA> ABC BEC
#> 3 MN AK 45 23
#> 4 <NA> <NA> DEF FED
#> 5 CO <NA> <NA> <NA>
#> 6 <NA> <NA> XYZ HIJ