gpt4 book ai didi

如果工作日位于日期范围之间,R data.table 将使用逻辑值设置新列

转载 作者:行者123 更新时间:2023-12-04 09:38:10 25 4
gpt4 key购买 nike

我有一个 data.table 对象,其中包含两个 date 列:fromto。我想创建一个新列来确定特定工作日是否在日期范围之间。

[数据]

library(data.table)
set.seed(1)
DT <- data.table(from=seq.Date(Sys.Date(), Sys.Date()+100, by="day"))[, to:=from+sample(10, 1), by=1:nrow(DT)][, from_wd:=wday(from)][, to_wd:=wday(to)]

> head(DT)
from to from_wd to_wd
1: 2015-08-06 2015-08-10 5 2
2: 2015-08-07 2015-08-10 6 2
3: 2015-08-08 2015-08-18 7 3
4: 2015-08-09 2015-08-16 1 1
5: 2015-08-10 2015-08-13 2 5
6: 2015-08-11 2015-08-13 3 5

[我的方法]

在本例中,我想添加一个新的 booleanflag,如果星期三在 范围内,则返回 TRUE >[从,到]

这是我的尝试:

DT[, flag:=0][DT[, .I[4 %in% unique(wday(seq.Date(from, to, by="day")))], by=1:nrow(DT)][[1]], flag:=1]

> table(DT$flag)

0 1
21 80

[问题]

代码运行需要一些时间,并且可以想象,如果 nrow(DT) 变大,则需要更多时间。

我的问题是:有更好的方法吗?在速度和代码可读性方面更好(我相信我的代码根本不直观)。

最佳答案

这是一种方法:

next_wday <- function(d,wd=4L){
wddiff = wd - wday(d)
d + wddiff + (wddiff < 0L)*7L
}


DT[, flag2 := +(next_wday(from) <= to)]

# test:
DT[,table(flag,flag2)]
# flag2
# flag 0 1
# 0 44 0
# 1 0 57

这个想法是您将与下周四进行比较**。替换行可以用多种不同的方式编写。

基准

OP 提到 fromto 可能相隔长达 200 天,所以...

set.seed(1)
from <- seq(as.IDate("1950-01-01"), by = "day", length = 1e6)
to <- from + pmin(200,rpois(length(from),1))
DT <- data.table(from,to)

system.time(DT[, flag2 := +(next_wday(from) <= to)])
# user system elapsed
# 2.11 0.03 2.14

# David Arenburg's solution
system.time({
DateDT <- DT[, {
temp <- seq(min(from), max(to), by = "day")
temp2 <- temp[wday(temp) == 4L]
list(from = temp2, to = temp2)
}
]
indx <- foverlaps(DT, setkey(DateDT), nomatch = 0L, which = TRUE)$xid
DT[, flag := 0L][indx, flag := 1L]
})
# user system elapsed
# 6.75 0.14 6.89

# check agreement
DT[,table(flag,flag2)]
# flag2
# flag 0 1
# 0 714666 0
# 1 0 285334

我使用 IDate 因为它是 data.table 包附带的日期格式,并且使用起来更快(?)。有几种方法可以使代码更快:

  • 首先,将注意力限制在 to-from 小于 6 的行上可能会更快(因为每个工作日都会有 6 或更大的间隙),例如

    DT[,flag2:=0L][to-from < 6, flag2 := +(next_wday(from) <= to)]
  • 其次,由于计算一次仅依赖于一行,因此并行化可能会带来一些改进,如 @grubjesic 的回答所示。

  • 根据实际数据,可能会发现其他改进。

这里没有对 OP 的代码进行基准测试,因为它需要按行拆分数据并枚举每行最多 200 个日期,这肯定会很慢。


** 或任何 wday 为 4 的意思。

关于如果工作日位于日期范围之间,R data.table 将使用逻辑值设置新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31842356/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com