使用带有管道

时间:2017-06-29 17:16:16

标签: r function dplyr magrittr

编辑:我重新设计了问题,使其更加清晰,并整合了我自己找到的内容

管道是使用单个命令链时使代码更具可读性的好方法

然而,在某些情况下,我觉得有人不得不通过创建不必要的临时变量,混合管道和嵌入式括号或定义自定义函数来与其哲学不一致。

例如,请参阅此SO问题,其中OP想知道如何使用管道将colnames转换为小写:Dplyr or Magrittr - tolower?

我会忘记names<-的存在来说明我的观点 基本上有3种方法可以做到:

  1. 使用临时变量

    temp <- df %>% names %>% tolower
    df %>% setNames(temp)
    
  2. 使用嵌入式括号

    df %>% setNames(tolower(names(.)))
    
  3. 定义自定义功能

    upcase <- function(df) {names(df) <- tolower(names(df)); df}
    df %>% upcase
    
  4. 我认为能够做到这样的事情会更加一致:

    df %T>%                              # create new branch with %T%>%
      {names(.) %>% tolower %as% n} %>%  # parallel branch assigned to alias n, then going back to main branch with %>%
      setNames(n)                        # combine branches
    

    对于更复杂的情况,我认为它比上面的3个例子更具可读性,而且我没有污染我的工作区。

    到目前为止,我已经能够非常接近,我可以输入:

    df %T>%
      {names(.) %>% tolower %as% n} %>%
      setNames(A(n));fp()
    

    或(对旧学校计算器有点致敬)

    df %1%                   # puts lhs in first memory slot (notice "%1%", I define these up to "%9%")
      names %>%
      tolower %>%
      setNames(M(1),.);fp()  # call the first stored value
    

    (见底部代码)

    我的问题如下:

    1. 我在全球环境中创建了一个新环境,我必须用fp()手动刷新它,这很难看
    2. 我想摆脱这个A函数,但我不太了解管道链的环境结构这样做
    3. 这是我的代码:

      • 它为别名
      • 创建一个名为PipeAliasEnv的环境
      • %as%在隔离环境中创建别名
      • %to%在调用环境中创建变量
      • A调用别名
      • fpPipeAliasEnv
      • 中删除所有对象

      这是我使用的代码,可重复的示例以4种不同的方式解决:

      library(magrittr)
      alias_init <- function(){
        assign("PipeAliasEnv",new.env(),envir=.GlobalEnv)
        assign("%as%"      ,function(value,variable)    {assign(as.character(substitute(variable)),value,envir=PipeAliasEnv)},envir=.GlobalEnv)
        assign("%to%"      ,function(value,variable)    {assign(as.character(substitute(variable)),value,envir=parent.frame())},envir=.GlobalEnv)
        assign("A"         ,function(variable)          {   get(as.character(substitute(variable)),      envir=PipeAliasEnv)},envir=.GlobalEnv)
        assign("fp"        ,function(remove_envir=FALSE){if(remove_envir) rm(PipeAliasEnv,envir=.GlobalEnv) else rm(list=ls(envir=PipeAliasEnv),envir=PipeAliasEnv)},envir=.GlobalEnv) # flush environment
        # to handle `%i%` and M(i) notation, 9 should be enough :
        sapply(1:9,function(i){assign(paste0("%",i,"%"),eval(parse(text=paste0('function(lhs,rhs){lhs <- eval(lhs)
                           rhs <- as.character(substitute(rhs))
                           str <- paste("lhs %>%",rhs[1],"(",paste(rhs[-1],collapse=","),")")
                           assign("x',i,'",lhs,envir=PipeAliasEnv)
                           eval(parse(text= str))}'))),envir=.GlobalEnv)})
        assign("M"         ,function(i)                 {   get(paste0("x",as.character(substitute(i))), envir=PipeAliasEnv)},envir=.GlobalEnv)
      }
      alias_init()
      
      # using %as%
      df <- iris %T>%
        {names(.) %>% toupper %as% n} %>%
        setNames(A(n)) %T>%
        {. %>% head %>% print}(.) ;fp()
      
      # still using %as%, choosing another main chain
      df <- iris %as% dataset %>%
        names %>%
        toupper %>%
        setNames(A(dataset),.) %T>%
        {. %>% head %>% print}(.);fp()
      
      # using %to% (notice no assignment on 1st line)
      iris %T>%
        {names(.) %>% toupper %as% n} %>%
        {setNames(.,A(n))} %to% df %>%     # no need for '%T>%' and '{}' here
        head %>% print;fp()
      
      # or using the old school calculator fashion (probably the clearest for this precise task)
      df <- iris %1%
        names %>%
        toupper %>%
        setNames(M(1),.) %T>%
        {. %>% head %>% print}(.);fp()
      

      我的问题简短:

      如何摆脱Afp? 奖励:%to%{}内无法使用,我该如何解决?

0 个答案:

没有答案