【问题标题】:Rowwise logical operations with mutate() and filter() in R在 R 中使用 mutate() 和 filter() 进行逐行逻辑运算
【发布时间】:2023-04-10 13:00:01
【问题描述】:

我经常需要在数据框中使用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 中的任何一个为 TRUE 时,其值为 TRUE:

我通常使用:

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)

没问题

这个和几个变体(rowwise()%&gt;%Reduce(...) 和其他)失败并显示各种错误消息:

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

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

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

我是否应该像上面那样使用 mutate() 创建一个新的“temp”列,然后进行过滤?

使用二进制数值变量:
- 现在假设这些逻辑变量被强制转换为数字,data_2&lt;-data%&gt;%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.

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

【问题讨论】:

    标签: r select filter dplyr rowwise


    【解决方案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
    

    或使用reduce 来自purrr

    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)
    

    【讨论】:

    • 我看到你的解决方案中实际上不需要 rowwise(),@akrun。比为什么这个data%&gt;%rowwise()%&gt;%mutate(abc_any=Reduce("|", a:c)) 起作用,但是没有 rowwise() 的类似尝试不起作用?它与函数的矢量化有什么关系吗?
    • @GuedesBF 使用Reduceif_any/if_all,它对每一行进行比较。除了rowwisec_across 效率会更低
    • @GuedesBF 你的rowwise 有效,但这里真的不需要。它不必要地按行分组,因为即使没有 Reduce 也适用于每一行
    猜你喜欢
    • 1970-01-01
    • 2021-12-23
    • 2015-12-28
    • 1970-01-01
    • 2012-06-30
    • 2014-10-18
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    相关资源
    最近更新 更多