Я пытаюсь применить последовательные фильтры к кадру данных, не зная заранее количества фильтров или их аргументов. Аргументы хранятся в списке. С 1 или 2 фильтрами я могу сделать это с purrrм.
Например, с двумя фильтрами:
require(tidyverse)
data("iris")
head(iris)
f2 <- list("Species" = "virginica", "Sepal.Length" = c(5.8, 6.3))
iris_f2 <- map2_df(.x = f2[[1]],
.y = f2[[2]],
.f = ~{
iris %>%
filter(get(names(f2)[1]) %in% .x,
get(names(f2)[2]) %in% .y)
})
# With 3 filters or more, I am completely stuck !
f3 <- list("Species" = "virginica", "Sepal.Length" = c(5.8, 6.3), "Sepal.Width" = 2.7)
Я хотел бы обобщить свой код, чтобы он применял последовательные фильтры с n аргументами в списке (n может быть 1 или 2, как в моем примере, или больше).
В идеале я хотел бы знать, как это сделать с помощью муррр, но меня также интересуют решения на основе циклов.
Вот один из способов, который использует call()
для построения обезвреженных выражений, которые можно вставить внутрь filter()
.
library(purrr)
library(dplyr)
fns <- imap(f3, ~ call(if (length(.x) == 1) "= = " else "%in%", sym(.y), .x))
Что дает следующее:
$Species
Species == "virginica"
$Sepal.Length
Sepal.Length %in% c(5.8, 6.3)
$Sepal.Width
Sepal.Width == 2.7
Однако имена вызывают проблемы при объединении, поэтому перед использованием их необходимо отменить:
iris %>%
filter(!!!unname(fns))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.8 2.7 5.1 1.9 virginica
2 6.3 2.7 4.9 1.8 virginica
3 5.8 2.7 5.1 1.9 virginica
Почему бы просто не сделать
filter(iris, Species == 'virginica' & Sepal.Length %in% c(5.8, 6.6))
?