6

我想使用dplyr新的 NSE 符号(版本 >= 0.6)来动态filter处理我的数据。假设我有以下虚拟数据集:

df = data_frame(x = 1:10, y = 10:1, z = 10 * runif(10))

如果现在我想过滤tofilter = "x"大于 5 的值的列,我知道我可以这样做:

df %>% 
  filter((!!rlang::sym(tofilter)) >= 5)

问题 1

如果我也想动态更改过滤运算符怎么办(假设我有一个 Shiny App,用户可以在其中动态selectInput过滤大于 5、等于 5 或​​小于 5 的值的数据?

我想做的是:

op = ">="
val = 5
filt_expr = paste("x", op, val)
df %>% 
  filter(filt_expr)

显然,这是行不通的,我已经玩了一些rlangquosore/symbols 等,但没有找到正确的方法来“引用”我的输入。

问题2

额外的问题是,如果我想应用多个过滤器怎么办?我是否需要循环,或者我可以创建一个过滤表达式列表并一次性应用它们?

一个例子是一个闪亮的应用程序,用户可以键入他/她想要应用于数据的多个条件,以便我们有一个动态变化的格式列表:

filt_expr_list = list("x >= 5", "y <= 10", "z >= 2")

我们想动态地应用它们,这样输出就相当于:

df %>%
  filter(x >= 5, y <= 10, z >= 2)

我想这在某种意义上是问题 1 的一个子集,因为当我知道如何正确引用论点时,我认为我可以这样做:

filt_expr = paste0(unlist(filt_expr_list), collapse = ", ")
df %>%
  filter(filt_expr)

但很高兴看看是否有更好的清洁方式

4

2 回答 2

9

如果我也想动态更改过滤的运算符怎么办

您可以通过取消引用代表运算符的符号来使用 tidy eval 来完成此操作(请注意,我expr()用来说明取消引用的结果):

lhs <- "foo"

# Storing the symbol `<` in `op`
op <- quote(`<`)

expr(`!!`(op)(!!sym(lhs), 5))
#> foo < 5

但是,使用常规 R 代码在 tidy eval 之外执行此操作更清洁。仅当您取消引用的符号代表数据框中的列时,才需要取消引用,即不在上下文中的内容。在这里,您可以将运算符存储在变量中,然后在过滤表达式中调用该变量:

# Storing the function `<` in `op`
op <- `<`

expr(op(!!sym(lhs), 5))
#> op(foo, 5)

如果我想应用多个过滤器怎么办?

您将表达式保存在列表中,然后将它们拼接到调用中!!!

filters <- list(
  quote(x >= 5),
  quote(y <= 10),
  quote(z >= 2)
)

expr(df %>% filter(!!!filters))
#> df %>% filter(x >= 5, y <= 10, z >= 2)`

注意:我在上面说过,没有必要从上下文中取消引用变量,但如果您正在编写一个以数据框作为输入的函数,这样做通常仍然是一个好主意。由于数据框是可变的,因此您事先不知道它包含哪些列。这些列将始终优先于您在环境中定义的对象。在这种情况下,这不是问题,因为我们正在讨论一个函数,如果 R 在数据框中找到一个类似命名的对象,它将继续寻找一个函数。

于 2017-09-11T11:58:13.383 回答
0

您实际上可以这样做:

    df = data_frame(x = 1:10, y = 10:1, z = 10 * runif(10))
    op = ">="
    val = 5
    filt_expr = paste("x", op, val)

    df %>% filter(eval(parse(filt_expr)))
于 2019-03-11T14:52:27.640 回答