包含两个单独日期的单独行,分别位于午夜前后

时间:2018-09-27 13:40:12

标签: r date dplyr

我有一个数据帧,其中包含睡眠数据,具有几个睡眠增量,其中一列用于睡眠的开始,一列用于睡眠的结束。 对于某些行,开始时间在前一天,结束时间在第二天。 我想将这些行分成两行,第一行包含开始时间,直到23:59:59,第二行包含00:00:00,直到结束时间。

例如:

# A tibble: 6 x 3
  sleepdatestarttime  sleepdateendtime    sleepstage 
  <dttm>              <dttm>              <chr>              
1 2018-03-02 23:31:00 2018-03-02 23:54:00 rem                
2 2018-03-02 23:54:00 2018-03-02 23:55:00 light              
3 2018-03-02 23:55:00 2018-03-03 00:02:00 wake               
4 2018-03-03 00:02:00 2018-03-03 00:03:30 light              
5 2018-03-03 00:03:30 2018-03-03 00:23:30 deep               
6 2018-03-03 00:23:30 2018-03-03 02:58:00 light               

,所需的输出是:

# A tibble: 6 x 3
  sleepdatestarttime  sleepdateendtime    sleepstage 
  <dttm>              <dttm>              <chr>      
1 2018-03-02 23:31:00 2018-03-02 23:54:00 rem         
2 2018-03-02 23:54:00 2018-03-02 23:55:00 light       
**3 2018-03-02 23:55:00 2018-03-02 23:59:59 wake 
4 2018-03-03 00:00:00 2018-03-03 00:01:59 wake** 
5 2018-03-03 00:02:00 2018-03-03 00:03:30 light       
6 2018-03-03 00:03:30 2018-03-03 00:23:30 deep        
7 2018-03-03 00:23:30 2018-03-03 02:58:00 light 

dplyr解决方案将非常有帮助。

2 个答案:

答案 0 :(得分:0)

这是一个可能的解决方案,但仅使用基数R,而不使用dplyr。我将所有时间都转换为UTC,以避免时间转换出现问题。 (请参阅相关答案change time zone in R without it returning to original time zone

请注意,此解决方案在sleepdatestarttime之前对整个数据框进行重新排序,因此,如果同一天有多个人,则最后一行的订单功能需要修改。

df<-read.table(header=TRUE, text="sleepdatestarttime  sleepdateendtime    sleepstage 
'2018-03-02 23:31:00' '2018-03-02 23:54:00' rem                
'2018-03-02 23:54:00' '2018-03-02 23:55:00' light              
'2018-03-02 23:55:00' '2018-03-03 00:02:00' wake               
'2018-03-03 00:02:00' '2018-03-03 00:03:30' light              
'2018-03-03 00:03:30' '2018-03-03 00:23:30' deep               
'2018-03-03 00:23:30' '2018-03-03 02:58:00' light")

df$sleepdatestarttime<-as.POSIXct(as.character(df$sleepdatestarttime), tz="UTC")
df$sleepdateendtime<-as.POSIXct(as.character(df$sleepdateendtime), tz="UTC")

    #find rows across days
rows<-which(as.Date(df$sleepdatestarttime) !=as.Date(df$sleepdateendtime))

#create the new rows
nstart<-data.frame(sleepdatestarttime= df$sleepdatestarttime[rows], 
                   sleepdateendtime= as.POSIXct(paste(as.Date(df$sleepdatestarttime[rows]), "23:59:59"), tz="UTC"),
                   sleepstage=df$sleepstage[rows])

nend<-data.frame(sleepdatestarttime= as.POSIXct(paste(as.Date(df$sleepdateendtime[rows]), "00:00:00"), tz="UTC"), 
                 sleepdateendtime= df$sleepdateendtime[rows],
                 sleepstage=df$sleepstage[rows])

#substitute in the new start rows
df[rows,]<-nstart
#tack on the new ending rows
df<-rbind(df, nend)
#resort the dataframe
df<-df[order(df$sleepdatestarttime ),]

答案 1 :(得分:0)

这是基因组学中的常见问题。为此,BioConductor上的IRanges软件包具有findOverlaps()功能。 foverlaps()是其版本,在此使用。 AFAIK,没有等效的

首先,我们需要创建一天开始和结束时间的向量。对foverlaps()的调用返回所有可能的重叠类型。最后,调整开始时间和结束时间以符合预期结果。

library(data.table)
library(lubridate)
day_seq <- setDT(df)[, .(day_start = seq(
  floor_date(min(sleepdatestarttime), "day"), 
  ceiling_date(max(sleepdateendtime), "day"), "day"))][
    , day_end := day_start + days(1)]
setkey(day_seq, day_start, day_end)

foverlaps(
  df, day_seq, by.x = c("sleepdatestarttime", "sleepdateendtime"), nomatch = 0L)[
    , `:=`(sleepdatestarttime = pmax(sleepdatestarttime, day_start),
           sleepdateendtime   = pmin(sleepdateendtime, day_end - seconds(1)))][
             , c("day_start", "day_end") := NULL][]
   i  sleepdatestarttime    sleepdateendtime sleepstage
1: 1 2018-03-02 23:31:00 2018-03-02 23:54:00        rem
2: 2 2018-03-02 23:54:00 2018-03-02 23:55:00      light
3: 3 2018-03-02 23:55:00 2018-03-02 23:59:59       wake
4: 3 2018-03-03 00:00:00 2018-03-03 00:02:00       wake
5: 4 2018-03-03 00:02:00 2018-03-03 00:03:30      light
6: 5 2018-03-03 00:03:30 2018-03-03 00:23:30       deep
7: 6 2018-03-03 00:23:30 2018-03-03 02:58:00      light

数据

df <- readr::read_table("i  sleepdatestarttime  sleepdateendtime    sleepstage 
1 2018-03-02 23:31:00 2018-03-02 23:54:00 rem                
2 2018-03-02 23:54:00 2018-03-02 23:55:00 light              
3 2018-03-02 23:55:00 2018-03-03 00:02:00 wake               
4 2018-03-03 00:02:00 2018-03-03 00:03:30 light              
5 2018-03-03 00:03:30 2018-03-03 00:23:30 deep               
6 2018-03-03 00:23:30 2018-03-03 02:58:00 light")