R中带mutate()和filter()的行逻辑运算

我经常需要在dataframes中使用mutate()select(),条件应用于变量的子集,但我不能始终如一地这样做。

玩具示例数据框:

data<-data.frame(id=c("John", "Jane", "Louis", "Mirian"),
                         a=c(FALSE, FALSE, TRUE, TRUE),
                         b=c(FALSE, NA, TRUE, NA), 
                         c=c(TRUE, FALSE, TRUE, TRUE),
                         num=1:4)

操作1:mutate(),对逻辑变量执行行操作:-我想创建一个新列"abc_any",当a:c中的任何一个值为真时,该列的值为真:

我通常使用:

data%>%mutate(abc_any=a|b|c)

      id     a     b     c num abc_any
1   John FALSE FALSE  TRUE   1    TRUE
2   Jane FALSE    NA FALSE   2      NA
3  Louis  TRUE  TRUE  TRUE   3    TRUE
4 Mirian  TRUE    NA  TRUE   4    TRUE

但我不能在链式“|”比较中不指定所有变量a:c。

我尝试了以下方法,结果不一致。不知道为什么:

data%>%mutate(abc_any=Reduce("|", a:c))

      id     a     b     c num abc_any
1   John FALSE FALSE  TRUE   1    TRUE
2   Jane FALSE    NA FALSE   2    TRUE
3  Louis  TRUE  TRUE  TRUE   3    TRUE
4 Mirian  TRUE    NA  TRUE   4    TRUE

这是可行的,但令人惊讶的是abc_any强制为数字:

data%>%rowwise()%>%mutate(abc_any=Reduce("|", a:c))

# A tibble: 4 x 6
# Rowwise: 
  id     a     b     c       num abc_any
  <fct>  <lgl> <lgl> <lgl> <int>   <int>
1 John   FALSE FALSE TRUE      1       1
2 Jane   FALSE NA    FALSE     2       0
3 Louis  TRUE  TRUE  TRUE      3       1
4 Mirian TRUE  NA    TRUE      4       1

这不起作用,并抛出几个错误消息:

data%>%rowwise()%>%mutate(abc_any=apply(a:c, 1, any))

操作#2:filter()-我有时想用类似的条件进行筛选,但不能:

data%>%filter(a|b|c)

works alright

此变体和几个变体(rowwise()%>%Reduce(...)及其他变体)失败,并显示各种错误消息:

data%>%filter(rowwise(Reduce("|", a:c)))

这个根本没有过滤,抛出“数值表达式有4个元素:只有第一个使用的”消息:

data%>%filter(Reduce("|", a:c))

我是否需要像上面那样使用mutate()创建一个新的“temp”列,然后使用filter?

对于二进制数字变量:-现在让我们假设这些逻辑变量被data_2<-data%>%mutate(across(where(is.logical), as.numeric))强制为数字:

我试图使用rowSums(),但也失败了:

data_2%>%rowwise()%>%mutate(abc_any=rowSums(a:c, na.rm = TRUE))

Error: Problem with `mutate()` input `abc_any`.
x 'x' must be an array of at least two dimensions
ℹ Input `abc_any` is `rowSums(a:c, na.rm = TRUE)`.
ℹ The error occured in row 1.

这些错误有哪些可能的解决方法?

✅ 最佳回答:

Reduce应该在list-selecta:c上,并在其上使用Reduce,因为data.frame/tibble也是list

library(dplyr)
data %>% 
     mutate(abc_any = Reduce("|", select(., a:c)))

或者我们需要filter

data %>% 
    filter(Reduce(`|`, select(., a:c)))

或者另一个选项是if_any

data %>%
   filter(if_any(a:c))
#      id     a     b    c num
#1   John FALSE FALSE TRUE   1
#2  Louis  TRUE  TRUE TRUE   3
#3 Mirian  TRUE    NA TRUE   4

或者从purrr使用reduce

library(purrr)
data %>%
      mutate(abc_any = select(., a:c) %>%
        reduce(`|`))

或者是带有rowSums的代码

data %>%
   mutate(across(where(is.logical), as.numeric)) %>%
   mutate(abc_any = rowSums(select(., a:c), na.rm = TRUE) > 0)