R:至少连续几年的子数据集

时间:2019-03-27 17:05:02

标签: r aggregate data-cleaning

我有一个具有以下结构的大数据框:

data <- data.frame(id = c(rep("A", 10), rep("B", 10), rep("C", 10), rep("D", 10)), 
                   year = rep(2008:2017, 4), 
                   value = c(rnorm(10, mean = 100, sd = 20), 
                             rnorm(10, mean = 100, sd = 20), 
                             rnorm(4, mean = 100, sd = 20), 
                             rep(NA, 2), 
                             rnorm(4, mean = 100, sd = 20), 
                             rnorm(2, mean = 100, sd = 20), 
                             rep(NA, 8))
                  )

首先,我希望仅在样本数据的十年总数中,仅包含那些具有id数据至少五年的value的数据来清理数据。我当前的方法是使用length聚合数据,将满足要求的id s存储为字符串,然后使用所述字符串对原始数据进行子集化:

data[data$id %in% as.character(subset(aggregate(value ~ id, data = data, FUN = length), value >= 5)$id), ]

这将消除D,因为它仅拥有value两年的数据。

但是,在第二步中,我也想消除C,因为它不提供连续5年的数据,而只提供两个四年的数据。这样做最适合初学者的方法是什么?请注意,如果存在更优雅或更复杂的步骤,我绝不坚持上述步骤。


编辑:

由于围绕原始数据的后续问题,这是dput(head(data))的输出(DSCD对应于idWC02999value,{{ 1}}相同):

year

3 个答案:

答案 0 :(得分:1)

这是dplyr版本。我正在过滤掉丢失的value,以便在group_by之后(必须至少为5)按id进行计数。使用rlediff获得游程长度和值(游程数),其长度必须至少为5,并且至少存在一次。

 data %>%
      filter(!is.na(value)) %>%
      group_by(id) %>%
      filter(
        n() >= 5 &
          any(rle(diff(year))$lengths >= 4 & rle(diff(year))$values >= 1)
      )

答案 1 :(得分:1)

tapply()开始使用R函数的另一种解决方案。对于data$id函数中的每个tapply()!is.na(data$value)产生一个逻辑向量TRUEFALSE并通过function(x)运行。在此函数内部,rle(x)对每个值(TF)的出现没有中断进行计数。例如T,T,T,F,F,T,T将产生3,2,2,这意味着T连续出现3次,然后F两次,然后T两次。在这些计数中,我们仅对表示您数据中非TRUE值的NA计数感兴趣,这由函数的rle(x)$values==T部分来确保。最后,生成包含max.rle长度计数的向量TRUE,并通过ifelse()运行,该向量评估max.rle的长度是否大于0,然后返回{{1向量的}}否则返回零。此条件是必要的,因为如果您有一个包含所有NA的条目,则它将产生max(),并且此-Inf命令将对此进行处理。

ifelse

答案 2 :(得分:0)

第二个条件似乎也照顾第一个条件。计算每个组的年份之间的差异,并查看是否至少有四个1

d = data[!is.na(data$value),]

d[ave(d$year, d$id, FUN = function(x){
    delta = diff(sort(x))
    if ( with(rle(delta), max(lengths[values == 1])) >=4 ){
        rep(TRUE, length(x))
    }else {
        rep(FALSE, length(x))
    }
}) == 1,]
#   id year     value
#1   A 2008 127.41917
#2   A 2009  88.70604
#3   A 2010 107.26257
#4   A 2011 112.65725
#5   A 2012 108.08537
#6   A 2013  97.87751
#7   A 2014 130.23044
#8   A 2015  98.10682
#9   A 2016 140.36847
#10  A 2017  98.74572
#11  B 2008 126.09739
#12  B 2009 145.73291
#13  B 2010  72.22279
#14  B 2011  94.42422
#15  B 2012  97.33357
#16  B 2013 112.71901
#17  B 2014  94.31494
#18  B 2015  46.87089
#19  B 2016  51.19066
#20  B 2017 126.40227

#DATA
    set.seed(42)
    data <- data.frame(id = c(rep("A", 10),
                              rep("B", 10),
                              rep("C", 10),
                              rep("D", 10)),
                       year = rep(2008:2017, 4),
                       value = c(rnorm(10, mean = 100, sd = 20),
                                 rnorm(10, mean = 100, sd = 20),
                                 rnorm(4, mean = 100, sd = 20),
                                 rep(NA, 2),
                                 rnorm(4, mean = 100, sd = 20),
                                 rnorm(2, mean = 100, sd = 20),
                                 rep(NA, 8)))