如何评估字符串以过滤R data.table?

时间:2016-06-15 16:32:46

标签: r data.table

我希望在将一串过滤条件传递给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特定方法?

希望有意义!

3 个答案:

答案 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\']')))