选择在数据框中按组首次出现的所有行

时间:2014-11-06 17:19:22

标签: r

我一直在摸不着头脑。我正在重新组织一些不平衡的面板数据(堆叠/长格式)。我需要将所有行保持到包括第一次出现的变量(indc = D)值的组(id),并保留尚未发生的组的行。我希望丢弃的唯一行是每组的行数,其中指标变量的值为第二个或更多(indc = D)。我还需要保留数据框中的所有列。

# Data 
id<-factor(c(1,1,1,2,2,2,2,2, 3,3,3,3,3,3,4,4))
time<-c(1,2,3,1,2,3,4,5, 1,2,3,4,5,6, 1,2)
indc<-factor(c("C","C","D","C","C","C","D","D","C","C","C","C","D","D","C","C"))
var1<-sample(seq(1,8.5, by=0.5))
var2<-c(rep(1,8),rep(0,8))

df<-data.frame(id,time,indc,var1,var2)

我的尝试是使用by和match - 问题是它返回最后一个变量作为匹配和每个组的索引。我坚持如何达到最终的解决方案。

attempt<-by(df, df$id, function(x) {match(unique(x$indc=="D"), x$indc=="D")} )

results<-(do.call("rbind", attempt))

所需的结果是df2 df2<-df[c(1:3,4:7,9:13,15:16),]

如果有人对解决方案有任何想法,我将非常感激。

1 个答案:

答案 0 :(得分:6)

一个选项是使用dplyr按“id”分组,然后计算“indc ==”D“的行的累积总和。然后检查并过滤此cumsum所在的行&lt; = 1。 / p>

require(dplyr)
df %>% group_by(id) %>% filter(cumsum(indc == "D") <= 1)
#Source: local data frame [14 x 5]
#Groups: id
#
#   id time indc var1 var2
#1   1    1    C  1.5    1
#2   1    2    C  1.0    1
#3   1    3    D  7.0    1
#4   2    1    C  2.5    1
#5   2    2    C  3.5    1
#6   2    3    C  6.5    1
#7   2    4    D  3.0    1
#8   3    1    C  2.0    0
#9   3    2    C  7.5    0
#10  3    3    C  6.0    0
#11  3    4    C  8.0    0
#12  3    5    D  8.5    0
#13  4    1    C  4.0    0
#14  4    2    C  4.5    0

评论后编辑#1:

感谢@ akrun的评论,下面是两个如何分组的选项:

选项1:使用基数R:

df[with(df, ave(indc=='D', id, FUN=function(x) cumsum(x)<=1)),]

选项2:使用data.table:

require(data.table)
setDT(df)[,.SD[cumsum(indc=='D')<=1], by=id]

归功于@akrun


在OP评论后编辑#2:

例如,如果第一个“D”发生,然后在同一组中出现“C”(或其他字母)的另一行,则不清楚如何删除行。如果在第一次“D”发生后发生,我的初始答案会保持这样一排。要在第一个“D”出现后更改该行为并删除所有行,您只需在代码中添加另一个cumsum,如下所示(对于下面显示的修改数据):

df %>% group_by(id2) %>% filter(cumsum(cumsum(indc2 == "D")) <= 1L)
#Source: local data frame [13 x 5]
#Groups: id2
#
#   id2 time2 indc2 var1 var2
#1    1     1     C  8.0    1
#2    1     2     C  5.0    1
#3    1     3     D  7.0    1
#4    2     1     C  1.0    1
#5    2     2     C  2.0    1
#6    2     3     D  9.0    1
#7    3     1     C  4.5    0
#8    3     2     C  3.0    0
#9    3     3     C  7.5    0
#10   3     4     C  1.5    0
#11   3     5     D  4.0    0
#12   4     1     C  6.0    0
#13   4     2     C  6.5    0

数据

df <- structure(list(id2 = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L), .Label = c("1", "2", 
"3", "4"), class = "factor"), time2 = c(1, 2, 3, 4, 1, 2, 3, 
4, 5, 1, 2, 3, 4, 5, 6, 1, 2), indc2 = structure(c(1L, 1L, 2L, 
1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L), .Label = c("C", 
"D"), class = "factor"), var1 = c(8, 5, 7, 8.5, 1, 2, 9, 3.5, 
2.5, 4.5, 3, 7.5, 1.5, 4, 5.5, 6, 6.5), var2 = c(1, 1, 1, 1, 
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("id2", "time2", 
"indc2", "var1", "var2"), row.names = c(NA, -17L), class = "data.frame")

> df
   id2 time2 indc2 var1 var2
1    1     1     C  8.0    1
2    1     2     C  5.0    1
3    1     3     D  7.0    1
4    1     4     C  8.5    1    <-- this row will also be removed now
5    2     1     C  1.0    1
6    2     2     C  2.0    1
7    2     3     D  9.0    1
8    2     4     D  3.5    1
9    2     5     D  2.5    0
10   3     1     C  4.5    0
11   3     2     C  3.0    0
12   3     3     C  7.5    0
13   3     4     C  1.5    0
14   3     5     D  4.0    0
15   3     6     D  5.5    0
16   4     1     C  6.0    0
17   4     2     C  6.5    0