R-如何在带有准引号的mutate中动态构造函数名称

时间:2018-11-15 11:02:22

标签: r dplyr

首先,这是我关于StackOverflow的第一个问题,我希望我会写一个好方法。如果没有,请不要犹豫告诉我...对不起,我的英语水平很高!

我想使用dplyr中的mutate函数来更改data.frame列的类型,但事先不知道新类型。因此,我想动态创建函数名称(例如“ as.numeric”,“ as.factor”),并从另一个data.frame中获取新类型。

这是一个具体的示例(我想对具有100个以上变量的data.frames进行操作,因此您将了解我不想手动执行此操作!):<​​/ p>

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 :(得分:0)

有趣的问题。我想我在tidyverse的purrr包中找到了使用map2的解决方案。

# 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

但是为了轻松进行数据类型转换,请尝试。为每一列提供合适的数据类型。但是,它从不暗示因素。但随后您可以根据需要使用convert。

library(hablar)

df %>% 
    retype() %>%
    convert(fct(Name))

答案 1 :(得分:0)

我认为您想要的是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