代码之家  ›  专栏  ›  技术社区  ›  Indrajeet Patil

混淆purr::pmap与rlang的行为;“to quote”或“not to quote”参数,即q

  •  6
  • Indrajeet Patil  · 技术社区  · 8 年前

    我有一个自定义函数,在该函数中,我使用 rlang . 这个功能很好用 不管 输入的参数是带引号还是不带引号。但是,奇怪的是,当这个函数与 purrr::pmap ,仅当引用参数时才有效。

    所以我有两个问题:

    1. 为什么函数的行为是这样的?

    2. 如何使用 朗朗 这样即使在 采购:采购管理计划 ?

    下面是一个使用简单函数突出显示此问题的最小reprex:

    # loading the needed libraries
    library(rlang)
    library(dplyr)
    library(purrr)
    
    
    # defining the function
    tryfn <- function(data, x, y) {
      data <-
        dplyr::select(
          .data = data,
          x = !!rlang::enquo(x),
          y = !!rlang::enquo(y)
        )
    
      # creating a dataframe of means
      result_df <- data.frame(mean.x = mean(data$x), mean.y = mean(data$y))
    
      # return the dataframe
      return(result_df)
    }
    
    # without quotes (works!)
    tryfn(iris, Sepal.Length, Sepal.Width)
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    
    # with quotes (works!)
    tryfn(iris, "Sepal.Length", "Sepal.Width")
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    
    # pmap without quotes (doesn't work)
    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x = list(Sepal.Length, wt, len),
      y = list(Sepal.Width, mpg, dose)
    ),
    .f = tryfn)
    #> Error in is.data.frame(.l): object 'Sepal.Length' not found
    
    # pmap with quotes (works!)
    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x = list("Sepal.Length", "wt", "len"),
      y = list("Sepal.Width", "mpg", "dose")
    ),
    .f = tryfn)
    #> [[1]]
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    #> 
    #> [[2]]
    #>    mean.x   mean.y
    #> 1 3.21725 20.09062
    #> 
    #> [[3]]
    #>     mean.x   mean.y
    #> 1 18.81333 1.166667
    

    创建于2018-05-21 reprex package (v0.2.0版)。

    2 回复  |  直到 8 年前
        1
  •  3
  •   Tung    8 年前

    问题是:R锯 Sepal.Length, wt, len 符号,因此它尝试在当前环境中查找并评估它们。当然,它会导致错误,因为它们是数据帧的列。当您引用它们时,R并没有尝试评估并返回值,因为它将这些值视为字符串。

    如果你替换 list 具有 base::alist dplyr::vars rlang::exprs ,应该有效

    注意:由于我们已经对输入进行了报价,因此不需要使用 rlang::enquo 里面 tryfn 不再。

    # loading the needed libraries
    library(rlang)
    library(tidyverse)
    
    # defining the function
    tryfn <- function(data, x, y) {
      data <-
        dplyr::select(
          .data = data,
          x = !! x,
          y = !! y
        )
    
      # creating a data frame of means
      result_df <- data.frame(mean.x = mean(data$x), mean.y = mean(data$y))
    
      # return the data frame
      return(result_df)
    }
    
    # alist handles its arguments as if they described function arguments. 
    # So the values are not evaluated, and tagged arguments with no value are 
    # allowed whereas list simply ignores them. 
    
    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x    = alist(Sepal.Length, wt, len),
      y    = alist(Sepal.Width, mpg, dose)
    ),
    .f = tryfn)
    
    #> [[1]]
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    #> 
    #> [[2]]
    #>    mean.x   mean.y
    #> 1 3.21725 20.09062
    #> 
    #> [[3]]
    #>     mean.x   mean.y
    #> 1 18.81333 1.166667
    
    
    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x    = dplyr::vars(Sepal.Length, wt, len),
      y    = dplyr::vars(Sepal.Width, mpg, dose)
    ),
    .f = tryfn)
    
    #> [[1]]
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    #> 
    #> [[2]]
    #>    mean.x   mean.y
    #> 1 3.21725 20.09062
    #> 
    #> [[3]]
    #>     mean.x   mean.y
    #> 1 18.81333 1.166667
    
    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x    = rlang::exprs(Sepal.Length, wt, len),
      y    = rlang::exprs(Sepal.Width, mpg, dose)
    ),
    .f = tryfn)
    
    #> [[1]]
    #>     mean.x   mean.y
    #> 1 5.843333 3.057333
    #> 
    #> [[2]]
    #>    mean.x   mean.y
    #> 1 3.21725 20.09062
    #> 
    #> [[3]]
    #>     mean.x   mean.y
    #> 1 18.81333 1.166667
    

    创建于2018-05-21 reprex package (v0.2.0版)。

        2
  •  1
  •   andrew_reece    8 年前

    问题不在 purrr ,真的。同样的行为也可以通过以下方式观察到:

    list(Sepal.Length) # Error: object 'Sepal.Length' not found
    

    据我所知,所有的魔法 !! , enquo 当您将参数传递到函数中时,类似的方法是可用的。 您已创建 . 这就是为什么要将未加引号的字段名传递给 tryfn() 直接。

    但是有 pmap() ,您要输入字段名( Sepal.Width , wt 等)在 list 定义,以及 列表 不喜欢这样-所以 pmap 从来没有机会把事情传给 tryfn 因为你的 列表 定义上的错误。

    以字符串形式传入字段名的效果很好,例如 列表 可以容纳该数据类型,然后 PMAP 有机会把它们映射到 tryfn()。 .

    哈德利的评论 quasiquotation with dplyr 可能对你有用。

    回答第二个问题:

    如何使用rlang生成函数,这样即使在purr::pmap中使用,也不必引用参数?

    您可以用 quo() 为了避免逐字引用它们作为字符串,尽管我不确定这是否有很大的改进:

    purrr::pmap(.l = list(
      data = list(iris, mtcars, ToothGrowth),
      x = list(quo(Sepal.Length), quo(wt), quo(len)),
      y = list(quo(Sepal.Width), quo(mpg), quo(dose))
    ),
    .f = tryfn) %>% 
      bind_rows(., .id="dataset")
    
      dataset    mean.x    mean.y
    1       1  5.843333  3.057333
    2       2  3.217250 20.090625
    3       3 18.813333  1.166667
    
    推荐文章