【问题标题】:R -apply- convert many columns from numeric to factorR -apply- 将许多列从数字转换为因子
【发布时间】:2016-03-11 12:24:32
【问题描述】:

我需要将许多数字列转换为因子类型。 示例表:

df <- data.frame(A=1:10, B=2:11, C=3:12)

我尝试过申请:

cols<-c('A', 'B')
df[,cols]<-apply(df[,cols], 2, function(x){ as.factor(x)});

但结果是一个字符类。

> class(df$A)
[1] "character"

如果不对每一列执行 as.factor,我该如何做到这一点?

【问题讨论】:

  • 您的想法是对的,但apply 正在返回一个无法识别因子的矩阵。但是数据框可以。

标签: r class apply


【解决方案1】:

试试

df[,cols] <- lapply(df[,cols],as.factor)

问题是apply() 试图将结果绑定到一个矩阵中,这导致将列强制转换为字符:

class(apply(df[,cols], 2, as.factor))  ## matrix
class(as.factor(df[,1]))  ## factor

相比之下,lapply() 对列表元素进行操作。

【讨论】:

    【解决方案2】:

    您可以将您的结果放回一个可以识别因素的数据框中:

    df[,cols]&lt;-data.frame(apply(df[,cols], 2, function(x){ as.factor(x)}))

    【讨论】:

    • 谢谢。所以结果返回一个矩阵,它们不识别因子。
    【解决方案3】:

    另一个选项,purrrdplyr,可能比基本解决方案更具可读性,并将数据保存在数据框中:

    这是数据:

    df <- data.frame(A=1:10, B=2:11, C=3:12)
    
    str(df)
    'data.frame':   10 obs. of  3 variables:
     $ A: int  1 2 3 4 5 6 7 8 9 10
     $ B: int  2 3 4 5 6 7 8 9 10 11
     $ C: int  3 4 5 6 7 8 9 10 11 12
    

    我们可以通过dmap轻松对所有列进行操作:

    library(purrr)
    library(dplyr)
    
    # all cols to factor
    dmap(df, as.factor)
    
    Source: local data frame [10 x 3]
    
            A      B      C
       (fctr) (fctr) (fctr)
    1       1      2      3
    2       2      3      4
    3       3      4      5
    4       4      5      6
    5       5      6      7
    6       6      7      8
    7       7      8      9
    8       8      9     10
    9       9     10     11
    10     10     11     12
    

    同样在使用select 来自dplyr 的列子集上使用dmap

    # selected cols to factor
    cols <- c('A', 'B')
    
    df[,cols] <- 
      df %>% 
      select(one_of(cols)) %>% 
      dmap(as.factor)
    

    要得到想要的结果:

    str(df)
    'data.frame':   10 obs. of  3 variables:
     $ A: Factor w/ 10 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10
     $ B: Factor w/ 10 levels "2","3","4","5",..: 1 2 3 4 5 6 7 8 9 10
     $ C: int  3 4 5 6 7 8 9 10 11 12
    

    【讨论】:

      【解决方案4】:

      2017 年 11 月 9 日更新

      purrr / purrrlyr 仍在开发中

      与 Ben 类似,但使用 purrrlyr::dmap_at

      library(purrrlyr)
      
      df <- data.frame(A=1:10, B=2:11, C=3:12)
      
      # selected cols to factor
      cols <- c('A', 'B')
      
      (dmap_at(df, factor, .at = cols))
      
      A        B       C
      <fctr>   <fctr>  <int>
      1        2       3      
      2        3       4      
      3        4       5      
      4        5       6      
      5        6       7      
      6        7       8      
      7        8       9      
      8        9       10     
      9        10      11     
      10       11      12 
      

      【讨论】:

      • 不会 map(df[cols], factor) 工作吗?我找不到任何 dmap_at() 函数。
      • 你可能是对的。可以理解的是,purrr 和相关的软件包仍在经历很多变化。 dmap_at 已移至 purrrlyr purrr.tidyverse.org/news/index.html
      • 这就解释了!我刚刚使用了最新版本的 purrr,所以以为我错过了一些东西。
      【解决方案5】:

      一个简单但有效的选择是mapply

      df <- data.frame(A=1:10, B=2:11, C=3:12)
      cols <- c('A', 'B')
      
      df[,cols] <- as.data.frame(mapply(as.factor,df[,cols]))
      

      你也可以使用for循环来达到同样的效果:

      for(col in cols){
        df[,col] <- as.factor(df[,col])
      }
      

      【讨论】:

        【解决方案6】:

        这里有几个tidyverse 选项-

        library(dplyr)
        
        cols <- c('A', 'B')
        
        df <- df %>% mutate(across(all_of(cols), factor)) 
        
        str(df)
        
        #'data.frame':  10 obs. of  3 variables:
        # $ A: Factor w/ 10 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10
        # $ B: Factor w/ 10 levels "2","3","4","5",..: 1 2 3 4 5 6 7 8 9 10
        # $ C: int  3 4 5 6 7 8 9 10 11 12
        

        使用map -

        df[cols] <- purrr::map(df[cols], factor)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-02
          • 1970-01-01
          相关资源
          最近更新 更多