15

编辑: %.% 运算符现在已弃用。使用 %>% 来自 magrittr。

原始问题这个%.%操作员做什么?我已经看到它与 dplyr 包一起使用了很多,但似乎找不到任何关于它是什么或它是如何工作的支持文档。

它似乎将命令链接在一起,但据我所知……当我在做的时候,任何人都可以解释那些挂在%标志上的特殊操作员的策略是做什么的,什么时候在技术上是正确的时间使用它们更好地编码?

4

2 回答 2

19

我认为哈德利是向你解释的最佳人选,但我会试一试。

%.%是一种称为链运算符的二元运算符。在R您几乎可以使用特殊字符定义您自己的任何二元运算%符。从我看来,我们几乎使用它来制作更简单的“可链接”语法(例如x+y,比 更好sum(x,y))。你可以用它们做一些很酷的事情,在这里看到这个很酷的例子。

%.%in的目的是dplyr什么?让你更容易表达自己,缩小你想做的事和表达方式之间的差距。

以dplyr 简介中的示例为例,假设您想按年、月和日对航班进行分组,选择这些变量加上到达和离开的延误,按平均值总结这些,然后只过滤超过 30 次的延误。如果有不是%.%,你必须这样写:

filter(
  summarise(
    select(
      group_by(hflights, Year, Month, DayofMonth),
      Year:DayofMonth, ArrDelay, DepDelay
    ),
    arr = mean(ArrDelay, na.rm = TRUE),
    dep = mean(DepDelay, na.rm = TRUE)
  ),
  arr > 30 | dep > 30
)

它完成了这项工作。但是表达自己和阅读它是相当困难的。现在,您可以使用链运算符以更友好的语法编写相同的内容%.%

hflights %.%
  group_by(Year, Month, DayofMonth) %.%
  select(Year:DayofMonth, ArrDelay, DepDelay) %.%
  summarise(
    arr = mean(ArrDelay, na.rm = TRUE),
    dep = mean(DepDelay, na.rm = TRUE)
  ) %.%
  filter(arr > 30 | dep > 30)

写和读都更容易!

那是如何工作的?

让我们看一下定义。首先是%.%

function (x, y) 
{
    chain_q(list(substitute(x), substitute(y)), env = parent.frame())
}

它使用另一个名为chain_q. 所以让我们看一下:

function (calls, env = parent.frame()) 
{
    if (length(calls) == 0) 
        return()
    if (length(calls) == 1) 
        return(eval(calls[[1]], env))
    e <- new.env(parent = env)
    e$`__prev` <- eval(calls[[1]], env)
    for (call in calls[-1]) {
        new_call <- as.call(c(call[[1]], quote(`__prev`), as.list(call[-1])))
        e$`__prev` <- eval(new_call, e)
    }
    e$`__prev`
}

那有什么作用?

为简化起见,假设您调用了:group_by(hflights,Year, Month, DayofMonth) %.% select(Year:DayofMonth, ArrDelay, DepDelay).

你的电话xy然后都是group_by(hflights,Year, Month, DayofMonth)select(Year:DayofMonth, ArrDelay, DepDelay)。因此,该函数创建了一个名为e( e <- new.env(parent = env)) 的新环境,并保存了一个__prev使用第一次调用 ( ) 的评估调用的对象e$'__prev' <- eval(calls[[1]], env)。然后对于彼此的调用,它会创建另一个调用,其第一个参数是前一次调用 - 也就是说__prev- 在我们的例子中它将是select('__prev', Year:DayofMonth, ArrDelay, DepDelay)- 所以它“链接”循环内的调用。

由于您可以一个接一个地使用二元运算符,因此您实际上可以使用这种语法以一种非常易读的方式表达非常复杂的操作。

于 2014-03-11T02:21:59.820 回答
2

快速搜索让我来到这里

dplyr提供了另一项创新plyr:将操作与操作员从左到右链接在一起的能力%.%。这使得dplyr行为有点像数据操作的语法。

例子:

Batting %.%
  group_by(playerID) %.%
  summarise(total = sum(G)) %.%
  arrange(desc(total)) %.%
  head(5)`

从帮助部分了解更多信息,?"%.%"。

于 2014-03-11T01:35:45.573 回答