我正在使用
arrow
包与 R 中的大型 (30GB) parquet 文件数据集进行交互。当我有一个明确的查询时,这非常有用,但当我尝试动态构建查询时,我不确定最佳实践因为我拥有的最佳解决方案需要使用eval(parse(text=))
,所以我正在寻找更好的解决方案。
作为示例,我有下面的简单数据集:
library(arrow)
artab <- arrow_table(int=1:1000, value=runif(1000))
我想检索值在 0.4 到 0.6 之间的所有行,这使用
dplyr
语法实现起来很简单:
library(dplyr)
library(data.table) # for %between% operator syntax
artab %>%
filter(value%between%c(0.4, 0.6)) %>%
collect()
当我有多个“窗口”时,我想使用
|
OR 运算符提取数据:
artab %>%
filter(value%between%c(0.4, 0.6) | value%between%c(0.8, 1.0)) %>%
collect()
但是,如果我有一长串窗口并且想要以编程方式生成此查询,我能想到的唯一选择是将整个管道链构建为字符向量,然后将其传递给
eval(parse(text=))
:
window_req_string <- data.frame(
lower_bound=c(0.1, 0.4, 0.8),
upper_bound=c(0.2, 0.6, 1.0)
) %>%
summarise(req_cmd=paste0("value%between%c(", lower_bound, ", ", upper_bound,
")", collapse="|")) %>%
pull(req_cmd)
full_arrow_req <- paste0(
'artab %>% filter(', window_req_string, ') %>% dplyr::collect()'
)
arrow_output <- eval(parse(text=full_arrow_req))
有更好的方法吗? 用户定义函数在这里似乎不是一个好的选择,因为该函数已经存在(
filter
),我只需要一个矢量化版本。我特别想要一种更好的方法来做到这一点,因为我传递的管道链也可能会变得很长(过滤附加列并运行计算)。
我想知道摆弄
R6
对象本身来强制插入查询(例如,编写减去此特定过滤步骤的查询,然后编辑 R6 对象以将其“添加”到步骤列表中)是否是一个好主意,但我我对 R6 不太熟悉,这看起来很老套。
除了将其写为字符串并使用
arrow
之外,有没有办法在 R 中动态构造 eval(paste())
查询?
摆弄 R6 对象感觉不是正确的路径,因为大多数这些查询内部都是基于通过 tidy eval 获取和评估表达式。我可能会做这样的事情:
library(arrow)
library(dplyr)
library(purrr)
library(rlang)
tbl <- tibble::tibble(x = 1:10)
ranges <- list(c(1, 3), c(5,6), c(9, 10))
calls <- map(ranges, ~call2("between", as.name("x"), .x[[1]], .x[[2]]) )
filter_string <- paste(calls, collapse = "|")
# works in dplyr
tbl |>
filter(!! rlang::parse_expr(filter_string))
#> # A tibble: 7 × 1
#> x
#> <int>
#> 1 1
#> 2 2
#> 3 3
#> 4 5
#> 5 6
#> 6 9
#> 7 10
# works in arrow too!
output <- arrow_table(tbl) |>
filter(!! rlang::parse_expr(filter_string))
output
#> Table (query)
#> x: int32
#>
#> * Filter: ((((x >= 1) and (x <= 3)) or ((x >= 5) and (x <= 6))) or ((x >= 9) and (x <= 10)))
#> See $.data for the source Arrow object
collect(output)
#> # A tibble: 7 × 1
#> x
#> <int>
#> 1 1
#> 2 2
#> 3 3
#> 4 5
#> 5 6
#> 6 9
#> 7 10
诚然,我们仍然处于构建和评估字符串的领域,但它可能更干净一点?