如何按每月最后一天对数据框进行子集化

3

我有一个数据框:

     dates  V1  V2  V3  V4  V5  V6  V7  V8  V9  V10
1999-05-31  66  65  64  63  62  61  60  59  58  57
1999-06-01  67  66  65  64  63  62  61  60  59  58
1999-06-02  68  67  66  65  64  63  62  61  60  59
1999-06-03  69  68  67  66  65  64  63  62  61  60
1999-06-04  70  69  68  67  66  65  64  63  62  61
1999-06-17  79  78  77  76  75  74  73  72  71  70
1999-06-18  80  79  78  77  76  75  74  73  72  71
1999-06-21  81  80  79  78  77  76  75  74  73  72
1999-06-22  82  81  80  79  78  77  76  75  74  73
1999-06-23  83  82  81  80  79  78  77  76  75  74
1999-06-24  84  83  82  81  80  79  78  77  76  75
1999-06-25  85  84  83  82  81  80  79  78  77  76
1999-06-28  86  85  84  83  82  81  80  79  78  77
1999-06-29  87  86  85  84  83  82  81  80  79  78
1999-06-30  88  87  86  85  84  83  82  81  80  79

我希望按每个月的最后一天对上述数据框进行子集化。也就是说,只有日期1999-05-31和1999-06-30会被保留。实际数据框要大得多,每个月的最后日期可能是28日、29日等等。
因此,我希望输出类似于以下内容:
dates   V1  V2  V3  V4  V5  V6  V7  V8  V9  V10
1999-05-31  66  65  64  63  62  61  60  59  58  57 
1999-06-30  88  87  86  85  84  83  82  81  80  79
1999-10-29  175 174 173 172 171 170 169 168 167 166

我试图在zoo或其他软件包中找到一些函数,但没有找到...非常感谢所有的建议!

3个回答

4
假设日期已正确格式化为日期,并且源数据框为x
> library(xts)
> x[endpoints(x$dates, on = "months"), ]
        dates V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1  1999-05-31 66 65 64 63 62 61 60 59 58  57
15 1999-06-30 88 87 86 85 84 83 82 81 80  79

谢谢!那么我如何找到每个月的第一个观测值呢?我可以简单地执行x[endpoints(x$dates, on = "months")+1, ],还是有一些特定的函数可以实现这个功能?最好的问候! - user1665355

3

这将选择月底的最后几天:

df[as.numeric(substr(as.Date(df$dates) + 1, 9, 10))
   < as.numeric(substr(df$dates, 9, 10)), ]

#        dates V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
#1  1999-05-31 66 65 64 63 62 61 60 59 58  57
#15 1999-06-30 88 87 86 85 84 83 82 81 80  79

请注意,此解决方案取决于每天的绝对月数(与您的数据无关)。
如果要选择实际数据中每个月的最后一天,请使用以下命令:
df[c(diff(as.numeric(substr(df$dates, 9, 10))) < 0, TRUE), ]

如果我想找到每个月的第一天而不是最后一天,我是否正确地认为我可以将 df[c(diff(as.numeric(substr(df$dates, 9, 10))) < 0, TRUE), ] 更改为 df[c(diff((as.numeric(substr(df$dates, 9, 10))))+1 > 0, TRUE), ]? :) - user1665355
@user1665355 不需要,只需将 TRUE 的位置改变一下:df[c(TRUE, diff(as.numeric(substr(df$dates, 9, 10))) < 0), ] - Sven Hohenstein
再次感谢您:) 我认为您的解决方案在编写优美代码方面总是最“棒”的。 - user1665355
为什么当order设置为TRUE时,diff(...)会反转并选取每月的第一天呢? :) - user1665355
@user1665355 因为所选元素的位置相对于上次选择增加了一个位置。由于最后几天本质上是紧随第一天的,因此此命令现在选择了数据集中的第一天。 - Sven Hohenstein
显示剩余3条评论

1
这是一个使用 dplyr 的选项:

library(dplyr)

df %>% 
  mutate(dates = as.Date(dates)) %>% 
  mutate(yr_mnth = format(dates, '%Y-%m')) %>% 
  group_by(yr_mnth) %>% 
  filter(dates == max(dates))

# or if you wanted the first observation of each month:
df %>% 
  mutate(dates = as.Date(dates)) %>% 
  mutate(yr_mnth = format(dates, '%Y-%m')) %>% 
  group_by(yr_mnth) %>% 
  filter(dates == min(dates))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接