【问题标题】:Replace missing for all the categorical variable with 'None'将所有分类变量的缺失替换为“无”
【发布时间】:2019-12-01 23:42:50
【问题描述】:

我想将数据集中所有分类变量的缺失值转换为“无”。我有 100 多个因子变量,我想一次为所有变量执行此操作,而无需在代码中使用它们的名称。

假设我有以下数据集(仅作为示例),并且我想将“x”和“y”等所有因子变量的“NA”替换为“无”作为级别。

  x = data.frame(x = as.factor(c(1, 2, NA, 3)), y = as.factor(c(NA, NA, 4, 5)), z=c(1,0,2,NA) )

【问题讨论】:

    标签: r replace missing-data


    【解决方案1】:

    另一种tidyverse 保留因子类的可能性:

    x %>%
     mutate_if(is.factor, ~ fct_explicit_na(., na_level = "None"))
    
         x    y  z
    1    1 None  1
    2    2 None  0
    3 None    4  2
    4    3    5 NA
    

    【讨论】:

      【解决方案2】:

      您可以转换为字符、替换和转换回因子,例如像这样:

      df <- data.frame(x = as.factor(c(1, 2, NA, 3)), y = as.factor(c(NA, NA, 4, 5)), z=c(1,0,2,NA) )
      
      isf <-  sapply(df, is.factor)  # check which columns are factors
      df[, isf] <- lapply(df[, isf], function(.){
        . <- as.character(.)  # convert to character
        .[is.na(.)] <- "None" # replace NA by "none"
        factor(.)             # return a factor 
      })
      

      工作部分的较短版本:

      df[, isf] <- lapply(df[, isf], function(.)
        factor(replace(as.character(.), is.na(.), "None"))
      )
      

      另一种策略(也许更优雅)是首先将“无”添加到每个因素的水平,然后将NA 替换为"None"

      df <- data.frame(x = as.factor(c(1, 2, NA, 3)), y = as.factor(c(NA, NA, 4, 5)), z=c(1,0,2,NA) )
      
      isf <-  sapply(df, is.factor)  # check which columns are factors
      df[, isf] <- lapply(df[, isf], function(.){
        levels(.) <- c(levels(.), "None")
        replace(., is.na(.), "None")
      })
      

      【讨论】:

        【解决方案3】:

        您可以像这样使用tidyr 包中的replace_na

        
        library(tidyr)               
        library(dplyr)
        x %>% 
          mutate(x = as.character(x), y = as.character(y)) %>% 
          replace_na(list(x = "None", y = "None"))
        

        请注意,您首先必须将感兴趣的列转换为字符,以便可以保存 "None" 字符串。

        【讨论】:

        • 在我的真实数据中,我有数十个分类变量,它们都是因素,我不想在编码中使用它们的名字。我希望我可以使用类似 is.factor 来选择所有因子变量
        【解决方案4】:

        这是另一个没有任何包装的答案。只需转换为矩阵并将其全部转换为 'None' 并将其转换回数据帧。它也很快

        x=as.matrix(data.frame(x = as.factor(c(1, 2, NA, 3)), y = as.factor(c(NA, NA, 4, 5)), z=c(1,0,2,NA) ))
        
        x[is.na(x)] = 'None'
        as.data.frame(x)
        

        【讨论】:

        • 这仅在数据框中的所有内容都可以转换为因子时才有效。
        【解决方案5】:

        这也可以在基础 R 中使用rapply 巧妙地完成:

        ## data
        dat <- data.frame(x = as.factor(c(1, 2, NA, 3)), y = as.factor(c(NA, NA, 4, 5)), z=c(1,0,2,NA))  
        
        ## rapply
        rapply(dat, function(col) {
              if(any(is.na(col))) {
                col_na <- addNA(col)
                levels(col_na) <- c(levels(col), "None")
                col_na
              } else col
            }, classes = "factor", how = "replace")
        #>      x    y  z
        #> 1    1 None  1
        #> 2    2 None  0
        #> 3 None    4  2
        #> 4    3    5 NA
        

        基准测试

        下面是针对@tmfmk 的 tidyverse 方法的一些小基准测试:

        library(dplyr)
        library(forcats)
        
        ## function to create simulated data.frame
        create_df <- function(df_size, prop_NA){
          v <- sample(1:100, df_size^2, replace = TRUE)
          v[sample(seq_len(df_size^2), prop_NA * df_size^2)] <- NA
          data.frame(apply(matrix(v, ncol = df_size), 1, as.factor))   
        }
        
        ## rapply approach
        replace_NA_rapply <- function(dat) {
          rapply(dat, function(col) {
                if(any(is.na(col))) {
                  col_na <- addNA(col)
                  levels(col_na) <- c(levels(col), "None")
                  col_na
                } else col
              }, classes = "factor", how = "replace")
        }
        
        ## tidyverse approach
        replace_NA_tidy <- function(dat) { 
          mutate_if(dat, is.factor, ~ fct_explicit_na(., na_level = "None"))
        }
        
        ## benchmark several data.frame sizes
        bnch <- bench::press(
            df_size = c(10, 100, 1E3),
            prop_NA = c(0.05, 0.5),
            {
              dat <- create_df(df_size, prop_NA)
              bench::mark(
                  rapply = replace_NA_rapply(dat),
                  tidyverse = replace_NA_tidy(dat),
                  min_iterations = 50
              )
            }
        )
        
        bnch
        #> # A tibble: 12 x 8
        #>    expression df_size prop_NA      min   median `itr/sec` mem_alloc
        #>    <bch:expr>   <dbl>   <dbl> <bch:tm> <bch:tm>     <dbl> <bch:byt>
        #>  1 rapply          10    0.05 118.13µs 132.45µs   7274.          0B
        #>  2 tidyverse       10    0.05   1.67ms   1.82ms    529.      1.74MB
        #>  3 rapply         100    0.05   3.35ms   3.79ms    256.      1.25MB
        #>  4 tidyverse      100    0.05  18.93ms  20.36ms     48.2     1.34MB
        #>  5 rapply        1000    0.05   58.3ms  77.28ms     12.3    41.91MB
        #>  6 tidyverse     1000    0.05 260.24ms 291.22ms      3.40   52.88MB
        #>  7 rapply          10    0.5   253.2µs 286.64µs   3097.          0B
        #>  8 tidyverse       10    0.5    2.17ms   2.48ms    369.      1.91KB
        #>  9 rapply         100    0.5    3.07ms   3.58ms    272.   1005.53KB
        #> 10 tidyverse      100    0.5   18.59ms  19.58ms     50.7     1.12MB
        #> 11 rapply        1000    0.5   57.73ms  76.63ms     12.4    41.83MB
        #> 12 tidyverse     1000    0.5  249.06ms 319.42ms      3.08   54.53MB
        

        【讨论】:

          猜你喜欢
          • 2014-10-04
          • 2018-03-21
          • 1970-01-01
          • 1970-01-01
          • 2018-02-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-05
          相关资源
          最近更新 更多