R 中任意确定的开始和结束日期

Round date to arbitrary established start and end of the year in R

我正在寻找 快速 解决方案以将日期舍入到一年的最后一天,但年份从 1.10 开始到 30.09 结束。所以,当我有 2020-04-05 时,它应该将这个日期四舍五入到 2020-09-30。当我有 2020-12-12 时,它应该将该日期四舍五入为 2021-09-30。我试过这个功能:

round_date_to_seasons <- function(dates) {
    rounded_dates <- structure(rep(NA_real_, length(dates)), class = "Date")
    for (i in seq.int(1, length.out = length(dates))) {
        if (month(dates[i]) %in% c(10, 11, 12)) {
            year(dates[i]) <- year(dates[i]) + 1
            month(dates[i]) <- 9
            day(dates[i]) <- 30
        } else {
            month(dates[i]) <- 9
            day(dates[i]) <- 30
        }
        rounded_dates[i] <- dates[i]
    }
    rounded_dates
}

但是速度很慢。如果我正确地进行了分析,则值分配很慢,因此上面代码中的第 7、8、9、11、12 和 14 行,但最后一行还不错。对于长度为 1000 万或更长的向量,我真的需要尽可能快的函数。

没有理由一步一步来,你可以使用向量化函数。

例如,这会快很多:

library(lubridate)
round_date_to_seasons_new <- function(dates)
{
  as.Date(ifelse(month(dates) %in% 10:12,
         as_date(ISOdate(year(dates) + 1, 9, 30)),
         as_date(ISOdate(year(dates), 10, 1))),
        origin = '1970-01-01')
}

我相信这可以进一步改进,但是当 运行 在这里时,它至少快了一个数量级。

尽可能在 R 中使用矢量化函数。

在您的示例中,在循环的每次迭代中,都会检索整个 rounded_dates-对象(多次),更改一个元素,然后将所有内容写回内存。 如果您的函数对整个对象执行某些操作,则这是必需的。但在这种情况下,第一次迭代只查看和更改第一个元素,第二次迭代仅查看和更改第二个元素,依此类推。

如果你使用向量化函数,R 知道它应该只看一小部分,最后只合并结果。

尝试:

library(lubridate)
round_date_to_seasons <- function(dat){
    lubridate::ceiling_date(dat %m+% months(-9) + days(1),'year') %m+% months(9)-days(1)}

round_date_to_seasons(as.POSIXct('2020-04-05'))
[1] "2020-09-30 CEST"

round_date_to_seasons(as.POSIXct('2020-12-12'))
[1] "2021-09-30 CEST"