r语言 - 基于一个匹配项的条件子集



我想分两部分对这样的数据库进行子集:

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 中,我们可以使用avesplit.这会将数据分为两个列表。第一个是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))

最新更新