r - 按日历月将开始日期和结束日期扩展为一系列开始日期和结束日期

标签 r

给定一个表格

id   start          end
1   22/03/2016    05/06/2016
2   17/08/2016    29/08/2016
3   22/09/2017    25/12/2017

我正在尝试按下表中的日历月拆分

id   start         end
1   22/03/2016    31/03/2016
1   01/04/2016    30/04/2016
1   01/05/2016    05/06/2016
2   17/08/2016    29/08/2016
3   22/09/2017    30/09/2017
3   01/10/2017    31/10/2017
3   01/11/2017    30/11/2017
3   01/12/2017    25/12/2017

我正在尝试修改来自 how to split rows of a dataframe in multiple rows based on start date and end date? 的代码摘录,但我无法正确修改代码。问题一般在有30天的月份,也许很简单,但我对正则表达式还不熟悉。

#sample data
df <- data.frame("starting_date" = as.Date(c("2016-03-22", "2016-08-17", "2017-09-12")),
             "end_date" = as.Date(c("2016-06-05", "2016-08-29", "2017-12-25")),
             col3=c('1','2', '3'))

df1 <- df[,1:2] %>% 
rowwise() %>%
do(rbind(data.frame(matrix(as.character(c(
.$starting_date, 

seq(.$starting_date, .$end_date, by=1)[grep("\\d{4}-\\d{2}-31|\\d{4}-\\d{2}-01", seq(.$starting_date, .$end_date, by=1))],

.$end_date)), ncol=2, byrow=T))
  )
) %>%
data.frame() %>%
`colnames<-`(c("starting_date", "end_date")) %>%
mutate(starting_date= as.Date(starting_date, format= "%Y-%m-%d"),
     end_date= as.Date(end_date, format= "%Y-%m-%d"))

#add temporary columns to the original and expanded date column dataframes
df$row_idx <- seq(1:nrow(df))
df$temp_col <- (year(df$end_date) - year(df$starting_date)) +1
df1 <- cbind(df1,row_idx = rep(df$row_idx,df$temp_col))

#join both dataframes to get the final result
final_df <- left_join(df1,df[,3:(ncol(df)-1)],by="row_idx") %>%
  select(-row_idx) 
final_df

如果有人知道如何修改代码或更好的方法,我将不胜感激。

最佳答案

我们假设问题中的示例输出存在错误,因为第三行跨越两个月的部分时间,因此应分为两行。

定义 Seq,它给定一个 startend 日期变量,生成 startend 列,然后使用 group_by 在每个 id 上运行它:

library(dplyr)
library(zoo)

Seq <- function(start, end) {
  ym <- seq(as.yearmon(start), as.yearmon(end), 1/12)
  starts <- pmax(start, as.Date(ym, frac = 0))
  ends <- pmin(end, as.Date(ym, frac = 1))
  unique(data.frame(start = starts, end = ends))
}

fmt <- "%d/%m/%Y"
DF %>%
  mutate(start = as.Date(start, fmt), end = as.Date(end, fmt)) %>%
  group_by(id) %>%
  do(Seq(.$start, .$end)) %>%
  ungroup

给予:

# A tibble: 9 x 3
     id start      end       
  <int> <date>     <date>    
1     1 2016-03-22 2016-03-31
2     1 2016-04-01 2016-04-30
3     1 2016-05-01 2016-05-31
4     1 2016-06-01 2016-06-05
5     2 2016-08-17 2016-08-29
6     3 2017-09-22 2017-09-30
7     3 2017-10-01 2017-10-31
8     3 2017-11-01 2017-11-30
9     3 2017-12-01 2017-12-25

注意事项

可重现形式的输入DF:

Lines <- "
id   start          end
1   22/03/2016    05/06/2016
2   17/08/2016    29/08/2016
3   22/09/2017    25/12/2017"
DF <- read.table(text = Lines, header = TRUE)

关于r - 按日历月将开始日期和结束日期扩展为一系列开始日期和结束日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53504279/

相关文章:

r - 从列表中加载 r 中的稀疏矩阵

R::tm - 创建术语关联频率表/矩阵并将值添加到树状图中

r - 更改 ggplot 上 ablines 的颜色

r - 如何处理 H2O 算法中的偏态响应

r - 将 Haven_labelled 向量的标签提取为字符串向量

r - 如何使用预测计算 R 中预测数据的标准误差

在 R 中使用 Psych 库运行 Omega

在 R 中使用 MSwM 包复制 Hamilton 的 Markov Switching Model 示例

r - 使用 R 绘图将目录添加到 PDF

R图表转换为html格式,无需其他文件