【问题标题】:Group consecutive working day dates (excluding weekends and holidays)团体连续工作日日期(不包括周末和节假日)
【发布时间】:2021-10-02 18:49:59
【问题描述】:

我有不同人的数据 (ID)、他们工作的日期 (Date) 以及他们每个日期的工作小时数 (Hours)。

周一至周五被视为工作日。对于每个 ID,我想将连续的工作日分组。在确定工作日是否连续时,应省略周末和节假日。

一些例子:

如果一个人在周一、周二和周三工作,然后跳过周四并在周五再次工作,则周一至周三被视为一组,周五被视为另一组。

如果一个人每周在周四和周五工作,下周周一和周二工作,那么这四天应该在同一个组中。因此,在检查工作天是否连续时,会省略周末的天数。

如果一周的周一至周五和下周的周一至周五,那么我会将这整整两周视为连续工作日。

我还想考虑美国的常见假期(例如新年),因此 2020 年 12 月 31 日至 2021 年 1 月 4 日仍将算作连续工作日。

创建分组变量后,我想对每个组的工作时间求和。

示例数据:

df1 = structure(list(ID = c(1, 1, 1, 1, 2, 2, 3, 3, 
3, 3), Date = structure(c(18781, 18782, 18785, 18750, 18687, 
18688, 18626, 18627, 18631, 18634), class = "Date"), Hours = c(8, 
8, 8, 16, 8, 8, 8, 8, 8, 8)), row.names = c(NA, -10L), class = "data.frame")


  ID       Date Hours
1  1 2021-06-03     8
2  1 2021-06-04     8
3  1 2021-06-07     8
4  1 2021-05-03    16
5  2 2021-03-01     8
6  2 2021-03-02     8
7  3 2020-12-30     8
8  3 2020-12-31     8
9  3 2021-01-04     8
10 3 2021-01-07     8

我想象我的输出看起来像这样:

 ID      Date1      Date2 Hours
1 1 2021-06-03 2021-06-07    24
# the weekend, June 5-6, is omitted
# when the group of consecutive working days is created
 
2 1 2021-05-03 2021-05-03    16
3 2 2021-03-01 2021-03-02    16

4 3 2020-12-30 2021-01-04    24
# the public holiday (Jan 1) and the weekend (Jan 2-3) are omitted
   
5 3 2021-01-07 2021-01-07     8

我的首要任务是至少弄清楚连续工作周,假期部分将是一个额外的奖励。

【问题讨论】:

    标签: r date


    【解决方案1】:

    您可以使用RQuantLib::businessDaysBetween。对于每个 ID (by = ID),计算每行之间的工作日数,即提供“滞后”(head(Date, -1)) 和“领先”(tail(Date, -1)) 向量作为fromto 日期。选择一个相关的calendar(参见?businessDaysBetween中的详细信息

    对于每个 ID 和连续工作日 (by = .(ID, g = cumsum(d != 1L))),选择第一个和最后一个日期 (from = Date[1]to = Date[.N]) 并将小时数相加 (sum(Hours))

    library(data.table)
    library(RQuantLib)
    setDT(df1)
    
    df1[ , d := c(1, businessDaysBetween(calendar = "UnitedStates",
                                         from = head(Date, -1), to = tail(Date, -1))),
        by = ID]
    
    df1[ , .(from = Date[1], to = Date[.N], Hours = sum(Hours)),
        by = .(ID, g = cumsum(d != 1L))]
    
    #    ID g       from         to Hours
    # 1:  1 0 2021-06-03 2021-06-07    24
    # 2:  1 1 2021-05-03 2021-05-03    16
    # 3:  2 1 2021-03-01 2021-03-02    16
    # 4:  3 1 2020-12-30 2021-01-04    24
    # 5:  3 2 2021-01-07 2021-01-07     8
    

    更复杂的解决方案(pre-businessDaysBetween):

    在每个 ID (df1[ , .(Date = seq(min(Date), max(Date), by = "1 day")), by = ID]) 中创建完整的日期序列。加入关于 ID 和日期的原始数据 (df1[..., on =.(ID, Date))。对于原始数据中不存在的日期,即(最初)连续天之间的间隔,小时将为NA

    在每个 ID (by = ID) 中,根据缺失的小时数 (rleid(is.na(Hours))) 创建一个运行长度索引。对于缺少 Hours (d[is.na(Hours)) 的行,即原始时间序列中的间隔,对于每个 ID 和运行 (by = .(ID, r)),检查 all 日期是周末 (wday(Date) %in% c(1, 7)) 还是 (@987654345 @) 一个公共假期* (Date %in% as.Date(holidayNYSE(unique(year(Date))))),并创建一个索引变量 ix。

    对于原始行和周末/节假日间隔 (!is.na(Hours) | ix),创建连续日期的分组变量 (g = cumsum(c(TRUE, diff(Date) != 1L)))。对于每个 ID 和连续日期 (by = .(ID, g)),选择第一个和最后一个日期 (from = Date[1], to = Date[.N]) 并将小时数相加 (sum(Hours, na.rm = TRUE))

    library(data.table)
    library(timeDate)
    setDT(df1)
    
    d = df1[df1[ , .(Date = seq(min(Date), max(Date), by = "1 day")), by = ID],
        on = .(ID, Date)]
    
    d[ , r := rleid(is.na(Hours)), by = ID]
    
    d[is.na(Hours), ix := all(
        wday(Date) %in% c(1, 7) |
          Date %in% as.Date(holidayNYSE(unique(year(Date)))))
    , by = .(ID, r)]
    
    
    d[!is.na(Hours) | ix, .(Date, Hours, g = cumsum(c(TRUE, diff(Date) != 1L))),
      by = ID][
      , .(from = Date[1], to = Date[.N],
        Hours = sum(Hours, na.rm = TRUE)),
      by = .(ID, g)] 
    
    #    ID g       from         to Hours
    # 1:  1 1 2021-05-03 2021-05-03    16
    # 2:  1 2 2021-06-03 2021-06-07    24
    # 3:  2 1 2021-03-01 2021-03-02    16
    # 4:  3 1 2020-12-30 2021-01-04    24
    # 5:  3 2 2021-01-07 2021-01-07     8
    

    *请参阅timeDate manual 了解假期的其他定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      • 2016-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多