我希望在将一串过滤条件传递给data.table时提供一些帮助。我已经尝试了解析和评估的所有方式,似乎无法弄清楚
我尝试使用 iris 数据集重新创建一个示例:
iris <- data.table(iris)
vars <- 'setosa'
filter <- 'Species == vars & Petal.Length >= 4'
data <- iris[filter, list(
sep.len.tot = sum(Sepal.Length)
, sep.width.total = sum(Sepal.Width)
), by = 'Species']
因此过滤器字符串中包含 vars 变量(基于循环而变化)。我尝试根据过滤器字符串过滤数据。
是否有一个评估字符串的data.table特定方法?
希望有意义!
答案 0 :(得分:8)
我认为eval(parse(text()))
会起作用,你只需要做一些修改。试试这个:
library(data.table)
iris <- data.table(iris)
#Updated so it will have quotes in your string
vars <- '\"setosa\"'
#Update so you can change your vars
filter <- paste0('Species==',vars,'& Petal.Length >= 4')
res <- iris[eval(parse(text=filter)), list(
sep.len.tot = sum(Sepal.Length)
, sep.width.total = sum(Sepal.Width)
), by = 'Species']
一些注意事项:我更新了您的vars
,因此字符串中会有引号以便它正常运行,我还更新了filter
,以便您可以动态更改vars
。< / p>
最后,为了解释的目的,得到的df是空白的(因为没有setosa物种有Petal.Length&gt; = 4.所以为了看到这个工作,我们可以删除最后一个条件。
filter <- paste0('Species==',vars)
res2 <- iris[eval(parse(text=filter)), list(
sep.len.tot = sum(Sepal.Length)
, sep.width.total = sum(Sepal.Width)
), by = 'Species']
res2
Species sep.len.tot sep.width.total
1: setosa 250.3 171.4
修改强>: 根据Per @ Frank的评论,更简洁的方法是将整个事物写成表达式:
filter <- substitute(Species == vars, list(vars = "setosa"))
res <- iris[eval(filter), list(
sep.len.tot = sum(Sepal.Length)
, sep.width.total = sum(Sepal.Width)
), by = 'Species']
答案 1 :(得分:1)
我找到的最简单的方法:
treat_string_as_expr = rlang::parse_expr
grid = list(
params = list(
SMA_20 = c(20, 30, 50, 100),
SMA_40 = c(30, 40, 50, 100, 200),
slope = c(10, 20, 30),
cons_ubw = c(2, 3, 5),
cons_blw = c(2, 3, 5)
),
filter = "SMA_20 > SMA_40 & cons_ubw == cons_blw"
)
expand.grid(grid$params) %>%
dplyr::filter(!!treat_string_as_expr(grid$filter))
答案 2 :(得分:0)
您需要粘贴过滤器并添加引号,即filter <- paste0('Species==\'',vars,'\' & Petal.Length >= 4')
然后你可以使用
eval(parse(text=paste0('iris[',filter,',list(sep.len.tot = sum(Sepal.Length), sep.width.total = sum(Sepal.Width)), by = \'Species\']')))