【问题标题】:How to use a variable in dplyr::filter?如何在 dplyr::filter 中使用变量?
【发布时间】:2016-03-17 03:39:19
【问题描述】:

我有一个与数据框中的列同名的变量:

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 指的是外部变量。

【问题讨论】:

  • 这可能会帮助您 file:///Library/Frameworks/R.framework/Versions/3.2/Resources/library/dplyr/doc/nse.html
  • @MLavoie 这是什么?最好提供this link。
  • @Pascal。前几天有类似的问题,我不记得它在哪里。但看起来环境在这里很重要,这个链接解释了如何在类似的上下文中使用 dplyr 的动词。但我可能不明白这个问题,所以如果是这样,请忽略我的评论:)
  • @MLavoie 你误解了我的评论。您提供了本地文件的路径,该路径仅适用于 OSX 用户,不适用于 Linux 和 Windows 用户。我只是为同一个文件提供了 Internet 版本。
  • 在控制台中输入 vignette("nse") 是另一种选择

标签: r dplyr


【解决方案1】:

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,因为评估会在数据框中搜索具有该名称的列首先(正如您所发现的那样)。

【讨论】:

    【解决方案2】:

    最近我发现这是解决这个问题的一个优雅的解决方案,虽然我才刚刚开始思考它是如何工作的。

    df %&gt;% filter(b == !!b)

    这是语法糖

    df %&gt;% filter(b == UQ(b))

    对此的高级意义是UQ(取消引用)操作导致其内容在过滤操作之前被评估,因此它不会在data.frame中评估。

    这在chapter of Advanced R 的“准报价”中有所描述。本章还包括一些与非标准评估 (NSE) 相关的类似问题的解决方案。

    【讨论】:

    • 我对你的警告感到困惑:我现在得到与b == !!b 和!!b == b 相同的结果,而后者与!!(b == b) 不同。也许不同的版本(我有 dplyr 1 和 rlang 0.4.7)?你可否确认?谢谢!
    • 这是一个很好的观点,谢谢。这种行为在 rlang 的更高版本中发生了变化。我会相应地编辑我的答案。
    【解决方案3】:

    您可以使用get 函数从环境中获取变量的值。

    df %>% filter(b == get("b")) # Note the "" around b
    

    【讨论】:

    • 这不再适用于dplyr 0.7.8。它返回所有行。
    • 使用df %&gt;% filter(b == get("b", envir = .env)) 指定环境仍然有效(dplyr 0.8.3)
    【解决方案4】:

    作为通用解决方案,您可以使用filter 的SE(标准评估)版本,即filter_。在这种情况下,事情会变得有点混乱,因为您在单个表达式中混合了一个变量和一个“外部”常量。以下是使用 interp 函数的方法:

    library(lazyeval)
    df %>% filter_(interp(~ b == x, x = b))
    

    如果您想在b 中使用更多值,您可以这样写:

    df %>% filter_(interp(~ b == x, .values = list(x = b)))
    

    【讨论】:

    • filter_ 现已弃用。
    猜你喜欢
    • 2019-09-13
    • 1970-01-01
    • 2018-07-14
    • 2015-09-30
    • 2017-12-26
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多