我有一个与数据框中的列同名的变量:
df <- data.frame(a=c(1,2,3), b=c(4,5,6))
b <- 5
我想获取
df$b == b
所在的行,但 dplyr 将其解释为 df$b == df$b
:
df %>% filter(b == b) # interpreted as df$b == df$b
# a b
# 1 1 4
# 2 2 5
# 3 3 6
如果我更改变量名称,它就会起作用:
B <- 5
df %>% filter(b == B) # interpreted as df$b == B
# a b
# 1 2 5
我想知道是否有更好的方法来告诉
filter
b
指的是外部变量。
最近我发现这是解决这个问题的一个优雅的解决方案,尽管我刚刚开始了解它是如何工作的。
df %>% filter(b == !!b)
这是
的语法糖df %>% filter(b == UQ(b))
这种情况的高级意义是,
UQ
(取消引用)操作会导致其内容在过滤操作之前被评估,因此不会在 data.frame 内评估它。
这在 Advanced R 的章节中关于“准引用”进行了描述。本章还包括一些与非标准评估(NSE)相关的类似问题的解决方案。
您可以使用
get
函数从环境中获取变量的值。
df %>% filter(b == get("b")) # Note the "" around b
rlang
(与 dplyr
一起导入)具有 .env
和 .data
代词,适合这种情况(当您由于数据屏蔽而需要明确表示时)。要显式引用数据框中的列,请使用 .data
并显式引用您的环境,请使用 .env
:
library(dplyr)
df %>%
filter(.data$b == .env$b) # b == .env$b works the same here
a b
1 2 5
来自文档:
注意.data只是一个代词,它不是真正的数据框。这意味着您无法获取其名称或在 .data 的内容上映射函数。同样,.env 也不是实际的 R 环境。
您不一定需要在此处使用
.data$b
,因为评估会在数据框中搜索具有该名称 first 的列(正如您所发现的)。
作为通用解决方案,您可以使用
filter
的SE(标准评估)版本,即filter_
。在这种情况下,事情会变得有点混乱,因为您在单个表达式中混合了变量和“外部”常量。以下是使用 interp
函数执行此操作的方法:
library(lazyeval)
df %>% filter_(interp(~ b == x, x = b))
如果您想在
b
中使用更多值,您可以写:
df %>% filter_(interp(~ b == x, .values = list(x = b)))
对于那些对如何使用列作为变量感兴趣的人,我发现这个解决方案是最快且易于理解的:
df %>% filter(!!as.name(column_name) == !!b)