根据列子集修剪NA - 更优雅的解决方案?

时间:2013-01-03 17:07:40

标签: r

对于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
  2. 中的NA存在修剪尾随NA
  3. 保留最终输出中的所有列
  4. 仅删除尾随的NA(即第3行作为占位符保留在记录中)
  5. 仅当所有列都具有NA(即第7行和第8行,但不是第6行)时才进行修剪
  6. 基于这些目标,解决方案应该删除最后两行df:

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

    na.trim的行为(在动物园包中)是理想的(因为它限制在data.frame结尾处移除那些NA,并且sides =“right”),并且我的解决方案涉及改变na.trim.default函数包含子集项。

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

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

    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]
    
    }
    

2 个答案:

答案 0 :(得分:0)

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)

使用包Rle中的IRanges的第二个解决方案:

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)

答案 1 :(得分:0)

基于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