r - dplyr 以编程方式过滤多个逻辑列的最佳实践
问题描述
要解决的问题
我需要两个函数来根据可能包含缺失值的列指示符(即逻辑)在小标题上实现和/或过滤。函数的参数应该是要考虑的列的字符向量。
我的解决方案
filter_checked <- function(db, vars = NULL) {
db %>%
dplyr::filter(
dplyr::if_all(dplyr::all_of(vars), ~ !is.na(.x) & .x)
)
}
filter_or_checked <- function(db, vars = NULL) {
db %>%
dplyr::filter(
dplyr::if_any(dplyr::all_of(vars), ~ !is.na(.x) & .x)
)
}
要通过的示例测试
test_that("filter checks", {
foo <- tibble::tibble(
id = 1:5,
a = c(TRUE, TRUE, FALSE, FALSE, FALSE),
b = c(NA, TRUE, NA, TRUE, NA)
)
expect_equal(filter_checked(foo)[["id"]], 1:5)
expect_equal(filter_checked(foo, "a")[["id"]], 1:2)
expect_equal(filter_checked(foo, "b")[["id"]], c(2, 4))
expect_equal(filter_checked(foo, c("a", "b"))[["id"]], 2)
})
test_that("filter_or_checks", {
foo <- tibble::tibble(
id = 1:5,
a = c(TRUE, TRUE, FALSE, FALSE, FALSE),
b = c(NA, TRUE, NA, TRUE, NA)
)
expect_equal(filter_or_checked(foo)[["id"]], integer(0))
expect_equal(filter_or_checked(foo, "a")[["id"]], 1:2)
expect_equal(filter_or_checked(foo, "b")[["id"]], c(2, 4))
expect_equal(filter_or_checked(foo, c("a", "b"))[["id"]], c(1, 2, 4))
})
我的问题
在我看来,我的功能太复杂了。无论如何,我认为这是我缺乏知识。那么,是否有更好的(即更容易阅读/理解/教授)tidyverse 解决方案来解决问题?
解决方案
如果发现您的代码很有趣。
要回答,当您有许多布尔值(至少三个或更多)时,我有一个解决方案是将它们全部转换为一列,其中包含 0(FALSE)和 1(TRUE),例如对于五个布尔值,它看起来像:
00000
01000
11111
01001
11110
然后:
- 要知道所有布尔值是否为 TRUE,您可以计算每个单元格中有多少个“1”,并要求有与列号一样多的“1”
- 要知道至少一列是否为 TRUE,只需搜索字符串 '1'
就我而言,我没有考虑缺失值。但是你可以重新编码它们 2 例如。
最后,这涉及更多的数据准备和之后的不太复杂的功能(因为您不是在玩多个布尔值,而是只玩一个字符串)。
代码将类似于:
library(dplyr)
# Prepare data, from your data
foo <- tibble::tibble(
id = 1:5,
a = c(TRUE, TRUE, FALSE, FALSE, FALSE),
b = c(NA, TRUE, NA, TRUE, NA),
d_bis = c(TRUE, TRUE, FALSE, FALSE, FALSE),
e_bis = c(TRUE, TRUE, FALSE, FALSE, FALSE),
f_bis = c(TRUE, TRUE, FALSE, FALSE, FALSE)
) %>%
mutate(a_bis = a, b_bis = b) %>% # copy columns to test
mutate_at(vars(ends_with('_bis')), as.integer) %>% # convert logicals to integers
mutate_at(vars(ends_with('_bis')), tidyr::replace_na, replace = 2) %>% # replace NA with 2
mutate(af_bis = paste0(a_bis, b_bis, d_bis, e_bis, f_bis))
# A tibble: 5 x 9
id a b d_bis e_bis f_bis a_bis b_bis af_bis
<int> <lgl> <lgl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 1 TRUE NA 1 1 1 1 2 12111
2 2 TRUE TRUE 1 1 1 1 1 11111
3 3 FALSE NA 0 0 0 0 2 02000
4 4 FALSE TRUE 0 0 0 0 1 01000
5 5 FALSE NA 0 0 0 0 2 02000
# list rows where at least one is TRUE
foo %>%
filter(grepl('1', af_bis))
# list rows where all columns are TRUE
foo %>%
filter(stringr::str_count(af_bis, '1') == 5L)
# list where at least one column is TRUE only if all columns are not missing
foo %>%
filter(grepl('1', af_bis) & ! grepl('2', af_bis))
推荐阅读
- javascript - 有没有更好的方法来更改 javascript/Vue 中的按钮显示?
- php - Laravel 响应返回空,但是当我在 db 中打印并运行查询时,它可以工作
- php - 如何将数据从主数组传递到 PHP 中的多个数组
- c - c中的char数组不适用于Visual Studio 2015
- elasticsearch - 无法在 Elasticsearch 中创建集群
- android - 是否可以在物理地板上检索物理(设备)相机高度?
- jsp - “预期语句或表达式结束”的例外
- r - 来自 R 中 quantmod 的 getSymbols() 不起作用
- r - 为什么 R HTTR 内容语句没有产生预期的请求正文?
- git - 远程服务器的 Git 客户端