我想分两部分对这样的数据库进行子集:
df <- data.frame(ID = c(1,1,1,1,1,2,2,2,3,3,3),
ins =c(1,2,3,4,5,3,2,4,5,8,9),
Ytx = c(NA,NA,1998,NA,NA,NA,NA,NA,NA,2011,NA))
ID ins Ytx
1 1 NA
1 2 NA
1 3 1998
1 4 NA
1 5 NA
2 3 NA
2 2 NA
2 4 NA
3 5 NA
3 8 2011
3 9 NA
第一个应该看起来像这样(Ytx 出现后的所有值按 ID 分组(:
ID ins Ytx
1 3 1998
1 4 NA
1 5 NA
3 8 2011
3 9 NA
剩下的另一个:
ID ins Ytx
1 1 NA
1 2 NA
2 3 NA
2 2 NA
2 4 NA
3 5 NA
感谢您的支持
在基础 R 中,我们可以使用ave
和split
.这会将数据分为两个列表。第一个是Ytx
值之前的数据,第二个是Ytx
之后的行。
split(df, with(df, ave(!is.na(Ytx), ID, FUN = cumsum)))
#Or if you may have multiple Ytx per ID
#split(df, with(df, ave(!is.na(Ytx), ID, FUN = cumsum)) > 0)
#$`0`
# ID ins Ytx
#1 1 1 NA
#2 1 2 NA
#6 2 3 NA
#7 2 2 NA
#8 2 4 NA
#9 3 5 NA
#$`1`
# ID ins Ytx
#3 1 3 1998
#4 1 4 NA
#5 1 5 NA
#10 3 8 2011
#11 3 9 NA
data.table 的另外两种替代方案:
# convert 'df' tot a 'data.table'
library(data.table)
setDT(df)
# alternative 1
split(df, df[, !!cumsum(!is.na(Ytx)), by = ID]$V1)
# alternative 2
split(df, df[, !!Reduce(`+`, !is.na(Ytx), accumulate = TRUE), by = ID]$V1)
两者都提供:
$`FALSE` ID ins Ytx 1: 1 1 NA 2: 1 2 NA 3: 2 3 NA 4: 2 2 NA 5: 2 4 NA 6: 3 5 NA $`TRUE` ID ins Ytx 1: 1 3 1998 2: 1 4 NA 3: 1 5 NA 4: 3 8 2011 5: 3 9 NA
下面是一个使用data.table
的选项:
setDT(df)[, rn := .I]
idx <- df[,
if (any(!is.na(Ytx)))
.I[seq(.N) >= match(TRUE, !is.na(Ytx))]
, ID]$V1
df[idx]
:
ID ins Ytx rn
1: 1 3 1998 3
2: 1 4 NA 4
3: 1 5 NA 5
4: 3 8 2011 10
5: 3 9 NA 11
df[-idx]
:
ID ins Ytx rn
1: 1 1 NA 1
2: 1 2 NA 2
3: 2 3 NA 6
4: 2 2 NA 7
5: 2 4 NA 8
6: 3 5 NA 9
数据:
library(data.table)
df <- data.frame(ID = c(1,1,1,1,1,2,2,2,3,3,3),
ins =c(1,2,3,4,5,3,2,4,5,8,9),
Ytx = c(NA,NA,1998,NA,NA,NA,NA,NA,NA,2011,NA))