如何在R中使用%。%运算符(EDIT:2014年弃用运算符)

时间:2014-03-11 01:27:10

标签: r special-characters dplyr

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

原始问题 这个%.%运算符做了什么? 我已经看到它在dplyr软件包中使用了很多,但似乎找不到任何支持文档,说明它是什么或它是如何工作的。

它似乎将命令链接在一起,但据我所知......当我在它时,任何人都可以解释那些与%符号挂钩的特殊操作符的开局什么时候在技术上是时候使用它们更好地编码?

2 个答案:

答案 0 :(得分:19)

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

%.%是一个名为chain operator的二元运算符。在R中,您可以使用特殊字符%define any binary operator of your own。从我看来,我们几乎用它来制作更容易的“可链接”语法(比如x+y,比sum(x,y)好得多)。你可以用它们做很酷的事情,see this cool example here.

%.%dplyr的目的是什么?为了让您更容易表达自己,减少您想要做的事情和表达方式之间的差距。

introduction to 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)。因此,该函数创建一个名为ee <- new.env(parent = env))的新环境,并保存一个名为__prev的对象,并评估第一个调用(e$'__prev' <- eval(calls[[1]], env)。然后为彼此调用它创建另一个调用,其第一个参数是前一个调用 - 即__prev - 在我们的例子中它将是select('__prev', Year:DayofMonth, ArrDelay, DepDelay) - 所以它“链接”循环内的调用。

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

答案 1 :(得分:2)

快速搜索让我here

  

dplyr提供了与plyr相比的另一项创新:使用%.%运算符从左到右连接操作的能力。这使得dplyr的行为有点像数据操作的语法。

示例:

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

从帮助部分了解更多相关信息,?“%。%”。