【问题标题】:How to get dplyr::mutate() to work with variable names when called inside a function?在函数内部调用时如何让 dplyr::mutate() 使用变量名?
【发布时间】:2019-03-23 12:36:27
【问题描述】:

我正在探索来自 Pokemon API 的数据(实际上并未使用 API,只是从 github 拉取 .csv 文件)。在一个名为pokemon_types.csv 的包含每个口袋妖怪类型的窄格式文件中(一个口袋妖怪最多可以有两种类型),类型被编码为整数(本质上是因子)。我想使用同样来自 API 的查找表 (types.csv) 标记这些级别,其中包含级别为 id(1、2、3 等)和相应的 identifier(正常,我想用作标签的战斗、飞行等)。

> head(read_csv(path("pokemon_types.csv")), 10)
# A tibble: 10 x 3
   pokemon_id type_id  slot
        <dbl>   <dbl> <dbl>
 1          1      12     1
 2          1       4     2
 3          2      12     1
 4          2       4     2
 5          3      12     1
 6          3       4     2
 7          4      10     1
 8          5      10     1
 9          6      10     1
10          6       3     2
> head(read_csv(path("types.csv")))
# A tibble: 6 x 4
     id identifier generation_id damage_class_id
  <dbl> <chr>              <dbl>           <dbl>
1     1 normal                 1               2
2     2 fighting               1               2
3     3 flying                 1               2
4     4 poison                 1               2
5     5 ground                 1               2
6     6 rock                   1               2

当我单独管道所有步骤时,我的代码可以工作,但由于我要执行此标记步骤至少十几次左右,我试图将它放入一个函数中。问题是,当我改为调用该函数时(据我所知,它的步骤完全相同)它会引发 object not found 错误。

设置:

library(readr)
library(magrittr)
library(dplyr)
library(tidyr)

options(readr.num_columns = 0)

# Append web directory to filename
path <- function(x) {
  paste0("https://raw.githubusercontent.com/",
         "PokeAPI/pokeapi/master/data/v2/csv/", x)
}

违规函数:

# Use lookup table to label factor variables
label <- function(data, variable, lookup) {
  mutate(data, variable = factor(variable, 
                                 levels = read_csv(path(lookup))$id,
                                 labels = read_csv(path(lookup))$identifier))
}

这个版本,不使用该功能,有效:

df.types <-
  read_csv(path("pokemon_types.csv")) %>%
  mutate(type_id = factor(type_id, 
                          levels = read_csv(path("types.csv"))$id,
                          labels = read_csv(path("types.csv"))$identifier)) %>%
  spread(slot, type_id)

head(df.types)

它返回:

# A tibble: 6 x 3
  pokemon_id `1`   `2`   
       <dbl> <fct> <fct> 
1          1 grass poison
2          2 grass poison
3          3 grass poison
4          4 fire  NA    
5          5 fire  NA    
6          6 fire  flying

使用该功能的这个版本没有:

df.types <-
  read_csv(path("pokemon_types.csv")) %>%
  label(type_id, "types.csv") %>%
  spread(slot, type_id)

它返回:

Error in factor(variable, 
                levels = read_csv(path(lookup))$id, 
                labels = read_csv(path(lookup))$identifier) : 
  object 'type_id' not found 

我知道这里有几件事可能不是最理想的(例如,每次下载 lookup 两次),但我更感兴趣的是为什么看起来与某些书面代码相同的函数使它不再工作。我确定我只是犯了一个愚蠢的错误。

【问题讨论】:

  • 这是另一个重复询问 dplyr 的 Non-Standard Evaluation 函数参数。这与factor() 无关。你看到factor() 感到困惑的唯一原因是因为它在dplyr::mutate() 调用中。
  • 请务必阅读 dplyr 编程指南:dplyr.tidyverse.org/articles/programming.html
  • @MrFlick 我什至不知道非标准评估,谢谢,抱歉重复。这似乎比我想象的要复杂,弄清楚如何管理 NSE 以在函数内部使用 dplyr 是标准的,还是完全避免在函数中使用 dplyr 更常见?
  • 这真的是个人喜好。但最好早点熟悉!! 和 quosures,因为在某些时候你会需要它们。

标签: r dplyr non-standard-evaluation


【解决方案1】:

感谢有帮助的 cmets,我能够了解所有关于非标准评估的知识并找到解决方案:

label <- function(data, variable, lookup) {
  variable <- enquo(variable)
  data %>%
    mutate(!!variable := factor(!!variable, 
                                 levels = read_csv(path(lookup))$id,
                                 labels = read_csv(path(lookup))$identifier))
}

主要功能是enquo(),它充当“准引用”,!!,它“取消引用”变量,以便可以通过参数解释它,以及:=,它允许在两者上取消引用侧面。

我尝试并未能实现完全避免dplyr 的解决方案,但至少这是可行的。

【讨论】:

    猜你喜欢
    • 2018-12-23
    • 2022-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 2019-01-29
    • 2016-11-15
    • 1970-01-01
    相关资源
    最近更新 更多