Как заставить dplyr :: mutate () работать с именами переменных при вызове внутри функции? - PullRequest
1 голос
/ 23 марта 2019

Я изучаю данные из Pokemon API (на самом деле не использую API, просто извлекаю файлы .csv из github). В файле, который содержит типы каждого покемона в узком формате (у покемона может быть до двух типов) с именем pokemon_types.csv, типы кодируются как целые числа (по существу, факторы). Я хочу пометить эти уровни, используя справочную таблицу (types.csv), также из API, которая содержит уровни как 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 дважды каждый раз), но меня больше интересует, почему функция, которая кажется идентичной некоторому написанному коду, делает ее более неработоспособной. Я уверен, что просто делаю глупую ошибку.

1 Ответ

1 голос
/ 23 марта 2019

Благодаря полезным комментариям я смог узнать все о нестандартной оценке и найти решение:

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, но по крайней мере это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...