【问题标题】:Convert all data frame character columns to factors将所有数据框字符列转换为因子
【发布时间】:2014-01-05 09:42:24
【问题描述】:

给定一个(预先存在的)具有各种类型列的数据框,在不影响任何其他类型的列的情况下,将其所有字符列转换为因子的最简单方法是什么?

这是一个例子data.frame

df <- data.frame(A = factor(LETTERS[1:5]),
                 B = 1:5, C = as.logical(c(1, 1, 0, 0, 1)),
                 D = letters[1:5],
                 E = paste(LETTERS[1:5], letters[1:5]),
                 stringsAsFactors = FALSE)
df
#   A B     C D   E
# 1 A 1  TRUE a A a
# 2 B 2  TRUE b B b
# 3 C 3 FALSE c C c
# 4 D 4 FALSE d D d
# 5 E 5  TRUE e E e
str(df)
# 'data.frame':  5 obs. of  5 variables:
#  $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
#  $ B: int  1 2 3 4 5
#  $ C: logi  TRUE TRUE FALSE FALSE TRUE
#  $ D: chr  "a" "b" "c" "d" ...
#  $ E: chr  "A a" "B b" "C c" "D d" ...

我知道我能做到:

df$D <- as.factor(df$D)
df$E <- as.factor(df$E)

有没有办法让这个过程自动化一点?

