【问题标题】:Trimming NAs based on column subset - a more elegant solution?基于列子集修剪 NA - 更优雅的解决方案?
【发布时间】:2015-06-03 10:01:25
【问题描述】:

stackoverflow 社区的新年难题,过去阅读帖子和答案给了我很大的帮助(这是我的第一个问题)。我找到了解决方法,但我想知道是否可以建议其他方法/解决方案。

我正在尝试从大 data.frame 中删除尾随的 NA,但这些 NA 仅在 data.frame 的少数列中找到,我想保留输出中的所有列。这是一个有代表性的数据子集。

df=data.frame(var1=rep("A", 8), var2=c("a","b","c","d","e","f","g","h"), var3=c(0,1,NA,2,3,NA,NA,NA), var4=c(0,0,NA,4,5,NA,NA,NA), var5=c(0,0,NA,0,2,4,NA,NA))

过程目标:

  1. 根据 var3、var4 和 var5 中的 NA 存在修剪尾随 NA
  2. 在最终输出中保留所有列
  3. 仅删除尾随 NA(即第 3 行作为占位符保留在记录中)
  4. 仅当所有列都有 NA(即第 7 行和第 8 行,但不是第 6 行)时才修剪

基于这些目标,解决方案应删除 df 的最后两行:

df.output = df[-c(7,8),]

na.trim (在 zoo 包中)的行为是理想的(因为它限制了在 data.frame 末尾的那些 NA 的删除,sides="right"),我的解决方法涉及更改na.trim.default 函数以包含子集术语。

有什么建议吗?非常感谢您的帮助。

编辑:为了完成这个问题,下面是我从 na.trim.default 代码创建的函数,它也可以工作,但如上所述,确实需要加载 zoo 包。

na.trim.multiplecols <-  function (object, colrange, sides = c("both", "left", "right"),     is.na = c("any","all"),...) 
{
is.na <- match.arg(is.na)
nisna <- if (is.na == "any" || length(dim(object[,colrange])) < 1) {
complete.cases(object[,colrange])
}
else rowSums(!is.na(object[,colrange])) > 0
idx <- switch(match.arg(sides), left = cumsum(nisna) > 0, 
            right = rev(cumsum(rev(nisna) > 0) > 0), both = (cumsum(nisna) > 
                                                               0) &       rev(cumsum(rev(nisna)) > 0))
if (length(dim(object)) < 2) 
object[idx]
else object[idx, , drop = FALSE]

}

【问题讨论】:

    标签: r


    【解决方案1】:

    基于max(which(!is.na())) 的东西会起作用。我们使用它从感兴趣的列中找到最大的非缺失数据索引。

    使用你的 df

    ind <-  max(max(which(!is.na(df$var3))),
            max(which(!is.na(df$var4))),        
            max(which(!is.na(df$var5)))) 
    
    df[1:ind, ]
    
       var1 var2 var3 var4 var5
     1    A    a    0    0    0
     2    A    b    1    0    0
     3    A    c   NA   NA   NA
     4    A    d    2    4    0
     5    A    e    3    5    2
     6    A    f   NA   NA    4
    

    【讨论】:

      【解决方案2】:

      Edit: 使用基础rleapply 的第一个解决方案

      t <- rle(apply(as.matrix(df[,3:5]), 1, function(x) all(is.na(x))))
      r <- ifelse(t$values[length(t$values)] == TRUE, t$lengths[length(t$lengths)], 0)
      head(df, -r)
      

      使用RleIRanges 的第二个解决方案:

      require(IRanges)
      t <- min(sapply(df[,3:5], function(x) {
          o <- Rle(x)
          val <- runValue(o)
          if (is.na(val[length(val)])) {
              len <- runLength(o)
              out <- len[length(len)]
          } else {
              out <- 0
          }
      }))
      head(df, -t)
      

      【讨论】:

      • 感谢您的解决方案。我以前听说过 rle 但从未实现过它,我知道它在前进中可能会有多大用处。一个小问题是,因为我的 data.frame 包含许多最后没有 NA 的实例,所以 head(df, -r) 调用在 r 返回 0 时不起作用。我只是编写了一些不同的代码来使用 r 进行计数从 df 的长度返回并删除这些行。
      猜你喜欢
      • 2018-04-28
      • 1970-01-01
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      • 2011-03-31
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多