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

tes*_*123 15 r special-characters dplyr

编辑:%.%运算符现已弃用.使用magrittr中的%>%.

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

它似乎将命令链接在一起,但据我所知......当我在它时,任何人都可以解释那些挂在%标志上的特殊操作员的开局是什么以及何时在技术上是时候到了用它们代码更好?

Car*_*lli 19

我想哈德利会是向你解释的最好的人,但我会试一试.

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

是什么目的%.%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
)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

写入和读取都更容易!

这是如何工作的?

我们来看看定义.首先%.%:

function (x, y) 
{
    chain_q(list(substitute(x), substitute(y)), env = parent.frame())
}
Run Code Online (Sandbox Code Playgroud)

它使用另一个叫做的函数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`
}
Run Code Online (Sandbox Code Playgroud)

那是做什么的?

为了简化,我们假设你打电话:group_by(hflights,Year, Month, DayofMonth) %.% select(Year:DayofMonth, ArrDelay, DepDelay).

你的电话x,y然后是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) - 所以它"链接"循环内的调用.

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