我正在尝试基于数据帧中的其他列创建一个标志列。
示例:
df <- tribble(
~x1, ~x2, ~x3, ~x4,
1, 0, 1, 1,
0, 0, NA, NA,
1, 0, NA, 1,
0, 0, NA, NA,
0, 1, NA, 0
)
我想创建一个标志列,这样,如果值1出现在x1~x4的任何一列中,那么标志的值将为1,否则为0。
res <- df |> mutate(flag = ifelse(if_any(x1:x4, function(x) x == 1), 1, 0))
我尝试过将dplyr::if_any()
与ifelse()
一起使用,它似乎在大多数情况下都有效,但由于某种原因,在错误的情况下它会返回NA
。
> res
# A tibble: 5 × 5
x1 x2 x3 x4 flag
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 1 1 1
2 0 0 NA NA NA
3 1 0 NA 1 1
4 0 0 NA NA NA
5 0 1 NA 0 1
为什么会发生这种情况?有什么更好的解决方案?
edit:我试着看看if_any()
函数本身返回了什么,它似乎返回了NA
而不是false。
> res
# A tibble: 5 × 6
x1 x2 x3 x4 flag true_flase
<dbl> <dbl> <dbl> <dbl> <dbl> <lgl>
1 1 0 1 1 1 TRUE
2 0 0 NA NA NA NA
3 1 0 NA 1 1 TRUE
4 0 0 NA NA NA NA
5 0 1 NA 0 1 TRUE
perhttps://stackoverflow.com/a/44411169/10276092
您可以在%中使用%而不是==来忽略NA。
df %>% mutate(flag = ifelse(if_any(.cols=x1:x4, .fns= ~ . %in% 1), 1, 0))
这里有一种方法:
library(dplyr)
library(tidyr)
df %>%
rowwise %>%
mutate(flag = any(cur_data() == 1),
flag = replace_na(flag, 0))
x1 x2 x3 x4 flag
<dbl> <dbl> <dbl> <dbl> <lgl>
1 1 0 1 1 TRUE
2 0 0 NA NA FALSE
3 1 0 NA 1 TRUE
4 0 0 NA NA FALSE
5 0 1 NA 0 TRUE
或者将NA更改为0
df %>% mutate_each(funs(replace(., which(is.na(.)), 0))) %>% mutate(flag = ifelse(if_any(x1:x4, function(x) x == 1), 1, 0))
输出:
x1 x2 x3 x4 flag
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 1 1 1
2 0 0 0 0 0
3 1 0 0 1 1
4 0 0 0 0 0
5 0 1 0 0 1
使用rowSums
的另一个选项
df %>% mutate(flag = +(rowSums(., na.rm = TRUE) > 0))
#----
# A tibble: 5 x 5
x1 x2 x3 x4 flag
<dbl> <dbl> <dbl> <dbl> <int>
1 1 0 1 1 1
2 0 0 NA NA 0
3 1 0 NA 1 1
4 0 0 NA NA 0
5 0 1 NA 0 1
从R手册页面
注意:
不要使用'==='和'!='对于测试,例如在"if"表达式中,其中必须获得单个"TRUE"或"FALSE"。除非你绝对确定不会发生任何异常,您应该使用"完全相同"函数。
遵循的建议
library(dplyr)
df %>%
rowwise() %>%
mutate(flag = if_any(starts_with("x"), ~ identical(.x, 1)) * 1 )
# A tibble: 5 × 5
# Rowwise:
x1 x2 x3 x4 flag
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 1 1 1
2 0 0 NA NA 0
3 1 0 NA 1 1
4 0 0 NA NA 0
5 0 1 NA 0 1