dplyr 0.7整理eval:将字符变量转换为因子

时间:2017-08-08 14:56:36

标签: r dplyr rlang tidyeval

我有一个包含许多变量的数据集,其中一些是字符变量,我想将其转换为因子。由于要转换的变量很多,我想使用dplyr_0.7中新的整理评估功能来实现这一点。以下是我的数据中的一个最小示例:

data <- data.frame(factor1 = c("K", "V"), 
                   factor2 = c("E", "K"), 
                   other_var = 1:2, 
                   stringsAsFactors = FALSE)

我有一个命名列表,其中包含我要转换的每个变量的data.frame。列表中的这些data.frame都具有相同的结构,可以在此示例中看到:

codelist_list <- list(factor1 = data.frame(Code = c("K", "V"), 
                                           Bezeichnung = c("Kauf", "Verkauf"), 
                                           stringsAsFactors = FALSE),
                      factor2 = data.frame(Code = c("E", "K"), 
                                           Bezeichnung = c("Eigengeschaeft", "Kundengeschaeft"), 
                                           stringsAsFactors = FALSE))

我做想要做的是为每个变量定义这样的因素:

mutate(df, factor1 = factor(factor1, 
                            levels = codelist_list[["factor1"]][["Code"]],
                            labels = codelist_list[["factor1"]][["Bezeichnung"]]))

到目前为止我所尝试的是以下内容:

convert_factors <- function(variable, df) {
  factor_variable <- enquo(variable)
  df %>% 
    mutate(!!quo_name(factor_variable) := factor(!!quo_name(factor_variable), 
                                                 levels = codelist_list[[variable]][["Code"]],
                                                 labels = codelist_list[[variable]][["Bezeichnung"]]))
}

在第一步中,我想通过调用返回的convert_factors()检查我的函数convert_factors("factor1", data)是否正常工作

  factor1 factor2 other_var
1    <NA>       E         1
2    <NA>       K         2

变量不显示值标签,而是替换为NA

最终目标是map超过我要转换的所有变量。在这里,我尝试了map(c("factor1", "factor2"), convert_factors, df = data),它返回了

  

错误(函数(x,严格= TRUE):参数已被评估

我尝试按照http://dplyr.tidyverse.org/articles/programming.html的说明进行操作,但这就是我提出的所有内容。

有谁知道问题所在(并希望向我解释我的错误)。

4 个答案:

答案 0 :(得分:3)

我认为你混淆了语录和字符串:

  1. 在你的功能中,variable是一个字符串,而不是表达式。因此,您应该使用rlang::sym而不是enquo将其转换为现状。

  2. quo_name用于将表达式转换为字符串。由于variable已经是一个字符串,您可以直接在!!variable的rhs(右侧)上mutate进行操作。

  3. mutate的lhs中,您需要使用factor_variable取消!!而不是尝试将其转换为quo_name的字符串。

    < / LI>

    在纠正上述错误后,您的功能将起作用:

    convert_factors <- function(variable, df) {
        factor_variable <- rlang::sym(variable)
        df %>% 
            mutate(!!variable := factor(
                !!factor_variable, 
                levels = codelist_list[[variable]][["Code"]],
                labels = codelist_list[[variable]][["Bezeichnung"]]))
    }
    
    # > convert_factors('factor1', data)
    #   factor1 factor2 other_var
    # 1    Kauf       E         1
    # 2 Verkauf       K         2
    

    以下是我的尝试:

    params <- lapply(codelist_list, setNames, nm = c('levels', 'labels'))
    
    convert_factors <- function(variable, df) {
        factor_variable <- rlang::sym(variable)
        factor_param <- c(list(factor_variable), params[[variable]])
    
        df %>% mutate(!!variable := do.call(factor, factor_param))
    }
    
    convert_factors('factor1', data)
    #   factor1 factor2 other_var
    # 1    Kauf       E         1
    # 2 Verkauf       K         2
    

答案 1 :(得分:2)

使用整齐的eval和dplyr的mt1022的很好的解决方案。但是,这项任务只能通过base-R完成:

data[,names(codelist_list)] <- lapply(names(codelist_list), function(x) 
  data[,x] <- factor(data[,x],
                     levels = codelist_list[[x]][["Code"]],
                     labels = codelist_list[[x]][["Bezeichnung"]]))

答案 2 :(得分:1)

您可以使用mutate_at使用.内的funs编码来处理此问题,以便立即将函数应用于多个列。

这种方法仍然需要使用tidyevalcodelist_list中提取正确的列表,同时通过.引用变量。

mutate_at(data, c("factor1", "factor2"), 
          funs( factor(., levels = codelist_list[[quo_name(quo(.))]][["Code"]],
                      labels = codelist_list[[quo_name(quo(.))]][["Bezeichnung"]]) ) )

  factor1         factor2 other_var
1    Kauf  Eigengeschaeft         1
2 Verkauf Kundengeschaeft         2

如果你想让一个函数传递给mutate_at,你可以这样做,只需稍作修改。

convert_factors = function(variable) {
     var2 = enquo(variable)
     factor(variable, levels = codelist_list[[quo_name(var2)]][["Code"]],
            labels = codelist_list[[quo_name(var2)]][["Bezeichnung"]]) 
}

mutate_at(data, c("factor1", "factor2"), convert_factors)

 factor1         factor2 other_var
1    Kauf  Eigengeschaeft         1
2 Verkauf Kundengeschaeft         2

答案 3 :(得分:0)

由于您只是使用字符串和SE函数(因子构造函数),因此您不需要表达式或定义。只需对:=

使用名称取消引用即可
convert_factors <- function(variable, df) {
  factor <- factor(variable,
    levels = codelist_list[[variable]][["Code"]],
    labels = codelist_list[[variable]][["Bezeichnung"]]
  )
  mutate(df, !! variable := factor)
}

map(c("factor1", "factor2"), convert_factors, df = data)