R - Как динамически построить имя функции в mutate с квази-цитатой - PullRequest
0 голосов
/ 15 ноября 2018

Во-первых, это мой первый вопрос по StackOverflow, я надеюсь, что напишу это хорошо.Если нет, не стесняйтесь сказать мне ... И извините за мой примерный английский!

Я хотел бы использовать функцию mutate из dplyr, чтобы изменить тип столбцов data.frame, ноне зная заранее нового типа.Таким образом, я хотел бы динамически создать имя функции (например, «as.numeric», «as.factor»), беря новый тип из другого data.frame.

Вот конкретный пример (что яЯ хочу сделать это для data.frames с более чем 100 переменными, так что вы поймете, что я не хочу делать это вручную!):

library(tidyverse)

df <- data.frame(Name = c("Roger", "Steve"), Age = c("40", "32"), stringsAsFactors = FALSE)
glimpse(df)

Observations: 2
Variables: 2
$ Name <chr> "Roger", "Steve"
$ Age  <chr> "40", "32"

types <- data.frame(Field = c("Name", "Age"), OldType = c("character", "character"), NewType = c("factor", "integer"), stringsAsFactors = FALSE)
glimpse(types)

Observations: 2
Variables: 3
$ Field   <chr> "Name", "Age"
$ OldType <chr> "character", "character"
$ NewType <chr> "factor", "integer"

Я искал в течение длительного времени и нашел многодокументация по квази-цитате, и я попробовал несколько вещей, но так и не получил ожидаемого результата.Вот две попытки, которые я сделал:

# First attempt
for(i in 1:nrow(types)){
  field <- types$Field[i]
  field_quo <- enquo(field)
  new_type <- paste0("as.", types$NewType[i], "(", field, ")")
  new_type_quo <- enquo(new_type)
  df <- df %>% mutate(!!field_quo := !!new_type_quo)
}
glimpse(df)

Observations: 2
Variables: 2
$ Name <chr> "as.factor(Name)", "as.factor(Name)"
$ Age  <chr> "as.integer(Age)", "as.integer(Age)"

=> вызовы функций считаются строками, а значения столбцов заменяются вместо их типов.

# Second attempt
for(i in 1:nrow(types)){
  field <- types$Field[i]
  field_quo <- ensym(field)
  new_type <- paste0("as.", types$NewType[i], "(", field, ")")
  new_type_quo <- ensym(new_type)
  df <- df %>% mutate(!!field_quo := !!new_type_quo)
}

Здесь яполучить сообщение об ошибке:

Error in mutate_impl(.data, dots) : Binding not found: as.factor(Name).

Я полагаю, что функция mutate рассматривает то, что в скобках, как целое имя переменной?

Я пробовал другие вещи, но безуспешно.Я должен признать, что я не являюсь экспертом в области R, и мне трудно полностью понять эту концепцию квазиквотирования, несмотря на качество документации.Итак, я знаю, что я делаю вещи неправильно, но я не знаю, почему и как это сделать правильно ... Может кто-то помочь?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Я думаю, что вы хотите get. Это позволяет вам получить объект, передав его имя в виде символа, поэтому get('as.factor') вернет функцию as.factor. Вписывая это в ваши предыдущие попытки:

for(i in 1:nrow(types)) {
    field <- sym(types$Field[i])
    typeFun <- get(paste0('as.', types$NewType[i]))
    df <- df %>% 
        mutate(!!field := typeFun(!!field))
}
glimpse(df)

Observations: 2
Variables: 2
$ Name <fct> Roger, Steve
$ Age  <int> 40, 32
0 голосов
/ 15 ноября 2018

интересный вопрос. Я думаю, что нашел решение, используя map2 из пакета purrr в tidyverse.

# Data
df <- data.frame(Name = c("Roger", "Steve"), Age = c("40", "32"), stringsAsFactors = FALSE)
types <- data.frame(Field = c("Name", "Age"), OldType = c("character", "character"), NewType = c("factor", "integer"), stringsAsFactors = FALSE)

library(tidyverse)

# Create a column with function names that is needed. I.e. adding as.
types <- types %>% 
  mutate(newType2 = paste0("as.", NewType))

# Then loop over column names and functions
df2 <- map2_dfc(types$Field, 
         types$newType2, 
         ~df %>% 
           select_(.x) %>% 
           mutate_all(.y)
  ) %>% as_tibble()

дает вам

> df2
# A tibble: 2 x 2
  Name    Age
  <fct> <int>
1 Roger    40
2 Steve    32

Но для простого преобразования типов данных попробуйте. который дает вам подходящий тип данных для каждого столбца. Тем не менее, это никогда не предполагает факторов. Но тогда вы можете использовать конвертирование, если хотите.

library(hablar)

df %>% 
    retype() %>%
    convert(fct(Name))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...