我有一个可以通过以下代码生成的数据框:
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
中,那将是理想的。
答案 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'))
或任何其他因素