基于一次出现的条件子集
Conditional subset based on one occurrence
我想将这样的数据库分为两部分:
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
感谢您的支持
在 base 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
的选项:
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))
另外两个 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
我想将这样的数据库分为两部分:
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
感谢您的支持
在 base 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
的选项:
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))
另外两个 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