将日常数据转换为每周数据并处理假期问题

问题描述:

我有一个包含日常数据的数据表。从这张数据表中,我想提取每周三获得的每周数据点。如果星期三是假期,即在数据表中不可用,则应采取下一个可用数据点。 这里,MWE:将日常数据转换为每周数据并处理假期问题

library(data.table) 
df <- data.table(date=as.Date(c("2012-06-25","2012-06-26","2012-06-27","2012-06-28","2012-06-29","2012-07-02","2012-07-03","2012-07-05","2012-07-06","2012-07-09","2012-07-10","2012-07-11","2012-07-12","2012-07-13","2012-07-16","2012-07-17","2012-07-18","2012-07-19","2012-07-20"))) 
df[,weekday:=strftime(date,'%u')] 

与输出:

  date weekday 
1: 2012-06-25  1 
2: 2012-06-26  2 
3: 2012-06-27  3 
4: 2012-06-28  4 
5: 2012-06-29  5 
6: 2012-07-02  1 
7: 2012-07-03  2 
8: 2012-07-05  4 #here the 4th of July was skipped 
9: 2012-07-06  5 
10: 2012-07-09  1 
11: 2012-07-10  2 
12: 2012-07-11  3 
13: 2012-07-12  4 
14: 2012-07-13  5 
15: 2012-07-16  1 
16: 2012-07-17  2 
17: 2012-07-18  3 
18: 2012-07-19  4 
19: 2012-07-20  5 

我期望的结果,在这种情况下将是:

 date weekday 
2012-06-27  3 
2012-07-05  4 
2012-07-11  3 
2012-07-18  3 

有没有获得这比去的更有效的方法逐周通过for循环并检查星期三数据点是否包含在数据中?我觉得必须有更好的方法,所以任何建议都将不胜感激!

工作溶液(以下伊莫的建议)

df[,weekday:=wday(date)] #faster way to get weekdays, careful: numbers increased by 1 vs strftime 
df[,numweek:=floor(as.numeric(date-date[1])/7+1)] #get continuous week numbers extending over end of years 
df[df[,.I[which.min(abs(weekday-4.25))],by=.(numweek)]$V1] #gets result 

下面是使用在该查找最接近的值至3中的(使用.I)的位置的data.table联接(即一个方法不是2,使用which.min(abs(as.integer(weekday)-3.25)))按周使用。

df[df[, .I[which.min(abs(as.integer(weekday)-3.25))], by=week(date)]$V1] 
     date weekday 
1: 2012-06-27  3 
2: 2012-07-05  4 
3: 2012-07-11  3 
4: 2012-07-18  3 

需要注意的是,如果你的真实数据跨越年,那么你需要使用by=.(week(date), year(date))


还要注意的是有一个data.table功能wday即会直接返回一周中的一天整数。它比由strftime返回的字符整数值大1,因此如果您想直接使用它,则需要进行调整。

从单变量的data.table,你会做

df[, weekday := wday(date)] 
df[df[, .I[which.min(abs(weekday-4.25))], by=week(date)]$V1] 
     date weekday 
1: 2012-06-27  4 
2: 2012-07-05  5 
3: 2012-07-11  4 
4: 2012-07-18  4 

注意,日期符合上面。

+0

谢谢@Imo,这很好。剩下的唯一不幸的细节是该方法在年底前的行为(我的数据确实跨越了几年)。 例如:2010-12-29是周三,2011-01-05是周三,两者都不是假期。但是,由于我们按周和年排序,2010年仍有一个开始的一周,因此该方法也会在2010-12-31的最后一天返回。 有没有办法来防止这种情况?删除每年的所有最后日期可能是相当危险的,因为有些人可能仍然需要。 – Daedalus

+0

可能的解决方法是在这个子集之后对日期进行区分(如'dat [,dtDiff:= diff(date)]')。如果该值小于5(或大约),则存在问题。对于这样的行,也许选择星期三(原始设置中的“周日== 3”)。 – lmo