对于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))
过程目标:
- 根据var3,var4和var5中NA的存在修剪尾NA
- 保留最终输出中的所有列
- 只删除后面的NAs(即第3行保留在记录中作为占位符)
- 仅在所有列都有NA(即第7行和第8行,但不是第6行)时进行修剪
基于这些目标,解决方案应该删除df:
的最后两行df.output = df[-c(7,8),]
na的行为。trim(在zoo包中)是理想的(因为它限制了对data.frame末尾带有sides="right"的NA的删除),我的解决方法是修改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]
}
基于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
Edit:
第一个碱rle
和apply
的解
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)