我有一个具有以下结构的大数据框:
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
对应于id
,WC02999
至value
,{{ 1}}相同):
year
答案 0 :(得分:1)
这是dplyr
版本。我正在过滤掉丢失的value
,以便在group_by
之后(必须至少为5)按id进行计数。使用rle
和diff
获得游程长度和值(游程数),其长度必须至少为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)
产生一个逻辑向量TRUE
和FALSE
并通过function(x)
运行。在此函数内部,rle(x)
对每个值(T
,F
)的出现没有中断进行计数。例如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)))