data.frame 的条件过滤,前面和后面的 NA 观察

Conditional filtering of data.frame with preceeding and tailing NA observations

我有一个 data.frame 由数据的观察和模型预测组成。一个最小的示例数据集可能如下所示:

myData <- data.frame(tree=c(rep("A", 20)), doy=c(seq(75, 94)), count=c(NA,NA,NA,NA,0,NA,NA,NA,NA,1,NA,NA,NA,NA,2,NA,NA,NA,NA,NA), pred=c(0,0,0,0,1,1,1,2,2,2,2,3,3,3,3,6,9,12,20,44))

计数列表示在一整套天数内进行观察和预测的时间,实际上是将数据插值到天级别(从每 5 天开始)。

我想有条件地过滤这个数据集,以便我最终将预测截断到与观察相同的范围内,实际上在计数开始和结束之间保持所有预测(即删除前面和后面 rows/values pred 当它们对应于计数列中的 NA 时)。对于这个例子,理想的结果是:

   tree doy count pred
5     A  79     0    1
6     A  80    NA    1
7     A  81    NA    1
8     A  82    NA    2
9     A  83    NA    2
10    A  84     1    2
11    A  85    NA    2
12    A  86    NA    3
13    A  87    NA    3
14    A  88    NA    3
15    A  89     2    3

我试图通过将filterfirstlast组合来解决这个问题,考虑使用条件mutate创建一个列来确定是否存在是对前一个 doy 的观察(可能使用 lag)并用 1 或 0 填充并使用该输出然后过滤,或者甚至创建第二个 data.frame 包含可以是的适当的 doy 范围加入此数据。

在我对 Whosebug 的搜索中,我遇到了以下看起来很接近的问题,但并不是我所需要的:

Conditional filtering based on the level of a factor R

我的实际数据集要大得多,多年来有多棵树(每棵 tree/year 都有不同的观察期,具体取决于地点的海拔等)。我目前正在我的代码中实施 dplyr 包,因此该框架内的答案会很好,但对任何解决方案都会感到满意。

尝试

  indx <- which(!is.na(myData$count))
  myData[seq(indx[1], indx[length(indx)]),]
  #    tree doy count pred
  #5     A  79     0    1
  #6     A  80    NA    1
  #7     A  81    NA    1
  #8     A  82    NA    2
  #9     A  83    NA    2
  #10    A  84     1    2
  #11    A  85    NA    2
  #12    A  86    NA    3
  #13    A  87    NA    3
  #14    A  88    NA    3
  #15    A  89     2    3

如果这是基于组

 ind <- with(myData, ave(!is.na(count), tree,
           FUN=function(x) cumsum(x)>0 & rev(cumsum(rev(x))>0)))
  myData[ind,]
 #   tree doy count pred
 #5     A  79     0    1
 #6     A  80    NA    1
 #7     A  81    NA    1
 #8     A  82    NA    2
 #9     A  83    NA    2
 #10    A  84     1    2
 #11    A  85    NA    2
 #12    A  86    NA    3
 #13    A  87    NA    3
 #14    A  88    NA    3
 #15    A  89     2    3

或使用 na.trim 来自 zoo

 library(zoo)
 do.call(rbind,by(myData, myData$tree, FUN=na.trim))

或使用data.table

 library(data.table)
 setDT(myData)[,.SD[do.call(`:`,as.list(range(.I[!is.na(count)])))] , tree]
 #   tree doy count pred
 #1:    A  79     0    1
 #2:    A  80    NA    1
 #3:    A  81    NA    1
 #4:    A  82    NA    2
 #5:    A  83    NA    2
 #6:    A  84     1    2
 #7:    A  85    NA    2
 #8:    A  86    NA    3
 #9:    A  87    NA    3
 #10:   A  88    NA    3
 #11:   A  89     2    3

我认为您只是希望将行限制在第一个和最后一个非 NA 计数值之间:

myData[seq(min(which(!is.na(myData$count))), max(which(!is.na(myData$count)))),]
#    tree doy count pred
# 5     A  79     0    1
# 6     A  80    NA    1
# 7     A  81    NA    1
# 8     A  82    NA    2
# 9     A  83    NA    2
# 10    A  84     1    2
# 11    A  85    NA    2
# 12    A  86    NA    3
# 13    A  87    NA    3
# 14    A  88    NA    3
# 15    A  89     2    3

dplyr 语法中,按 tree 变量分组:

library(dplyr)
myData %>%
  group_by(tree) %>%
  filter(seq_along(count) >= min(which(!is.na(count))) &
         seq_along(count) <= max(which(!is.na(count))))
# Source: local data frame [11 x 4]
# Groups: tree
# 
#    tree doy count pred
# 1     A  79     0    1
# 2     A  80    NA    1
# 3     A  81    NA    1
# 4     A  82    NA    2
# 5     A  83    NA    2
# 6     A  84     1    2
# 7     A  85    NA    2
# 8     A  86    NA    3
# 9     A  87    NA    3
# 10    A  88    NA    3
# 11    A  89     2    3