我有一个数据帧,其中包含睡眠数据,具有几个睡眠增量,其中一列用于睡眠的开始,一列用于睡眠的结束。 对于某些行,开始时间在前一天,结束时间在第二天。 我想将这些行分成两行,第一行包含开始时间,直到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
解决方案将非常有帮助。
答案 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()
是其data.table版本,在此使用。 AFAIK,没有等效的dplyr。
首先,我们需要创建一天开始和结束时间的向量。对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")