高效地从一个数据框中同时删除多个时间序列开头和结尾的缺失值。

6
使用R语言,我正在尝试从包含多个时间序列的数据框的开头和结尾修剪NA值。我已经使用for循环和zoo包实现了我的目标,但是在大型数据框上效率极低,这是可以预料的。
我的数据框看起来像这样,包含3列,每个时间序列都由其唯一ID标识。在这种情况下,分别为AAA,B和CCC。
id   date          value
AAA  2010/01/01    NA
AAA  2010/02/01    34
AAA  2010/03/01    35
AAA  2010/04/01    30
AAA  2010/05/01    NA
AAA  2010/06/01    28
B    2010/01/01    NA
B    2010/02/01    0
B    2010/03/01    1
B    2010/04/01    2
B    2010/05/01    3
B    2010/06/01    NA
B    2010/07/01    NA
B    2010/07/01    NA
CCC  2010/01/01    0
CCC  2010/02/01    400
CCC  2010/03/01    300
CCC  2010/04/01    200
CCC  2010/05/01    NA

我想知道如何有效地从每个时间序列的开头和结尾删除NA值。在这种情况下,AAA,B和CCC应该是这样的。

id   date          value
AAA  2010/02/01    34
AAA  2010/03/01    35
AAA  2010/04/01    30
AAA  2010/05/01    NA
AAA  2010/06/01    28
B    2010/02/01    0
B    2010/03/01    1
B    2010/04/01    2
B    2010/05/01    3
CCC  2010/01/01    0
CCC  2010/02/01    400
CCC  2010/03/01    300
CCC  2010/04/01    200

我已经确定了唯一的ID(共有60,000个),然后使用for循环遍历它们,每次创建一个代码子集并创建一个zoo对象。接着使用zoo包中的trim函数来去除前导和尾随的缺失值,最后将它们rbinding到一个新的数据框中,以包含最终修剪后的时间序列数据。正如预期的那样,这非常低效。 - sizeight
2个回答

7
我会这样做,非常快速:

require(data.table)
DT = as.data.table(your data)   # please provide something pastable

DT2 = DT[!is.na(value)]
setkey(DT,id,date)
setkey(DT2,id,date)
tokeep = DT2[DT,!is.na(value),rolltolast=TRUE,mult="last"]
DT = DT[tokeep]

这是通过在每个组内滚动前面的非NA值来实现的,但不会越过最后一个值。

mult="last"是可选的。如果使用v1.8.0(在CRAN上)可以加速它。对于有和没有使用它进行计时感兴趣。默认情况下,data.table连接到组(mult="all"),但在这种情况下,我们连接到关键字的所有列,并且我们知道关键字是唯一的; 即关键字中没有重复项。在v1.8.1(在dev中),不需要了解这一点,它会更好地照顾你。


我也在准备使用data.table来回答问题,但是Matthew已经抢先了,这很好。然而,另一种选择是使用zoo包中的na.trim函数。类似于DT[, na.trim(.SD), by = id],因为该函数接受除zoo对象以外的其他对象。 - BenBarnes
@BenBarnes 听起来不错,而且更短。有趣的是看看哪个更快。 - Matt Dowle
@Matthew Dowle的作品完美无缺,速度极快。它恰好满足了我的需求,并且我可以再次向我办公室中那些顽固的SAS编程人员证明R是一个可行的替代方案。我认为这比他们的SAS替代方案执行得更快。 - sizeight
@BenBarnes 我会研究一下你关于使用na.trim的建议。 - sizeight
@sizeight,Matthew的答案比我的快得多(特别是在处理大量数据时)。相信那些制作工具的人最懂得如何最好地使用它们! - BenBarnes
@Matthew Dowle,我今天升级到了data.table 1.8.8,但在使用上述解决方案时遇到了问题。我收到了一个错误信息:“尝试在因子列x.date上进行滚动连接。只有整数、双精度或字符列可以进行滚动连接。”你有什么建议吗? - sizeight

0

如果您的数据在数据框架data

fun <- function(x)
{
    x$value[is.na(x$value)] <- "NA"
    tmp <- rle(x$value)
    values <- tmp$values
    lengths <- tmp$lengths
    n <- length(values)

    nr <- nrow(x)
    id <- c()
    if(values[1] == "NA") id <- c(id, 1:lengths[1])
    if(values[n] == "NA") id <- c(id, (nr-lengths[n]+1):nr)
    if(length(id) == 0)return(x)
    x[-id,]
}

do.call(rbind,
        by(data, INDICES=data$id,
           FUN=fun))

我想这不是最优雅的解决方案。就像这篇文章所说的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接