dplyr 中基于字符串的过滤 - NSE
String based filtering in dplyr - NSE
我想使用 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
如果我也想动态更改过滤运算符怎么办(假设我有一个闪亮的应用程序,用户可以在其中动态 selectInput
如果过滤值大于 5 的数据,等于5 或低于 5?
我想做的是:
op = ">="
val = 5
filt_expr = paste("x", op, val)
df %>%
filter(filt_expr)
显然,这是行不通的,我已经使用 rlang
quosore/symbols 等进行了一些尝试,但没有找到 "quote" 我的输入的正确方法。
问题二
额外的问题是,如果我想应用多个过滤器怎么办?我需要循环还是可以创建一个过滤表达式列表并一次性应用它们?
一个例子是一个闪亮的应用程序,用户可以在其中键入多个条件 he/she 想要应用到数据,以便我们有一个动态变化的格式列表:
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)
但很高兴看到是否有更好更清洁的方法
What if I want to dynamically change the operator of the filtering too
您可以通过取消引用代表运算符的符号来使用 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)
what if I want to apply multiple filters?
您将表达式保存在一个列表中,然后在 !!!
:
的调用中拼接它们
filters <- list(
quote(x >= 5),
quote(y <= 10),
quote(z >= 2)
)
expr(df %>% filter(!!!filters))
#> df %>% filter(x >= 5, y <= 10, z >= 2)`
注意:我在上面说过,没有必要从上下文中取消对变量的引用,但是如果您正在编写函数,这样做通常仍然是个好主意以数据框作为输入。由于数据框是可变的,您事先不知道它包含哪些列。这些列将始终优先于您在环境中定义的对象。在这里的例子中,这不是问题,因为我们正在谈论一个函数,如果 R 在数据框中找到一个类似命名的对象,它将继续寻找一个函数。
你实际上可以这样做:
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)))
我想使用 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
如果我也想动态更改过滤运算符怎么办(假设我有一个闪亮的应用程序,用户可以在其中动态 selectInput
如果过滤值大于 5 的数据,等于5 或低于 5?
我想做的是:
op = ">="
val = 5
filt_expr = paste("x", op, val)
df %>%
filter(filt_expr)
显然,这是行不通的,我已经使用 rlang
quosore/symbols 等进行了一些尝试,但没有找到 "quote" 我的输入的正确方法。
问题二
额外的问题是,如果我想应用多个过滤器怎么办?我需要循环还是可以创建一个过滤表达式列表并一次性应用它们?
一个例子是一个闪亮的应用程序,用户可以在其中键入多个条件 he/she 想要应用到数据,以便我们有一个动态变化的格式列表:
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)
但很高兴看到是否有更好更清洁的方法
What if I want to dynamically change the operator of the filtering too
您可以通过取消引用代表运算符的符号来使用 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)
what if I want to apply multiple filters?
您将表达式保存在一个列表中,然后在 !!!
:
filters <- list(
quote(x >= 5),
quote(y <= 10),
quote(z >= 2)
)
expr(df %>% filter(!!!filters))
#> df %>% filter(x >= 5, y <= 10, z >= 2)`
注意:我在上面说过,没有必要从上下文中取消对变量的引用,但是如果您正在编写函数,这样做通常仍然是个好主意以数据框作为输入。由于数据框是可变的,您事先不知道它包含哪些列。这些列将始终优先于您在环境中定义的对象。在这里的例子中,这不是问题,因为我们正在谈论一个函数,如果 R 在数据框中找到一个类似命名的对象,它将继续寻找一个函数。
你实际上可以这样做:
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)))