【问题标题】:Replace NAs in multiple list elements in R替换 R 中多个列表元素中的 NA
【发布时间】:2018-08-25 23:44:31
【问题描述】:

假设我有以下列表:

list(c(1:5,NA,NA),NA,c(NA,6:10))

[[1]]
[1]  1  2  3  4  5 NA NA

[[2]]
[1] NA

[[3]]
[1] NA  6  7  8  9 10

我想用0替换所有NAs:

[[1]]
[1] 1 2 3 4 5 0 0

[[2]]
[1] 0

[[3]]
[1]  0  6  7  8  9 10

我原本以为is.na 会参与其中,但无法让它影响所有列表元素。我从相关问题 (Remove NA from list of lists) 中了解到,使用lapply 可以让我将is.na 应用于每个元素,但该帖子演示了如何删除(而不是替换NA价值观。

我如何替换来自多个列表元素的NA值?

我尝试过for 循环和ifelse 方法,但我尝试过的所有方法要么很慢,要么不起作用,要么很笨重。必须有一个简单的方法来使用 apply 函数来做到这一点......

【问题讨论】:

  • lapply(L1, function (x) ifelse(is.na(x), 0, x))
  • 顺便说一句,您可能只想将它们存储在一个表中,例如 data.table::rbindlist(lapply(L, function(x) data.frame(x)), id=TRUE) 在这种情况下,普通方法将起作用..
  • @janos 感谢您的评论。有关lapply 方法的性能比较,请参阅我的post belowreplace()ifelse() 快。

标签: r list replace na


【解决方案1】:

我决定对提到的各种lapply 方法进行基准测试

lapply(Lt, function(x) replace(x,is.na(x),0)) 
lapply(Lt, function(x) {x[is.na(x)] <- 0; x})
lapply(Lt, function(x) ifelse(is.na(x), 0, x)) 

基准代码:

Lt <- lapply(1:10000, function(x)  sample(c(1:10000,rep(NA,1000))) )    ##Sample list

elapsed.time <- data.frame(
    m1 = mean(replicate(25,system.time(lapply(Lt, function(x) replace(x,is.na(x),0)))[3])),
    m2 = mean(replicate(25,system.time(lapply(Lt, function(x) {x[is.na(x)] <- 0; x}))[3])),
    m3 = mean(replicate(25,system.time(lapply(Lt, function(x) ifelse(is.na(x), 0, x)))[3]))
  )

结果:

Function                                          Average Elapsed Time
lapply(Lt, function(x) replace(x,is.na(x),0))     0.8684 
lapply(Lt, function(x) {x[is.na(x)] <- 0; x})     0.8936
lapply(Lt, function(x) ifelse(is.na(x), 0, x))    8.3176

replace 方法最快,紧随其后的是[] 方法。 ifelse 方法慢了 10 倍。

【讨论】:

    【解决方案2】:

    这将处理任何列表深度和结构:

    x <-  eval(parse(text=gsub("NA","0",capture.output(dput(a)))))
    # [[1]]
    # [1] 1 2 3 4 5 0 0
    # 
    # [[2]]
    # [1] 0
    # 
    # [[3]]
    # [1]  0  6  7  8  9 10
    

    【讨论】:

      【解决方案3】:
      kk<- list(c(1:5,NA,NA),NA,c(1,6:10))
      
      lapply(kk, function(i) 
        { p<- which(is.na(i)==TRUE)
          i[p] <- 0
          i
        })
      

      根据格雷戈尔的评论编辑

      lapply(kk, function(i) {i[is.na(i)] <- 0; i})
      

      【讨论】:

      • 感谢您的回答。这类似于我自己的早期尝试。我试图找到一些更容易阅读/遵循的东西。
      • 你永远不需要== TRUE。在这种情况下,which 是多余的。只是i[is.na(i)] &lt;- 0; ifunction(i) 的正文中很好。
      【解决方案4】:

      试试这个:

      lapply(enlist, function(x) { x[!is.na(x)]})
      

      地点:

      enlist <- list(c(1:5,NA,NA),NA,c(NA,6:10))
      

      这会产生:

      [[1]]
      [1] 1 2 3 4 5
      
      [[2]]
      logical(0)
      
      [[3]]
      [1]  6  7  8  9 10
      

      【讨论】:

      • 嗨。我想更换 NA 而不是摆脱它们。谢谢。
      【解决方案5】:

      还有

      这是使用replace 函数的简单lapply 方法:

      L1 <-list(c(1:5,NA,NA),NA,c(NA,6:10))
      
      lapply(L1, function(x) replace(x,is.na(x),0))
      

      得到想要的结果:

      [[1]]
      [1] 1 2 3 4 5 0 0
      
      [[2]]
      [1] 0
      
      [[3]]
      [1]  0  6  7  8  9 10
      

      【讨论】:

      • 或者rapply 如果列表更高级:rapply(L, function(x) replace(x, is.na(x), 0), classes = c("logical", "integer"), how="replace")
      【解决方案6】:

      有多种方法可以做到这一点:

      使用 purrrr 包中的 map

      lt <- list(c(1:5,NA,NA),NA,c(NA,6:10))
      lt %>% 
          map(~replace(., is.na(.), 0))
      
      
      #output
      
      [[1]]
      [1] 1 2 3 4 5 0 0
      
      [[2]]
      [1] 0
      
      [[3]]
      [1]  0  6  7  8  9 10
      

      【讨论】:

        猜你喜欢
        • 2019-07-22
        • 1970-01-01
        • 2017-07-05
        • 2022-10-04
        • 2014-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多