【问题标题】:dplyr change many data typesdplyr 改变许多数据类型
【发布时间】:2015-02-24 10:09:24
【问题描述】:

我有一个data.frame:

dat <- data.frame(fac1 = c(1, 2),
                  fac2 = c(4, 5),
                  fac3 = c(7, 8),
                  dbl1 = c('1', '2'),
                  dbl2 = c('4', '5'),
                  dbl3 = c('6', '7')
                  )

要更改数据类型,我可以使用类似

l1 <- c("fac1", "fac2", "fac3")
l2 <- c("dbl1", "dbl2", "dbl3")
dat[, l1] <- lapply(dat[, l1], factor)
dat[, l2] <- lapply(dat[, l2], as.numeric)

dplyr

dat <- dat %>% mutate(
    fac1 = factor(fac1), fac2 = factor(fac2), fac3 = factor(fac3),
    dbl1 = as.numeric(dbl1), dbl2 = as.numeric(dbl2), dbl3 = as.numeric(dbl3)
)

在 dplyr 中有更优雅(更短)的方式吗?

谢谢 克里斯托夫

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    编辑(截至 2021 年 3 月)

    正如Eric's answer 中还指出的那样,mutate_[at|if|all] 已被mutate()across() 的组合所取代。作为参考,我将在原始答案中的示例中添加相应的挂件(见下文):

    # convert all factor to character
    dat %>% mutate(across(where(is.factor), as.character))
    
    # apply function (change encoding) to all character columns 
    dat %>% mutate(across(where(is.character), 
                   function(x){iconv(x, to = "ASCII//TRANSLIT")}))
    
    # subsitute all NA in numeric columns
    dat %>% mutate(across(where(is.numeric), function(x) tidyr::replace_na(x, 0)))
    

    原答案

    由于尼克的答案现在已被弃用,而拉斐尔的评论非常有用,我想将其添加为答案。如果您想将所有 factor 列更改为character,请使用mutate_if

    dat %>% mutate_if(is.factor, as.character)
    

    还允许其他功能。例如,我使用iconv 更改所有character 列的编码:

    dat %>% mutate_if(is.character, function(x){iconv(x, to = "ASCII//TRANSLIT")})
    

    或将数字列中的所有 NA 替换为 0:

    dat %>% mutate_if(is.numeric, function(x){ifelse(is.na(x), 0, x)})
    

    【讨论】:

    • dat %&gt;% mutate_if(is.factor, as.character) 将所有因子列更改为字符,是迄今为止最好的一般答案。
    • funs 现在在 dplyr 中已被弃用,所以现在这是最好的答案
    • 现在dat %&gt;% mutate_if(where(is.factor), as.character) 更正确
    【解决方案2】:

    您可以使用mutate_each(即mutate_each_)的标准评估版来更改列类:

    dat %>% mutate_each_(funs(factor), l1) %>% mutate_each_(funs(as.numeric), l2)
    

    【讨论】:

    • 在这种情况下你也可以使用starts_with()
    • 感谢您的建议,@hadley。因此,对于第一种情况,dat %&gt;% mutate_each(funs(factor), starts_with("fac")) 将以字符串“fac”开头的所有列转换为因子。
    • @hadley 是否可以进行相同的操作,但是以某种方式转换用户选择转换后的所有列?不确定我的问题是否明确。
    • mutate_each 在最新版本中已弃用,请改用mutate_at...
    【解决方案3】:

    编辑 - 此答案的语法已被弃用,loki's updated answer 更合适。

    原创-

    ?mutate_each 的底部(至少在 dplyr 0.5 中)看起来该功能,如@docendo discimus 的回答,将被弃用并替换为更灵活的替代方案mutate_ifmutate_all 和@ 987654325@。与@hadley 在他的评论中提到的最相似的可能是使用mutate_at。请注意,与mutate_each 相比,参数的顺序是颠倒的,vars() 使用类似于select() 的语义,我将其解释为?select_helpers 函数。

    dat %>% mutate_at(vars(starts_with("fac")),funs(factor)) %>%   
      mutate_at(vars(starts_with("dbl")),funs(as.numeric))
    

    但是mutate_at 可以采用列号而不是vars() 参数,在阅读完此页面并查看替代方案后,我最终使用mutate_at 但使用grep 来捕获许多不同类型的一次列名(除非你总是有这么明显的列名!)

    dat %>% mutate_at(grep("^(fac|fctr|fckr)",colnames(.)),funs(factor)) %>%
      mutate_at(grep("^(dbl|num|qty)",colnames(.)),funs(as.numeric))
    

    我很高兴能找到mutate_at + grep,因为现在一行可以处理很多列。

    编辑 - 现在我在 select_helpers 中看到matches(),它处理正则表达式,所以现在我喜欢这个。

    dat %>% mutate_at(vars(matches("fac|fctr|fckr")),funs(factor)) %>%
      mutate_at(vars(matches("dbl|num|qty")),funs(as.numeric))
    

    另一个一般相关的评论 - 如果您的所有日期列都具有可匹配的名称和一致的格式,那么这很强大。就我而言,这会将我所有读取为数字的 YYYYMMDD 列转换为日期。

      mutate_at(vars(matches("_DT$")),funs(as.Date(as.character(.),format="%Y%m%d")))
    

    【讨论】:

    • 如果您从因子更改为数字,请记住 as.numeric 本身不起作用。因子在内部存储为带有表格的整数,以给出因子级别标签。仅使用as.numeric 只会给出内部整数代码。要从因子更改为数字,应稍微调整代码。 mutate_at(vars(matches("dbl|num|qty")),function(x) as.numeric(as.character(x)))
    【解决方案4】:

    Dplyr across 函数已取代 _if_at_all。见vignette("colwise")

    dat %>% 
    mutate(across(all_of(l1), as.factor),
           across(all_of(l2), as.numeric))
    

    【讨论】:

    • 类似地,使用列索引:dat &lt;- dat %&gt;% mutate(across(all_of(names(dat)[1:3]), as.factor), across(all_of(names(dat)[4:6]), as.numeric))
    【解决方案5】:

    这是与mutate_at 的单线:

    dat %>% mutate_at("l1", factor) %>% mutate_at("l2", as.numeric)
    

    【讨论】:

      【解决方案6】:

      更通用的实现列类型转换的方式如下:

      如果您想将所有 factor 列转换为 character 列,例如,可以使用一个管道来完成:

      df %>%  mutate_each_( funs(as.character(.)), names( .[,sapply(., is.factor)] ))
      

      【讨论】:

      • 对于这种情况,df %&gt;% mutate_if(is.factor,as.character) 有效(对于 dplyr > 0.5 的版本)
      【解决方案7】:

      或者使用来自hablarconvert 可能更简单:

      library(hablar)
      
      dat %>% 
        convert(fct(fac1, fac2, fac3),
                num(dbl1, dbl2, dbl3))
      

      或与tidyselect结合:

      dat %>% 
        convert(fct(contains("fac")),
                num(contains("dbl")))
      

      【讨论】:

        【解决方案8】:

        试试这个

        df[,1:11]

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-06
          • 2014-08-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多