确定日期序列中的第三个星期五

Identify 3rd Friday in a sequence of Dates

下面的代码有一个日期列表,如果日期是该月的最后一天,对于数据集中的所有日期(不在日历上),那么它将日期标记为该月的最后一天月

data = data.frame(day  = seq(as.Date("2014-01-01"),as.Date("2016-05-10"),"day"), weekday = weekdays ( seq(as.Date("2014-01-01"),as.Date("2016-05-10"),"day")))
excludeDays <- c("Saturday", "Sunday")
data <- subset(data, !weekdays(data$day) %in% excludeDays) #exclude weekend
setDT(data)
data[, LastDayInMonth := day == max(day), by = list(year(day),month(day)  )]
head(data,100)

我还需要在数据中添加一个标记 (TRUE/FALSE) 任何星期五的列,即该月的第 3 个星期五。有什么想法吗?

例如 2014-01-17、2014-02-21、......2014-05-16 等......是第三个星期五。

谢谢。

试试这个 - 没有 data.table:

library(lubridate)
library(dplyr)
data <- data.frame(day  = seq(as.Date("2014-01-01"),
                              as.Date("2016-05-10"),"day"),
                  weekday = weekdays(seq(as.Date("2014-01-01"),
                                         as.Date("2016-05-10"),"day")))
data$year_month <- floor_date(data$day, unit = 'month')
fri3 <- filter(data, weekday == 'Friday') %>%
  group_by(year_month) %>% slice(3)

data$Third_Fri <- data$day %in% fri3$day

您可以稍后删除 year_month

另一种方法:

data[, is3Friday:=cumsum(weekday=="Friday"), by=substring(day, 1, 7)]
data[, is3Friday:=ifelse(weekday=="Friday" & is3Friday==3, TRUE, FALSE)]

data[is3Friday==TRUE]
           day weekday LastDayInMonth is3Friday
 1: 2014-01-17  Friday          FALSE      TRUE
 2: 2014-02-21  Friday          FALSE      TRUE
 3: 2014-03-21  Friday          FALSE      TRUE
 4: 2014-04-18  Friday          FALSE      TRUE
 5: 2014-05-16  Friday          FALSE      TRUE
 6: 2014-06-20  Friday          FALSE      TRUE
data[, numWeek := 1:.N, by = .(year(day), month(day), weekday)]

data[numWeek == 3 & weekday == "Friday"]

或添加为列:

data[, is3rdFriday := numWeek == 3 & weekday == "Friday"]

如果您要查找日历中的第 3 个星期五,而不是数据中的第 3 个星期五,那么您可以做得更简单:

data[, is3rdFriday := (mday(day) - 1) %/% 7 + 1 == 3 & weekday == "Friday"]

要涵盖数据在月中开始时的极端情况,您可以尝试这样做:

occ <- 3L   # 3rd occurrence of selected weekday
data[, ThirdFridayInMonth := weekday == "Friday" &
       as.integer(day - lubridate::floor_date(day, "month")) %/% 7L + 1L == occ]

这也适用于该月的其他工作日,例如,在每个第一个星期一进行标记。

编辑: 要求的解释。

基本思路是每个月的第一个星期五必须是每个月的前 7 天之一,第二个星期五必须是第 8 到 14 天之一,依此类推。因此,lubridate::floor_date(day, "month") 计算出 day 所在月份的第一天。现在,您构建一个需要转换为 integerdifftime 对象的差异.如果 day 恰好是一个月的第一天,则为 0。现在你使用整数除法 %/% 其中 returns 0 代表一个月的前 7 天,1 代表第二个 7 天,等等。然后通过添加 1.

进行调整

编辑 2: 改进代码

在写解释的时候,我认识到代码可以进一步改进。

我们可以直接使用月中的第几天,这样可以避免计算日期差异和随后的整数转换:

data[, ThirdFridayInMonth := weekday == "Friday" &
       (mday(day) - 1) %/% 7L + 1L == occ]

在这里,我使用 mdaydata.table 包的一部分)而不是 as.integer(format(day, "%d"))