Search code examples
rdataframefillzoo

In R, is the any way can fill NA and keep variable attribute?


Using zoo::na.fill(0) can fill all the NA by 0 , but this will change the variable attribute, for instance, the attribute of variable amount is num in dataframe md, after zoo::na.fill(0) the attribute change to chr. Is the any way can fill na so easy like na.fill and keep variable attribute?

md <- data.frame(cat=c('a','b','d',NA,'E',NA),
                 subcat=c('A','C',NA,NA,NA,'D'),
                 amount=c(1,2,NA,5,NA,8)) 

md %>% zoo::na.fill(0)

Data


Solution

  • Here is a solution without the usage of zoo.

    library(dplyr)
    md2 <- md %>% 
      mutate(across(where(is.factor), as.character)) %>% 
      mutate(across(where(is.character), function(x) { replace(x, is.na(x), "0") } )) %>% 
      mutate(across(where(is.numeric), function(x) { replace(x, is.na(x), 0) } )) %>% 
      mutate(across(where(is.character), as.factor)) 
    

    If you want to, you can wrap this into a self-defined function to use it as easily as the fill-na method by zoo, e.g.

    FillNA <- function(df){
      df2 <- df %>% 
        mutate(across(where(is.factor), as.character)) %>% 
        mutate(across(where(is.character), function(x) { replace(x, is.na(x), "0") } )) %>% 
        mutate(across(where(is.numeric), function(x) { replace(x, is.na(x), 0) } )) %>% 
        mutate(across(where(is.character), as.factor)) 
      return(df2)
    }
    

    Here the verification for the types:

    > str(md)
    'data.frame':   6 obs. of  3 variables:
     $ cat   : Factor w/ 4 levels "a","b","d","E": 1 2 3 NA 4 NA
     $ subcat: Factor w/ 3 levels "A","C","D": 1 2 NA NA NA 3
     $ amount: num  1 2 NA 5 NA 8
    
    str(FillNA(md))
    'data.frame':   6 obs. of  3 variables:
     $ cat   : Factor w/ 5 levels "0","a","b","d",..: 2 3 4 1 5 1
     $ subcat: Factor w/ 4 levels "0","A","C","D": 2 3 1 1 1 4
     $ amount: num  1 2 0 5 0 8