【问题讨论】:

    标签: r dataframe


    【解决方案1】:
    DF <- data.frame(x=letters[1:5], y=1:5, stringsAsFactors=FALSE)
    
    str(DF)
    #'data.frame':  5 obs. of  2 variables:
    # $ x: chr  "a" "b" "c" "d" ...
    # $ y: int  1 2 3 4 5
    

    as.data.frame 的(烦人的)默认设置是将所有字符列转换为因子列。你可以在这里使用它:

    DF <- as.data.frame(unclass(DF),stringsAsFactors=TRUE)
    str(DF)
    #'data.frame':  5 obs. of  2 variables:
    # $ x: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
    # $ y: int  1 2 3 4 5
    

    【讨论】:

    【解决方案2】:

    Roland 的回答非常适合这个特定问题,但我想我会分享一个更通用的方法。

    DF <- data.frame(x = letters[1:5], y = 1:5, z = LETTERS[1:5], 
                     stringsAsFactors=FALSE)
    str(DF)
    # 'data.frame':  5 obs. of  3 variables:
    #  $ x: chr  "a" "b" "c" "d" ...
    #  $ y: int  1 2 3 4 5
    #  $ z: chr  "A" "B" "C" "D" ...
    
    ## The conversion
    DF[sapply(DF, is.character)] <- lapply(DF[sapply(DF, is.character)], 
                                           as.factor)
    str(DF)
    # 'data.frame':  5 obs. of  3 variables:
    #  $ x: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
    #  $ y: int  1 2 3 4 5
    #  $ z: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
    

    对于转换,分配 (DF[sapply(DF, is.character)]) 的左侧子集是字符的列。在右侧,对于该子集,您使用lapply 来执行您需要执行的任何转换。 R 足够聪明,可以用结果替换原始列。

    这样做的方便之处在于,如果您想换一种方式或进行其他转换,只需在左侧更改您要查找的内容,然后在右侧指定您要更改的内容。

    【讨论】:

    • 谢谢,非常有用,尤其是在 RMySQL 请求提供仅包含字符向量的数据帧之后。只是不要忘记(像我一样)预先在非字符的列中设置正确的数字逻辑类型等。
    • 我喜欢这个答案。部分原因是它是一个更彻底的解决方案,部分原因是我见过的 lapply 和 sapply 使用最多。我会从那个中学到更多!
    • 你是个传奇人物!谢谢,最近 1-2 天我一直在寻找这个。
    【解决方案3】:

    正如@Raf Z 对此question 的评论,dplyr 现在有 mutate_if。超级好用,简单易读。

    > str(df)
    'data.frame':   5 obs. of  5 variables:
     $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
     $ B: int  1 2 3 4 5
     $ C: logi  TRUE TRUE FALSE FALSE TRUE
     $ D: chr  "a" "b" "c" "d" ...
     $ E: chr  "A a" "B b" "C c" "D d" ...
    
    > df <- df %>% mutate_if(is.character,as.factor)
    
    > str(df)
    'data.frame':   5 obs. of  5 variables:
     $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
     $ B: int  1 2 3 4 5
     $ C: logi  TRUE TRUE FALSE FALSE TRUE
     $ D: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
     $ E: Factor w/ 5 levels "A a","B b","C c",..: 1 2 3 4 5
    

    【讨论】:

      【解决方案4】:

      我曾经做过一个简单的for 循环。正如@A5C1D2H2I1M1N2O1R2T1 的回答,lapply 是一个不错的解决方案。但是如果你转换所有的列,你之前需要一个data.frame,否则你最终会得到一个list。执行时间差异很小。

       mm2N=mm2New[,10:18]
       str(mm2N)
      'data.frame':   35487 obs. of  9 variables:
       $ bb    : int  4 6 2 3 3 2 5 2 1 2 ...
       $ vabb  : int  -3 -3 -2 -2 -3 -1 0 0 3 3 ...
       $ bb55  : int  7 6 3 4 4 4 9 2 5 4 ...
       $ vabb55: int  -3 -1 0 -1 -2 -2 -3 0 -1 3 ...
       $ zr    : num  0 -2 -1 1 -1 -1 -1 1 1 0 ...
       $ z55r  : num  -2 -2 0 1 -2 -2 -2 1 -1 1 ...
       $ fechar: num  0 -1 1 0 1 1 0 0 1 0 ...
       $ varr  : num  3 3 1 1 1 1 4 1 1 3 ...
       $ minmax: int  3 0 4 6 6 6 0 6 6 1 ...
      
       # For solution
       t1=Sys.time()
       for(i in 1:ncol(mm2N)) mm2N[,i]=as.factor(mm2N[,i])
       Sys.time()-t1
      Time difference of 0.2020121 secs
       str(mm2N)
      'data.frame':   35487 obs. of  9 variables:
       $ bb    : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ...
       $ vabb  : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ...
       $ bb55  : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ...
       $ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ...
       $ zr    : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ...
       $ z55r  : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ...
       $ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ...
       $ varr  : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ...
       $ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ...
      
       #lapply solution
       mm2N=mm2New[,10:18]
       t1=Sys.time()
       mm2N <- lapply(mm2N, as.factor)
       Sys.time()-t1
      Time difference of 0.209012 secs
       str(mm2N)
      List of 9
       $ bb    : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ...
       $ vabb  : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ...
       $ bb55  : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ...
       $ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ...
       $ zr    : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ...
       $ z55r  : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ...
       $ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ...
       $ varr  : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ...
       $ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ...
      
       #data.frame lapply solution
       mm2N=mm2New[,10:18]
       t1=Sys.time()
       mm2N <- data.frame(lapply(mm2N, as.factor))
       Sys.time()-t1
      Time difference of 0.2010119 secs
       str(mm2N)
      'data.frame':   35487 obs. of  9 variables:
       $ bb    : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ...
       $ vabb  : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ...
       $ bb55  : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ...
       $ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ...
       $ zr    : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ...
       $ z55r  : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ...
       $ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ...
       $ varr  : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ...
       $ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ...
      

      【讨论】:

      • 这也会改变所有的列。 OP 要求仅将字符列更改为因子。
      • @SeGa 可以使用if(is.character()) 来仅转换这些列。
      • 请注意,在转换所有列时,您无需使用lapply 方法执行data.frame。您可以使用mm2N[] &lt;- lapply(mm2N, as.factor) 代替mm2N &lt;- data.frame(lapply(mm2N, as.factor))。注意[]
      • @xm1,因为data.frame 只是list 的一种特殊类型,您可以在特定索引处重新插入相关元素(这就是我在其中使用[sapply(DF, is.character)] 的原因我的答案)。如果您使用[],它将替换所有内容(前提是尺寸正确)。因此,您可以使用df &lt;- data.frame(v1 = 1, v2 = 2); df[] &lt;- list("a", "b"),但不能使用df[] &lt;- list("a", "b", "c")
      • 这也适用于其他对象,对于保留原始对象的结构很有用。例如,如果你有m &lt;- matrix(1:2, ncol = 2),并且你想将值与字母匹配,如果你有m &lt;- letters[m],尺寸就会丢失。但如果您使用m[] &lt;- letters[m],它们会被保留。
      【解决方案5】:

      最简单的方法是使用下面给出的代码。它将自动将所有变量转换为 R 中数据框中的因子的整个过程。它对我来说非常好。 food_cat 这里是我正在使用的数据集。将其更改为您正在处理的那个。

          for(i in 1:ncol(food_cat)){
      
      food_cat[,i] <- as.factor(food_cat[,i])
      
      }
      

      【讨论】:

      • 这会将所有列更改为因子,无论它们的类型如何。
      【解决方案6】:

      我注意到“[”索引列在迭代时无法创建级别:

      for(convert.to.factors 中的 a_feature){
      特征.df[a_feature]

      它创建,例如对于“状态”列:

      状态:因子 w/ 1 级 "c(\"Success\", \"Fail\")" : NA NA NA ...

      这可以通过使用“[[”索引来解决:

      for(convert.to.factors 中的 a_feature){
      特征.df[[a_feature]]

      根据需要给予:

      。状态:因素 w/ 2 个级别“成功”、“失败”:1 1 2 1 ...

      【讨论】:

        【解决方案7】:

        使用dplyr

        library(dplyr)
        
        df <- data.frame(A = factor(LETTERS[1:5]),
                         B = 1:5, C = as.logical(c(1, 1, 0, 0, 1)),
                         D = letters[1:5],
                         E = paste(LETTERS[1:5], letters[1:5]),
                         stringsAsFactors = FALSE)
        
        str(df)
        

        我们得到:

        'data.frame':   5 obs. of  5 variables:
         $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
         $ B: int  1 2 3 4 5
         $ C: logi  TRUE TRUE FALSE FALSE TRUE
         $ D: chr  "a" "b" "c" "d" ...
         $ E: chr  "A a" "B b" "C c" "D d" ...
        

        现在,我们可以将所有chr 转换为factors

        df <- df%>%mutate_if(is.character, as.factor)
        str(df)
        

        我们得到:

        'data.frame':   5 obs. of  5 variables:
         $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
         $ B: int  1 2 3 4 5
         $ C: logi  TRUE TRUE FALSE FALSE TRUE
         $ D: chr  "a" "b" "c" "d" ...
         $ E: chr  "A a" "B b" "C c" "D d" ...
        

        让我们也提供其他解决方案:

        带基础包:

        df[sapply(df, is.character)] <- lapply(df[sapply(df, is.character)], 
                                                                   as.factor)
        

        dplyr1.0.0

        df <- df%>%mutate(across(where(is.factor), as.character))
        

        使用purrr 包:

        library(purrr)
        
        df <- df%>% modify_if(is.factor, as.character) 
        

        【讨论】:

          【解决方案8】:

          根据@Roland 的回答和@Paul de Barros 的cmets,我观察到以下结论:

              df <- data.frame(A = factor(LETTERS[1:5]),
                           B = 1:5, C = as.logical(c(1, 1, 0, 0, 1)),
                           D = letters[1:5],
                           E = paste(LETTERS[1:5], letters[1:5]),
                           stringsAsFactors = FALSE)
             
             df<-as.data.frame(unclass(df),stringsAsFactors=TRUE)
             str(df)
          

          看起来很实用。

          > str(df)
          'data.frame':   5 obs. of  5 variables:
           $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
           $ B: int  1 2 3 4 5
           $ C: logi  TRUE TRUE FALSE FALSE TRUE
           $ D: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
           $ E: Factor w/ 5 levels "A a","B b","C c",..: 1 2 3 4 5
          

          【讨论】:

            猜你喜欢
            • 2019-04-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多