选择子组的第一行和最后一行

时间:2016-04-07 07:21:05

标签: r dplyr

我有一个可以通过以下代码生成的数据框:

dt=data.frame(Time=seq.Date(from =as.Date("2000/1/31"),by="month",length.out = 70),
          ID=rep(c(1,2,3,4,5,6,7)),
          Category=rep(c("Satisfactory","Marginal","Satisfactory","Marginal","Satisfactory")))
dt=dt[with(dt,order(ID)),]
dt

我想找出ID属于某个类别的时间段。期望的结果如下所示:

           Time    ID     Category
1  2000-01-31     1 Satisfactory
2  2001-03-31     1 Satisfactory
3  2001-10-31     1     Marginal
4  2002-05-31     1     Marginal
5  2002-12-31     1 Satisfactory
6  2004-03-02     1 Satisfactory
7  2004-10-01     1     Marginal
8  2005-05-01     1     Marginal
9  2000-03-02     2     Marginal
10 2000-10-01     2     Marginal

如果代码在dplyr中,那将是理想的。

3 个答案:

答案 0 :(得分:3)

我们可以使用data.table。将'data.frame'转换为'data.table',按照'Category'(rleid(Category))的游程长度id进行分组,得到第一个和最后一个元素的行索引,提取该列({{ 1}})并对数据集进行子集化。

$V1

library(data.table) i1 <- setDT(df1)[, .I[c(1, .N)] , by = rleid(Category)]$V1 df1[i1] # Time ID Category # 1: 30/06/2014 1 Satisfactory # 2: 31/10/2014 1 Satisfactory # 3: 30/11/2014 1 Unsatisfactory # 4: 31/05/2015 1 Unsatisfactory # 5: 30/06/2015 1 Marginal # 6: 31/08/2015 1 Marginal # 7: 30/09/2015 1 Satisfactory # 8: 30/11/2015 1 Satisfactory # 9: 30/06/2013 2 Marginal #10: 31/05/2014 2 Marginal 的另一个选项是使用base R创建逻辑索引,然后使用它来对数据集进行子集

ave

df1[with(df1, as.logical(ave(seq_along(Category), cumsum(c(TRUE,Category[-1]!=Category[-nrow(df1)])), FUN = function(x) x %in% c(head(x,1), tail(x,1))) )),] # Time ID Category #1 30/06/2014 1 Satisfactory #5 31/10/2014 1 Satisfactory #6 30/11/2014 1 Unsatisfactory #12 31/05/2015 1 Unsatisfactory #13 30/06/2015 1 Marginal #15 31/08/2015 1 Marginal #16 30/09/2015 1 Satisfactory #18 30/11/2015 1 Satisfactory #19 30/06/2013 2 Marginal #23 31/05/2014 2 Marginal

dplyr

答案 1 :(得分:3)

如果您想使用dplyr逻辑(即使仍然需要来自rleid的{​​{1}}函数),这是一个解决方案。

data.table

答案 2 :(得分:0)

基础解决方案:

aggregate(df$Time,FUN=min,by=list(df$ID,df$Category))

可以用作过滤器。

和max:

相同
aggregate(df$Time,FUN=max,by=list(df$ID,df$Category))

所以

rbind(aggregate(df$Time,FUN=min,by=list(df$ID,df$Category)),
      aggregate(df$Time,FUN=max,by=list(df$ID,df$Category)))

会给你:

  Group.1        Group.2          x
1       1       Marginal 2015-06-30
2       2       Marginal 2013-06-30
3       1   Satisfactory 2014-06-30
4       1 Unsatisfactory 2014-11-30
5       1       Marginal 2015-08-31
6       2       Marginal 2014-05-31
7       1   Satisfactory 2015-11-30
8       1 Unsatisfactory 2015-05-31

你可以改名字等等。我希望我能帮到你。 您是否有机会希望将年份包括在内?我可以从

看到这一点
30/06/2014  1   Satisfactory
31/10/2014  1   Satisfactory
30/09/2015  1   Satisfactory
30/11/2015  1   Satisfactory

因此您可以将年份添加到&#39; by&#39;简单:by=list(df$ID,df$Category,format(df$Time,'%Y')) 或任何其他因素