【问题标题】:Conditional filtering of data.frame with preceeding and tailing NA observations具有前后 NA 观察值的 data.frame 条件过滤
【发布时间】:2015-06-24 15:18:26
【问题描述】:

我有一个由数据的观察和模型预测组成的 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 天开始)。

我想有条件地过滤此数据集,以便最终将预测截断到与观察相同的范围内,实际上将所有预测保持在 count 开始和结束之间(即删除 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 范围。

在我对 StackOverflow 的搜索中,我遇到了以下问题,这些问题似乎很接近,但并不是我所需要的:

Select first observed data and utilize mutate

Conditional filtering based on the level of a factor R

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

【问题讨论】:

  • 更新了您在 cmets 中提到的 data.table 选项

标签: r dplyr


【解决方案1】:

我认为您只是希望将行限制在第一个和最后一个非 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

【讨论】:

    【解决方案2】:

    试试

      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
    

    或者使用来自zoona.trim

     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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-17
      • 1970-01-01
      • 2020-11-10
      • 2021-06-20
      • 1970-01-01
      • 2020-01-30
      相关资源
      最近更新 更多