【问题标题】:how to split rows of a dataframe in multiple rows based on start date and end date?如何根据开始日期和结束日期将数据框的行拆分为多行?
【发布时间】:2018-04-18 19:36:43
【问题描述】:

我有一个包含开始日期和结束日期的数据集,我想根据期间的年份拆分此数据框中的行。以这个数据框为例:

df <- data.frame("starting_date"=as.Date("2015-06-01"),"end_date"=as.Date("2017-09-30"))

应该分成 3 行,一行开始日期 2015-06-01 和结束日期 2015-12-31,一行开始日期 2016-01-01 和结束日期 2016-12-31,一行开始日期 2017-01-01 和结束日期 2017-09-30。知道怎么做吗?最后应该是这样的:

  starting_date   end_date
1    2015-06-01 2015-12-31
2    2016-01-01 2016-12-31
3    2017-01-01 2017-09-30

编辑:我已调整代码以在基础 R 中工作。

EDIT2:我试过了

library(dplyr)
df2 <- df[1,]
df2 <- df[-1,]
for (i in 1:dim(df)[1]){
  for (j in year(df$starting_date[i]):year(df$end_date[i])) 
  {
    df2 <- bind_rows(df2,df[i,])  
  }
}

它可以工作,但速度太慢了。

编辑3: 我设法复制了与所涉及的年数相等的行:

df2 <- df[rep(seq_len(nrow(df)),year(df$end_date)-year(df$starting_date)+1),]

现在我需要另一列这样的年份:

  starting_date   end_date  years
1    2015-06-01 2017-09-30   2015
2    2015-06-01 2017-09-30   2016
3    2015-06-01 2017-09-30   2017

一旦我来到这里,就很容易获得所需的最终结果......关于如何做到这一点的任何想法? 我试图用年份制作一个单独的向量,以便将它与 df2 绑定,但它没有用....

years <- lapply(df,function(x) seq(x[,"starting_date"],length.out=x[,"year"]))

编辑4: 终于在这篇文章的帮助下做到了:R Create a time sequence as xts index based on two columns in data.frame 代码可能可以改进很多,但它可以工作....

diffs <- abs(with(df, year(starting_date)-year(end_date)))+1
df.rep <- df[rep(1:nrow(df), times=diffs), ]
reps <- rep(diffs, times=diffs)

dates.l <- apply(
  df[colnames(df) %in% c("starting_date", "end_date")], 1, 
  function(x) {
    seq(min(year(as.Date(x))), max(year(as.Date(x))))
  })

years <- do.call(c, dates.l)
df.long <- cbind(df.rep, reps, years)
df.long$yearstart <- as.Date(paste0(year(df.long$years),"-01-01"))
df.long$yearend <- as.Date(paste0(year(df.long$years),"-12-31"))
df.long$starting_date2 <- pmax(df.long$starting_date,df.long$yearstart)
df.long$end_date2 <- pmin(df.long$end_date,df.long$yearend)

【问题讨论】:

  • 编写一个在新 R 会话中工作的完整代码示例。 date 不是基本 R 函数...例如,x = as.Date(c("2015-06-01", "2017-09-30")) 似乎很合适。
  • @Frank 从技术上讲...date 是一个基本的 R 函数,但它不接受任何参数。
  • @lmo 啊,有趣。我想我从来没有见过这种情况
  • 是的。我最近在查看timestamp 函数时发现。
  • 我已经编辑了代码,所以它现在可以在基础 R 中使用。

标签: r dataframe


【解决方案1】:

另一种方法可能是

library(dplyr)
library(lubridate)

#sample data
df <- data.frame("starting_date" = as.Date(c("2015-06-01", "2013-06-01", "2016-02-11")),
                 "end_date" = as.Date(c("2017-09-30", "2017-11-11", "2017-01-01")),
                 col3=c('AAA','BBB', 'CCC'),
                 col4=c('33445454','565664', '123'))

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}-12-31|\\d{4}-01-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

输出是:

   starting_date   end_date col3     col4
1     2015-06-01 2015-12-31  AAA 33445454
2     2016-01-01 2016-12-31  AAA 33445454
3     2017-01-01 2017-09-30  AAA 33445454
4     2013-06-01 2013-12-31  BBB   565664
5     2014-01-01 2014-12-31  BBB   565664
6     2015-01-01 2015-12-31  BBB   565664
7     2016-01-01 2016-12-31  BBB   565664
8     2017-01-01 2017-11-11  BBB   565664
9     2016-02-11 2016-12-31  CCC      123
10    2017-01-01 2017-01-01  CCC      123

【讨论】:

  • 在这个例子中效果很好,但实际上我还有多个其他列。如何调整此代码以在输出中包含其他列?
  • @Cuchulainn 请参考我更新的代码。希望对您有所帮助!
  • 几乎 :-) 当结束日期是一年的第一天时它不起作用,比如 2017-01-01。
  • 我们现在试试吧:)
猜你喜欢
  • 1970-01-01
  • 2021-07-21
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多