Lubridate - 查找间隔和日期之间的重叠时间
Lubridate - Find overlap time between interval and a date
我有一个以日期时间格式开始和结束的数据框,如下所示:
shift_time <- data.frame(
started_at = c("2019-09-01 02:00:00 AEST", "2019-09-02 05:00:00 AEST", "2019-11-04 20:00:00 AEDT"),
ended_at = c("2019-09-01 11:30:00 AEST", "2019-09-02 19:00:00 AEST", "2019-11-05 04:00:00 AEDT")
)
我有另一个数据框 public 假期日期如下:
public_holidays <- data.frame(
hol_name = c('Cup Day', 'Christmas'),
date = c("2019-11-05", "2019-12-25")
)
我想用一个新列更新 shift_time df,记录在 public 假期发生的轮班小时数 - 即,我想计算重叠(在小时)在班次间隔和适用的任何 public 假期之间。在上面的示例中,新变量的预期值为 0、0、4。
有没有不涉及创建大量新变量(例如,difftimes、间隔、匹配日期)的方法来做到这一点?
有内置的 lubridate::int_overlaps
但只有 return 是合乎逻辑的,而不是它们重叠多长时间。幸运的是,intersection
函数有一个用于 Interval
对象的方法。唯一的技巧是,如果没有重叠,它是return长度-NA
,而不是长度-0
。所以我们可以像这样总结这个逻辑:
library(lubridate)
int_overlaps_numeric <- function (int1, int2) {
stopifnot(c(is.interval(int1), is.interval(int2)))
x <- intersect(int1, int2)@.Data
x[is.na(x)] <- 0
as.duration(x)
}
这构造了作为重叠的区间,然后提取它的长度(以秒为单位)。如果是 NA
,则将其更改为零,然后 return。 as.duration
只是给我们漂亮的打印。现在你只需要给它两个间隔:
int1 <- as.interval(5, Sys.time())
int2 <- as.interval(5, Sys.time()+3)
int_overlaps_numeric(int1, int2)
"1.99299597740173s"
所以你需要把你所有的假期都变成间隔,把你所有的班次都变成间隔。假设您想将这些重叠与 shift_time
数据框中的其他数据相关联,因此我们将使用 dplyr
在那里完成我们的所有工作。然而,你想检查 each 相对于 all 假期的向量,所以我们应该添加另一个辅助函数(使用 purrr::map
) .
library(dplyr)
library(purrr)
check_shift_against_holidays <- function(shift, holidays) {
map(shift, ~sum(int_overlaps_numeric(.x, holidays))) %>%
unlist() %>%
as.duration()
}
此函数采用两个间隔向量。对于第一个向量的每个元素,它计算与第二个向量的每个元素的重叠,然后将它们相加。然后将其从列表转换回向量,并将其重新分类为 duration
以进行漂亮打印。这里需要注意的是,如果 holidays
向量中有任何重叠,这些小时数将被重复计算。
# days(1) since the holiday lasts all day
holiday_intervals <- as.interval(days(1), ymd(public_holidays$date))
shift_time %>%
mutate(
shift = interval(ymd_hms(started_at), ymd_hms(ended_at)),
holiday_hours = check_shift_against_holidays(shift, holiday_intervals)
)
started_at ended_at shift holiday_hours
1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 2019-09-01 02:00:00 UTC--2019-09-01 11:30:00 UTC 0s
2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 2019-09-02 05:00:00 UTC--2019-09-02 19:00:00 UTC 0s
3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 2019-11-04 20:00:00 UTC--2019-11-05 04:00:00 UTC 14400s (~4 hours)
如果您真的反对创建任何新的中间变量:
shift_time %>%
mutate(
holiday_hours = check_shift_against_holidays(
ymd_hms(started_at) %--% ymd_hms(ended_at),
holiday_intervals
)
)
started_at ended_at holiday_hours
1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 0s
2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 0s
3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 14400s (~4 hours)
我有一个以日期时间格式开始和结束的数据框,如下所示:
shift_time <- data.frame(
started_at = c("2019-09-01 02:00:00 AEST", "2019-09-02 05:00:00 AEST", "2019-11-04 20:00:00 AEDT"),
ended_at = c("2019-09-01 11:30:00 AEST", "2019-09-02 19:00:00 AEST", "2019-11-05 04:00:00 AEDT")
)
我有另一个数据框 public 假期日期如下:
public_holidays <- data.frame(
hol_name = c('Cup Day', 'Christmas'),
date = c("2019-11-05", "2019-12-25")
)
我想用一个新列更新 shift_time df,记录在 public 假期发生的轮班小时数 - 即,我想计算重叠(在小时)在班次间隔和适用的任何 public 假期之间。在上面的示例中,新变量的预期值为 0、0、4。
有没有不涉及创建大量新变量(例如,difftimes、间隔、匹配日期)的方法来做到这一点?
有内置的 lubridate::int_overlaps
但只有 return 是合乎逻辑的,而不是它们重叠多长时间。幸运的是,intersection
函数有一个用于 Interval
对象的方法。唯一的技巧是,如果没有重叠,它是return长度-NA
,而不是长度-0
。所以我们可以像这样总结这个逻辑:
library(lubridate)
int_overlaps_numeric <- function (int1, int2) {
stopifnot(c(is.interval(int1), is.interval(int2)))
x <- intersect(int1, int2)@.Data
x[is.na(x)] <- 0
as.duration(x)
}
这构造了作为重叠的区间,然后提取它的长度(以秒为单位)。如果是 NA
,则将其更改为零,然后 return。 as.duration
只是给我们漂亮的打印。现在你只需要给它两个间隔:
int1 <- as.interval(5, Sys.time())
int2 <- as.interval(5, Sys.time()+3)
int_overlaps_numeric(int1, int2)
"1.99299597740173s"
所以你需要把你所有的假期都变成间隔,把你所有的班次都变成间隔。假设您想将这些重叠与 shift_time
数据框中的其他数据相关联,因此我们将使用 dplyr
在那里完成我们的所有工作。然而,你想检查 each 相对于 all 假期的向量,所以我们应该添加另一个辅助函数(使用 purrr::map
) .
library(dplyr)
library(purrr)
check_shift_against_holidays <- function(shift, holidays) {
map(shift, ~sum(int_overlaps_numeric(.x, holidays))) %>%
unlist() %>%
as.duration()
}
此函数采用两个间隔向量。对于第一个向量的每个元素,它计算与第二个向量的每个元素的重叠,然后将它们相加。然后将其从列表转换回向量,并将其重新分类为 duration
以进行漂亮打印。这里需要注意的是,如果 holidays
向量中有任何重叠,这些小时数将被重复计算。
# days(1) since the holiday lasts all day
holiday_intervals <- as.interval(days(1), ymd(public_holidays$date))
shift_time %>%
mutate(
shift = interval(ymd_hms(started_at), ymd_hms(ended_at)),
holiday_hours = check_shift_against_holidays(shift, holiday_intervals)
)
started_at ended_at shift holiday_hours 1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 2019-09-01 02:00:00 UTC--2019-09-01 11:30:00 UTC 0s 2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 2019-09-02 05:00:00 UTC--2019-09-02 19:00:00 UTC 0s 3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 2019-11-04 20:00:00 UTC--2019-11-05 04:00:00 UTC 14400s (~4 hours)
如果您真的反对创建任何新的中间变量:
shift_time %>%
mutate(
holiday_hours = check_shift_against_holidays(
ymd_hms(started_at) %--% ymd_hms(ended_at),
holiday_intervals
)
)
started_at ended_at holiday_hours 1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 0s 2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 0s 3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 14400s (~4 hours)