首页 文章

如何在R数据帧中用零替换NA值?

提问于
浏览
563

我有一个数据框,有些列有 NA 值 .

如何用零替换这些 NA 值?

14 回答

  • 106

    如果我们在导出时尝试替换 NA ,例如在写入csv时,我们可以使用:

    write.csv(data, "data.csv", na = "0")
    
  • 4

    使用 dplyr 0.5.0,您可以使用 coalesce 函数,通过执行 coalesce(vec, 0) 可以轻松地将其集成到 %>% 管道中 . 这将取代 vec 中的所有NAs为0:

    假设我们有一个 NA 的数据框:

    library(dplyr)
    df <- data.frame(v = c(1, 2, 3, NA, 5, 6, 8))
    
    df
    #    v
    # 1  1
    # 2  2
    # 3  3
    # 4 NA
    # 5  5
    # 6  6
    # 7  8
    
    df %>% mutate(v = coalesce(v, 0))
    #   v
    # 1 1
    # 2 2
    # 3 3
    # 4 0
    # 5 5
    # 6 6
    # 7 8
    
  • 8

    在@ gsk3回答中查看我的评论 . 一个简单的例子:

    > m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
    > d <- as.data.frame(m)
       V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
    1   4  3 NA  3  7  6  6 10  6   5
    2   9  8  9  5 10 NA  2  1  7   2
    3   1  1  6  3  6 NA  1  4  1   6
    4  NA  4 NA  7 10  2 NA  4  1   8
    5   1  2  4 NA  2  6  2  6  7   4
    6  NA  3 NA NA 10  2  1 10  8   4
    7   4  4  9 10  9  8  9  4 10  NA
    8   5  8  3  2  1  4  5  9  4   7
    9   3  9 10  1  9  9 10  5  3   3
    10  4  2  2  5 NA  9  7  2  5   5
    
    > d[is.na(d)] <- 0
    
    > d
       V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
    1   4  3  0  3  7  6  6 10  6   5
    2   9  8  9  5 10  0  2  1  7   2
    3   1  1  6  3  6  0  1  4  1   6
    4   0  4  0  7 10  2  0  4  1   8
    5   1  2  4  0  2  6  2  6  7   4
    6   0  3  0  0 10  2  1 10  8   4
    7   4  4  9 10  9  8  9  4 10   0
    8   5  8  3  2  1  4  5  9  4   7
    9   3  9 10  1  9  9 10  5  3   3
    10  4  2  2  5  0  9  7  2  5   5
    

    没有必要申请 apply . =)

    EDIT

    您还应该看一下 norm 包 . 它有很多很好的功能,可用于缺少数据分析 . =)

  • 3

    在矩阵或向量中使用 replace() 替换 NA0 的更一般方法

    例如:

    > x <- c(1,2,NA,NA,1,1)
    > x1 <- replace(x,is.na(x),0)
    > x1
    [1] 1 2 0 0 1 1
    

    这也是在 dplyr 中使用 ifelse() 的替代方法

    df = data.frame(col = c(1,2,NA,NA,1,1))
    df <- df %>%
       mutate(col = replace(col,is.na(col),0))
    
  • 6

    你可以使用 replace()

    例如:

    > x <- c(-1,0,1,0,NA,0,1,1)
    > x1 <- replace(x,5,1)
    > x1
    [1] -1  0  1  0  1  0  1  1
    
    > x1 <- replace(x,5,mean(x,na.rm=T))
    > x1
    [1] -1.00  0.00  1.00  0.00  0.29  0.00 1.00  1.00
    
  • 19

    Datacamp中提取的这个简单函数可以帮助:

    replace_missings <- function(x, replacement) {
      is_miss <- is.na(x)
      x[is_miss] <- replacement
    
      message(sum(is_miss), " missings replaced by the value ", replacement)
      x
    }
    

    然后

    replace_missings(df, replacement = 0)
    
  • 689

    另一个使用 imputeTS 包的例子:

    library(imputeTS)
    na.replace(yourDataframe, 0)
    
  • 18

    另一个 dplyr 管道兼容选项, tidyr 方法 replace_na 适用于多个列:

    require(dplyr)
    require(tidyr)
    
    m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
    d <- as.data.frame(m)
    
    myList <- setNames(lapply(vector("list", ncol(d)), function(x) x <- 0), names(d))
    
    df <- d %>% replace_na(myList)
    

    您可以轻松限制为例如数字列:

    d$str <- c("string", NA)
    
    myList <- myList[sapply(d, is.numeric)]
    
    df <- d %>% replace_na(myList)
    
  • 156

    've commented on @ianmunoz'的帖子,但我没有足够的声誉 . 你可以组合 dplyrmutate_eachreplace 来处理 NA0 的替换 . 使用来自@ aL3xa答案的数据框...

    > m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
    > d <- as.data.frame(m)
    > d
    
        V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
    1   4  8  1  9  6  9 NA  8  9   8
    2   8  3  6  8  2  1 NA NA  6   3
    3   6  6  3 NA  2 NA NA  5  7   7
    4  10  6  1  1  7  9  1 10  3  10
    5  10  6  7 10 10  3  2  5  4   6
    6   2  4  1  5  7 NA NA  8  4   4
    7   7  2  3  1  4 10 NA  8  7   7
    8   9  5  8 10  5  3  5  8  3   2
    9   9  1  8  7  6  5 NA NA  6   7
    10  6 10  8  7  1  1  2  2  5   7
    
    > d %>% mutate_each( funs_( interp( ~replace(., is.na(.),0) ) ) )
    
        V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
    1   4  8  1  9  6  9  0  8  9   8
    2   8  3  6  8  2  1  0  0  6   3
    3   6  6  3  0  2  0  0  5  7   7
    4  10  6  1  1  7  9  1 10  3  10
    5  10  6  7 10 10  3  2  5  4   6
    6   2  4  1  5  7  0  0  8  4   4
    7   7  2  3  1  4 10  0  8  7   7
    8   9  5  8 10  5  3  5  8  3   2
    9   9  1  8  7  6  5  0  0  6   7
    10  6 10  8  7  1  1  2  2  5   7
    

    我们在这里使用标准评估(SE),这就是为什么我们需要“ funs_ ”的下划线 . 我们还使用 lazyevalinterp / ~. 引用"everything we are working with",即数据帧 . 现在有零!

  • 40

    对于单个向量:

    x <- c(1,2,NA,4,5)
    x[is.na(x)] <- 0
    

    对于data.frame,从上面创建一个函数,然后 apply 到列 .

    请在下次详细说明下提供可重现的示例:

    How to make a great R reproducible example?

  • 3

    如果要在因子变量中替换NA,这可能很有用:

    n <- length(levels(data.vector))+1
    
    data.vector <- as.numeric(data.vector)
    data.vector[is.na(data.vector)] <- n
    data.vector <- as.factor(data.vector)
    levels(data.vector) <- c("level1","level2",...,"leveln", "NAlevel")
    

    它将因子矢量转换为数字矢量,并添加另一个人工数字因子级别,然后将其转换回因子矢量,并选择一个额外的“NA级别” .

  • 8

    混合dplyr / Base R选项: mutate_all(funs(replace(., is.na(.), 0)))) 的速度是基本R d[is.na(d)] <- 0 选项的两倍多 . (请参阅下面的基准分析 . )

    如果您正在努力应对海量数据帧, data.table 是最快的选择:比dplyr少30%的时间,比Base R接近3倍 . 它还可以修改数据,有效地允许您同时处理几乎两倍的数据 .


    其他有用的tidyverse替换方法的聚类

    Locationally:

    • index mutate_at(c(5:10), funs(replace(., is.na(.), 0)))

    • 直接参考 mutate_at(vars(var5:var10), funs(replace(., is.na(.), 0)))

    • 固定匹配 mutate_at(vars(contains("1")), funs(replace(., is.na(.), 0)))

    • 或代替 contains() ,试试 ends_with()starts_with()

    • 模式匹配 mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))

    Conditionally:
    (仅更改数字(列)并单独保留字符串(列) . )

    • 整数 mutate_if(is.integer, funs(replace(., is.na(.), 0)))

    • 双打 mutate_if(is.numeric, funs(replace(., is.na(.), 0)))

    • 字符串 mutate_if(is.character, funs(replace(., is.na(.), 0)))


    完整分析 -

    测试方法:

    # Base R: 
    baseR.sbst.rssgn   <- function(x) { x[is.na(x)] <- 0; x }
    baseR.replace      <- function(x) { replace(x, is.na(x), 0) }
    baseR.for          <- function(x) { for(j in 1:ncol(x))
                                        x[[j]][is.na(x[[j]])] = 0 }
    # tidyverse
    ## dplyr
    library(tidyverse)
    dplyr_if_else      <- function(x) { mutate_all(x, funs(if_else(is.na(.), 0, .))) }
    dplyr_coalesce     <- function(x) { mutate_all(x, funs(coalesce(., 0))) }
    
    ## tidyr
    tidyr_replace_na   <- function(x) { replace_na(x, as.list(setNames(rep(0, 10), as.list(c(paste0("var", 1:10)))))) }
    
    ## hybrid 
    hybrd.ifelse     <- function(x) { mutate_all(x, funs(ifelse(is.na(.), 0, .))) }
    hybrd.rplc_all   <- function(x) { mutate_all(x, funs(replace(., is.na(.), 0))) }
    hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), funs(replace(., is.na(.), 0))) }
    hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), funs(replace(., is.na(.), 0))) }
    hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), funs(replace(., is.na(.), 0))) }
    hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), funs(replace(., is.na(.), 0))) }
    hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), funs(replace(., is.na(.), 0))) }
    hybrd.rplc_if    <- function(x) { mutate_if(x, is.numeric, funs(replace(., is.na(.), 0))) }
    
    # data.table   
    library(data.table)
    DT.for.set.nms   <- function(x) { for (j in names(x))
                                        set(x,which(is.na(x[[j]])),j,0) }
    DT.for.set.sqln  <- function(x) { for (j in seq_len(ncol(x)))
                                        set(x,which(is.na(x[[j]])),j,0) }
    

    此分析的代码:

    library(microbenchmark)
    # 20% NA filled dataframe of 5 Million rows and 10 columns
    set.seed(42) # to recreate the exact dataframe
    dfN <- as.data.frame(matrix(sample(c(NA, as.numeric(1:4)), 5e6*10, replace = TRUE),
                                dimnames = list(NULL, paste0("var", 1:10)), 
                                ncol = 10))
    # Running 250 trials with each replacement method 
    # (the functions are excecuted locally - so that the original dataframe remains unmodified in all cases)
    perf_results <- microbenchmark(
        hybrid.ifelse    = hybrid.ifelse(copy(dfN)),
        dplyr_if_else    = dplyr_if_else(copy(dfN)),
        baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
        baseR.replace    = baseR.replace(copy(dfN)),
        dplyr_coalesce   = dplyr_coalesce(copy(dfN)),
        hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
        hybrd.rplc_at.stw= hybrd.rplc_at.stw(copy(dfN)),
        hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
        hybrd.rplc_at.mtc= hybrd.rplc_at.mtc(copy(dfN)),
        hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
        hybrd.rplc_if    = hybrd.rplc_if(copy(dfN)),
        tidyr_replace_na = tidyr_replace_na(copy(dfN)),
        baseR.for        = baseR.for(copy(dfN)),
        DT.for.set.nms   = DT.for.set.nms(copy(dfN)),
        DT.for.set.sqln  = DT.for.set.sqln(copy(dfN)),
        times = 250L
    )
    

    结果摘要

    perf_results
    单位:毫秒
    expr min lq mean中位数uq max neval
    hybrid.ifelse 5250.5259 5620.8650 5809.1808 5759.3997 5947.7942 6732.791 250
    dplyr_if_else 3209.7406 3518.0314 3653.0317 3620.2955 3746.0293 4390.888 250
    baseR.sbst.rssgn 1611.9227 1878.7401 1964.6385 1942.8873 2031.5681 2485.843 250
    baseR.replace 1559.1494 1874.7377 1946.2971 1920.8077 2002.4825 2516.525 250
    dplyr_coalesce 949.7511 1231.5150 1279.3015 1288.3425 1345.8662 1624.186 250
    hybrd.rplc_at.nse 735.9949 871.1693 1016.5910 1064.5761 1104.9590 1361.868 250
    hybrd.rplc_at.stw 704.4045 887.4796 1017.9110 1063.8001 1106.7748 1338.557 250
    hybrd.rplc_at.ctn 723.9838 878.6088 1017.9983 1063.0406 1110.0857 1296.024 250
    hybrd.rplc_at.mtc 686.2045 885.8028 1013.8293 1061.2727 1105.7117 1269.949 250
    hybrd.rplc_at.idx 696.3159 880.7800 1003.6186 1038.8271 1083.1932 1309.635 250
    hybrd.rplc_if 705.9907 889.7381 1000.0113 1036.3963 1083.3728 1338.190 250
    tidyr_replace_na 680.4478 973.1395 978.2678 1003.9797 1051.2624 1294.376 250
    baseR.for 670.7897 965.6312 983.5775 1001.5229 1052.5946 1206.023 250
    DT.for.set.nms 496.8031 569.7471 695.4339 623.1086 861.1918 1067.640 250
    DT.for.set.sqln 500.9945 567.2522 671.4158 623.1454 764.9744 1033.463 250

    结果箱图(以对数刻度)

    # adjust the margins to prepare for better boxplot printing
    par(mar=c(8,5,1,1) + 0.1) 
    # generate boxplot
    boxplot(opN, las = 2, xlab = "", ylab = "log(time)[milliseconds]")
    

    颜色编码的试验散点图(以对数刻度)

    qplot(y=time/10^9, data=opN, colour=expr) + 
        labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
        scale_y_log10(breaks=c(1, 2, 4))
    

    关于其他高绩效者的说明

    当数据集变大时,Tidyr的 replace_na 历史上已经退出了前面 . 目前收集50M要运行的数据点,它几乎与Base R For Loop一样好 . 我很想知道不同大小的数据帧会发生什么 .

    可以在此处找到 mutatesummarize _at_all 函数变体的其他示例:https://rdrr.io/cran/dplyr/man/summarise_all.html此外,我在此处找到了有用的演示和示例集合:https://blog.exploratory.io/dplyr-0-5-is-awesome-heres-why-be095fd4eb8a

    归因和赞赏

    特别感谢:

    • Tyler RinkerAkrun用于演示微基准 .

    • alexis_laz致力于帮助我理解 local() 的使用,以及(在弗兰克的耐心帮助下)静音强制在加速许多这些方法中所起的作用 .

    • ArthurYip用于戳添加更新的 coalesce() 函数并更新分析 .

    • 格雷戈尔为了轻松搞清楚 data.table 功能,最终将他们列入阵容 .

    • Base R For循环:alexis_laz

    • data.table For循环:Matt_Dowle

    (当然,如果你发现这些方法有用的话,也请到达并给予他们投票 . )

    Note on my use of Numerics: 如果您有纯整数数据集,则所有函数都将运行得更快 . 有关更多信息,请参阅alexiz_laz's work . IRL,我不记得遇到包含超过10-15%整数的数据集,所以我在完全数字数据帧上运行这些测试 .

  • 63

    dplyr示例:

    library(dplyr)
    
    df1 <- df1 %>%
        mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
    

    Note: 这适用于每个选定的列,如果我们需要对所有列执行此操作,请参阅使用mutate_each的@reidjax的答案 .

  • 47

    我知道这个问题已经回答了,但这样做对某些人来说可能更有用:

    定义此功能:

    na.zero <- function (x) {
        x[is.na(x)] <- 0
        return(x)
    }
    

    现在,无论何时需要将向量中的NA转换为零,您都可以:

    na.zero(some.vector)
    

相关问题