【问题标题】:Filter in dplyr if condition is met across ANY variable within a row如果在一行中的任何变量都满足条件,则在 dplyr 中过滤
【发布时间】:2021-02-11 00:36:56
【问题描述】:

获取以下小数据框。

df = tribble(
~col1,~col2,~col3,
1,2,3,
4,5,6,
7,8,9
)

我想过滤 ANY 值小于 5 的行。以下不起作用,但这是我最初的想法:

df %>%
filter(across(
    .fns = ~.<5
))

然而,输出是

1 , 2 , 3

而不是预期的输出

1 , 2 , 3,
4 , 5 , 6

虽然有不使用across() 和使用filter(col1 &lt; 5 | col2 &lt; 5 | col3 &lt; 5) 过滤的解决方案,但我想了解一种更通用的方法,可以用于all_of()everything() 的更大数据集。

要怎么做呢?

【问题讨论】:

  • 如果您希望一行中的任何值小于 5,为什么您的预期输出会有一行 4,5,6? 5 和 6 不符合您的标准,对吧?

标签: r filter dplyr


【解决方案1】:

1) 使用rowSums

df %>% filter(rowSums(. < 5) > 0)
## # A tibble: 2 x 3
##    col1  col2  col3
##   <dbl> <dbl> <dbl>
## 1     1     2     3
## 2     4     5     6

2)Reduce

df %>% filter(Reduce(`|`, as.data.frame(. < 5)))
## # A tibble: 2 x 3
##    col1  col2  col3
##   <dbl> <dbl> <dbl>
## 1     1     2     3
## 2     4     5     6

如果您只想考虑某些列,请将点替换为 select(., ...whatever...) 或使用普通下标。

3) 或使用c_across

df %>% rowwise %>% filter(any(c_across() < 5))
## # A tibble: 2 x 3
##    col1  col2  col3
##   <dbl> <dbl> <dbl>
## 1     1     2     3
## 2     4     5     6

【讨论】:

  • 谢谢!稍微扩展一下,假设单元格是字符/字符串,并且我们想要任何具有字符“5”的行,df %&gt;% rowwise %&gt;% filter(any(str_detect(c_across(),'5'))) 是要走的路吗?至少使用 str_detect 时,其他方法不起作用(不过,它们确实适用于简单的 ==。再次感谢您!
  • 使用非列表:df2 &lt;- data.frame(a = c("12", "34"), b = c("56", "78")) df2 %&gt;% rowwise %&gt;% filter(any(grepl("5", unlist(c_across()))))
  • 谢谢@g-grothendieck!欣赏它。
【解决方案2】:

之前我们可以使用filter_all

library(dplyr)
df %>% filter_all(any_vars(. < 5))

但是,由于filter_all 已被弃用,我们可以将Reduceacross 结合使用。

df %>% filter(Reduce(`|`, across(.fns = ~. < 5)))

#   col1  col2  col3
#  <dbl> <dbl> <dbl>
#1     1     2     3
#2     4     5     6

【讨论】:

  • 这太棒了!将在某个时候测试这些选项。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 2021-10-20
  • 1970-01-01
相关资源
最近更新 更多