r - 将 filter_all(any_vars()) 转换为 filter(across())

标签 r dplyr

关于更新 my own answer to another thread ,我无法想出一个好的解决方案来替换最后一个示例(见下文)。这个想法是获取任何列包含某个字符串的所有行,在我的示例“V”中。

library(tidyverse)

#get all rows where any column contains 'V'
diamonds %>%
  filter_all(any_vars(grepl('V',.))) %>%
  head
#> # A tibble: 6 x 10
#>   carat cut       color clarity depth table price     x     y     z
#>   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31
#> 2 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
#> 3 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
#> 4 0.24  Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
#> 5 0.26  Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
#> 6 0.22  Fair      E     VS2      65.1    61   337  3.87  3.78  2.49


# this does naturally not give the desired output! 
diamonds %>%
  filter(across(everything(), ~ grepl('V', .))) %>%
  head
#> # A tibble: 0 x 10

我发现了一个线程,其中 poster ponders over similar stuff ,但在 grepl 上应用类似的逻辑不起作用。
### don't run, this is ugly and does not work
diamonds %>%
  rowwise %>%
  filter(any(grepl("V", across(everything())))) %>%
  head

最佳答案

这是非常困难的,因为该示例表明您希望在所有列中的任何列满足条件时过滤所有列中的数据(即您想要联合)。这是通过 filter_all() 完成的和 any_vars() .
虽然 filter(across(everything(), ...))当所有列都满足条件时从所有列中过滤掉(即这是一个交集,与之前的完全相反)。
要将其从交集转换为并集(即再次获取任何列满足条件的行),您可能需要检查行总和:

diamonds %>%
   filter(rowSums(across(everything(), ~grepl("V", .x))) > 0)
它将总结所有 TRUE s 出现在行中,即如果至少有一个值满足条件,则该行总和将为 > 0并将显示。
对不起 across()不是filter()的第一个 child ,但至少有一些想法如何做到这一点。 :-)

评价:
使用@TimTeaFan 的方法来检查:
 identical(
     {diamonds %>%
         filter_all(any_vars(grepl('V',.)))
     }, 
     {diamonds %>%
         filter(rowSums(across(everything(), ~grepl("V", .x))) > 0)
     }
 )
 #> [1] TRUE
基准:
根据我们在 TimTeaFan 的回答下的讨论,这是一个比较,令人惊讶的是,所有解决方案都有相似的时间:
library(tidyverse)
microbenchmark::microbenchmark(
  filter_all = {diamonds %>%
      filter_all(any_vars(grepl('V',.)))}, 
  purrr_reduce = {diamonds %>%
      filter(across(everything(), ~ grepl('V', .)) %>% purrr::reduce(`|`))},
  base_reduce = {diamonds %>%
      filter(across(everything(), ~ grepl('V', .)) %>% Reduce(`|`, .))},
  rowsums = {diamonds %>%
      filter(rowSums(across(everything(), ~grepl("V", .x))) > 0)},
  times = 100L,
  check = "identical"
)
#> Unit: milliseconds
#>          expr      min       lq     mean   median       uq      max neval
#>    filter_all 295.7235 302.1311 309.6455 305.0491 310.0335 449.3619   100
#>  purrr_reduce 297.8220 302.4411 310.2829 306.2929 312.2278 461.0194   100
#>   base_reduce 298.5033 303.6170 309.4147 306.1839 312.3518 409.5273   100
#>       rowsums 295.3863 301.0281 307.8517 305.3142 309.4793 372.8867   100
创建于 2020-07-14 由 reprex package (v0.3.0)

关于r - 将 filter_all(any_vars()) 转换为 filter(across()),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62885164/

相关文章:

r - 堆积条形图 : what if each subcategory (fill) is unique?

在 R 中使用 for 循环记录分层数据

r - 使用数据类型名称列表更改数据类型

r - 在 R 中使用子集时如何忽略大小写

R 从 .CSV 创建 NetCDF

R pch 在 Illustrator 中绘制为 "q"

r - 使用 dplyr/plyr 计算跨行的百分比?

r - ggplot2 Boxplot 显示与计算不同的中位数

R dplyr,将 mutate 与 na.omit 一起使用会导致错误大小不兼容 (%d)

r - 模糊与精确匹配相结合