R / lubridate:计算两个时期之间重叠的天数
R / lubridate: Calculate number of overlapping days between two periods
我正在尝试计算两个时间段之间重叠的天数。一个时间段固定在开始日期和结束日期中,另一个时间段记录为数据框中的开始日期和结束日期。
编辑:我正在处理具有发布日期 (df$start) 和取消发布日期 (df$end) 的广告。我想知道的是他们在特定月份在线了多少天(my.start = 2018-01-01,my.end = 2018-08-31)。
library(dplyr)
library(lubridate)
my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")
df <- data.frame(start = c("2018-07-15", "2018-07-20", "2018-08-15", "2018-08-20", "2018-09-01"),
end = c("2018-07-20", "2018-08-05", "2018-08-19", "2018-09-15", "2018-09-15"))
# strings to dates
df <- mutate(df, start = ymd(start), end = ymd(end))
# does not work - calculate overlap in days
df <- mutate(df, overlap = intersect(interval(my.start, my.end), interval(start, end)))
结果应为 0、5、4、12、0 天:
my.start |-------------------------------| my.end
|-----| (0)
|---------| (5)
|----| (4)
|------------------| (12)
|---------------| (0)
在Excel中,我会使用
=MAX(MIN(my.end, end) - MAX(my.start, start) + 1, 0)
但这也不起作用:
# does not work - calculate via min/max
df <- mutate(df, overlap = max(min(my.end, end) - max(my.start, start) + 1, 0))
在我尝试使用 Excel 方法使用日期 as.numeric()
之前,我想知道是否有更聪明的方法来做到这一点。
编辑:实际上,Excel 数字方法似乎也没有两种方法(所有结果均为零):
# does not work - calculate via numeric
ms.num <- as.numeric(my.start)
me.num <- as.numeric(my.end)
df <- df %>%
mutate(s.num = as.numeric(start),
e.num = as.numeric(end),
overlap = max(min(e.num, me.num) - max(s.num, ms.num) + 1, 0))
编辑:@akrun 的方法似乎适用于 ymd 日期。但是,它似乎无法工作 ymd_hms 次:
library(dplyr)
library(lubridate)
library(purrr)
my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")
df <- data.frame(start = c("2018-07-15 10:00:00", "2018-07-20 10:00:00", "2018-08-15 10:00:00", "2018-08-20 10:00:00", "2018-09-01 10:00:00"),
end = c("2018-07-20 10:00:00", "2018-08-05 10:00:00", "2018-08-19 10:00:00", "2018-09-15 10:00:00", "2018-09-15 10:00:00"))
# strings to dates
df <- mutate(df, start = ymd_hms(start), end = ymd_hms(end))
# leads to 0 results
df %>% mutate(overlap = map2(start, end, ~ sum(seq(.x, .y, by = '1 day') %in% seq(my.start, my.end, by = '1 day'))))
我认为您可能 运行 遇到 max
和 min
与 pmax
和 pmin
的问题:
library(dplyr)
df %>%
mutate(overlap = pmax(pmin(my.end, end) - pmax(my.start, start) + 1,0))
start end overlap
1 2018-07-15 2018-07-20 0 days
2 2018-07-20 2018-08-05 5 days
3 2018-08-15 2018-08-19 5 days
4 2018-08-20 2018-09-15 12 days
5 2018-09-01 2018-09-15 0 days
我们可以用pmin/pmax
得到两组vector
的min/max
df %>%
mutate(overlap = ifelse(my.start > end, 0, pmin(my.end, end) -
pmax(my.start, start) + 1))
# start end overlap
#1 2018-07-15 2018-07-20 0
#2 2018-07-20 2018-08-05 5
#3 2018-08-15 2018-08-19 5
#4 2018-08-20 2018-09-15 12
#5 2018-09-01 2018-09-15 0
如果我们想使用与 OP 代码中相同的选项,即 min/max
,使用 rowwise()
或使用 map2
,我们遍历行
library(purrr)
df %>%
mutate(overlap = map2_dbl(start, end, ~
max( as.integer(min(my.end, .y) - max(my.start, .x) + 1), 0)))
注意到OP的实际数据有时间成分。在这种情况下,通过转换为 Date
class
来更改上述解决方案
df %>%
mutate(overlap = map2_dbl(start, end, ~
max(as.integer(min(my.end, as.Date(.y)) - max(my.start, as.Date(.x)) + 1), 0)))
我正在尝试计算两个时间段之间重叠的天数。一个时间段固定在开始日期和结束日期中,另一个时间段记录为数据框中的开始日期和结束日期。
编辑:我正在处理具有发布日期 (df$start) 和取消发布日期 (df$end) 的广告。我想知道的是他们在特定月份在线了多少天(my.start = 2018-01-01,my.end = 2018-08-31)。
library(dplyr)
library(lubridate)
my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")
df <- data.frame(start = c("2018-07-15", "2018-07-20", "2018-08-15", "2018-08-20", "2018-09-01"),
end = c("2018-07-20", "2018-08-05", "2018-08-19", "2018-09-15", "2018-09-15"))
# strings to dates
df <- mutate(df, start = ymd(start), end = ymd(end))
# does not work - calculate overlap in days
df <- mutate(df, overlap = intersect(interval(my.start, my.end), interval(start, end)))
结果应为 0、5、4、12、0 天:
my.start |-------------------------------| my.end
|-----| (0)
|---------| (5)
|----| (4)
|------------------| (12)
|---------------| (0)
在Excel中,我会使用
=MAX(MIN(my.end, end) - MAX(my.start, start) + 1, 0)
但这也不起作用:
# does not work - calculate via min/max
df <- mutate(df, overlap = max(min(my.end, end) - max(my.start, start) + 1, 0))
在我尝试使用 Excel 方法使用日期 as.numeric()
之前,我想知道是否有更聪明的方法来做到这一点。
编辑:实际上,Excel 数字方法似乎也没有两种方法(所有结果均为零):
# does not work - calculate via numeric
ms.num <- as.numeric(my.start)
me.num <- as.numeric(my.end)
df <- df %>%
mutate(s.num = as.numeric(start),
e.num = as.numeric(end),
overlap = max(min(e.num, me.num) - max(s.num, ms.num) + 1, 0))
编辑:@akrun 的方法似乎适用于 ymd 日期。但是,它似乎无法工作 ymd_hms 次:
library(dplyr)
library(lubridate)
library(purrr)
my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")
df <- data.frame(start = c("2018-07-15 10:00:00", "2018-07-20 10:00:00", "2018-08-15 10:00:00", "2018-08-20 10:00:00", "2018-09-01 10:00:00"),
end = c("2018-07-20 10:00:00", "2018-08-05 10:00:00", "2018-08-19 10:00:00", "2018-09-15 10:00:00", "2018-09-15 10:00:00"))
# strings to dates
df <- mutate(df, start = ymd_hms(start), end = ymd_hms(end))
# leads to 0 results
df %>% mutate(overlap = map2(start, end, ~ sum(seq(.x, .y, by = '1 day') %in% seq(my.start, my.end, by = '1 day'))))
我认为您可能 运行 遇到 max
和 min
与 pmax
和 pmin
的问题:
library(dplyr)
df %>%
mutate(overlap = pmax(pmin(my.end, end) - pmax(my.start, start) + 1,0))
start end overlap
1 2018-07-15 2018-07-20 0 days
2 2018-07-20 2018-08-05 5 days
3 2018-08-15 2018-08-19 5 days
4 2018-08-20 2018-09-15 12 days
5 2018-09-01 2018-09-15 0 days
我们可以用pmin/pmax
得到两组vector
的min/max
df %>%
mutate(overlap = ifelse(my.start > end, 0, pmin(my.end, end) -
pmax(my.start, start) + 1))
# start end overlap
#1 2018-07-15 2018-07-20 0
#2 2018-07-20 2018-08-05 5
#3 2018-08-15 2018-08-19 5
#4 2018-08-20 2018-09-15 12
#5 2018-09-01 2018-09-15 0
如果我们想使用与 OP 代码中相同的选项,即 min/max
,使用 rowwise()
或使用 map2
,我们遍历行
library(purrr)
df %>%
mutate(overlap = map2_dbl(start, end, ~
max( as.integer(min(my.end, .y) - max(my.start, .x) + 1), 0)))
注意到OP的实际数据有时间成分。在这种情况下,通过转换为 Date
class
df %>%
mutate(overlap = map2_dbl(start, end, ~
max(as.integer(min(my.end, as.Date(.y)) - max(my.start, as.Date(.x)) + 1), 0)))