将中间输出分配给临时变量作为dplyr管道的一部分

时间:2016-11-01 22:51:32

标签: r dplyr pipeline

问:在R dplyr管道中,如何将一些中间输出分配给临时变量以便在管道中进一步使用?

我的方法可行。但它分配到全局框架中,这是不可取的。必须有更好的方法,对吗?我认为我的方法涉及评论线将得到预期的结果。没有骰子。困惑为什么不起作用。

df <- data.frame(a = LETTERS[1:3], b=1:3)
df %>%
  filter(b < 3) %>%
  assign("tmp", ., envir = .GlobalEnv) %>% # works
  #assign("tmp", .) %>% # doesn't work
  mutate(b = b*2) %>%
  bind_rows(tmp)
  a b
1 A 2
2 B 4
3 A 1
4 B 2

5 个答案:

答案 0 :(得分:13)

在全球环境中创建一个对象:

df %>% 
   filter(b < 3) %>% 
   { 
     { . -> tmp } %>% 
     mutate(b = b*2) %>% 
     bind_rows(tmp) 
   }

如果您使用. ->> tmp代替. -> tmp或将其插入管道,也可以用于调试:

{ browser(); . } %>% 

答案 1 :(得分:9)

pipeR是一个扩展管道功能而不添加不同管道的软件包(如magrittr所做)。要进行分配,请将括号中带有~的变量名称作为管道中的元素传递:

library(dplyr)
library(pipeR)

df %>>%
  filter(b < 3) %>>%
  (~tmp) %>>% 
  mutate(b = b*2) %>>%
  bind_rows(tmp)
##   a b
## 1 A 2
## 2 B 4
## 3 A 1
## 4 B 2

tmp
##   a b
## 1 A 1
## 2 B 2

虽然语法不是非常具有描述性,但pipeRvery well documented

答案 2 :(得分:6)

我经常发现需要在管道中保存中间产品。虽然我的用例通常是为了避免重复过滤器以便以后进行拆分,操作和重组,但这种技术在这里可以很好地工作:

df %>%
  filter(b < 3) %>%
  {. ->> intermediateResult} %>%  # this saves intermediate 
  mutate(b = b*2) %>%
  bind_rows(intermediateResult)    

答案 3 :(得分:4)

您可以在管道中需要的位置生成所需的对象。例如:

df %>% filter(b < 3) %>% mutate(b = b*2) %>%
  bind_rows(df %>% filter(b < 3))

此方法避免了必须过滤两次:

df %>%
  filter(b < 3) %>%
  bind_rows(., mutate(., b = b*2))

答案 4 :(得分:0)

我对调试感兴趣(想要保存中间结果,以便我可以从控制台检查和操作它们,而不必将管道分成两个很麻烦的部分。所以,就我的目的而言, OP解决方案原始解决方案的唯一问题是它略显冗长。

这可以通过定义辅助函数来解决:

to_var <- function(., ..., env=.GlobalEnv) {
  var_name = quo_name(quos(...)[[1]])
  assign(var_name, ., envir=env)
  .
}

然后可以按如下方式使用:

df <- data.frame(a = LETTERS[1:3], b=1:3)
df %>%
  filter(b < 3) %>%
  to_var(tmp) %>%
  mutate(b = b*2) %>%
  bind_rows(tmp)
# tmp still exists here

仍然使用全局环境,但您也可以显式传递更多本地环境,如下例所示:

f <- function() {
    df <- data.frame(a = LETTERS[1:3], b=1:3)
    env = environment()
    df %>%
      filter(b < 3) %>%
      to_var(tmp, env=env) %>%
      mutate(b = b*2) %>%
      bind_rows(tmp)
}
f()
# tmp does not exist here

accepted solution的问题在于,它似乎没有开箱即用的整流管。 G. Grothendieck's solution根本不适用于调试用例。(更新:请参阅下面的G. Grothendieck的评论及其更新后的答案!)

最后,assign("tmp", .) %>%不起作用的原因是assign()的默认'envir'参数是“当前环境”(参见documentation for assign),每个阶段都不同管道。要查看此信息,请尝试在各个点将{ print(environment()); . } %>%插入管道,并查看每次都打印不同的地址。 (可能可以调整to_var的定义,以便默认为祖父母环境。)