您如何 return 时间序列的 "period" 部分?

How do you return the "period" part of to a time series?

R 中,您可以使用 cycle() 函数轻松 return 时间序列对象的 cycle 部分。例如

> series <- ts(1:50, frequency = 4, start = 2011)
> cycle(series)
     Qtr1 Qtr2 Qtr3 Qtr4
2011    1    2    3    4
2012    1    2    3    4
2013    1    2    3    4
2014    1    2    3    4
2015    1    2    3    4
2016    1    2    3    4
2017    1    2    3    4
2018    1    2    3    4
2019    1    2    3    4
2020    1    2    3    4
2021    1    2    3    4
2022    1    2    3    4
2023    1    2   

但是,我一直没能想出一个干净的方法来 return "period" 部分(例如季度数据的年份)。在大多数情况下,你可以做一个简单的:

> floor(time(series))
     Qtr1 Qtr2 Qtr3 Qtr4
2011 2011 2011 2011 2011
2012 2012 2012 2012 2012
2013 2013 2013 2013 2013
2014 2014 2014 2014 2014
2015 2015 2015 2015 2015
2016 2016 2016 2016 2016
2017 2017 2017 2017 2017
2018 2018 2018 2018 2018
2019 2019 2019 2019 2019
2020 2020 2020 2020 2020
2021 2021 2021 2021 2021
2022 2022 2022 2022 2022
2023 2023 2023 

但是,我发现对于一些数据(通常是高频数据), errors in floating point precision 会导致一个周期的第一个时间点为 return 的值上一时期(例如,它被存储为 2010.9999999 而不是 2011,所以 floor() returns 2010)。我们可以通过以下方式人为地将问题引入数据中:

> seriesprec <- ts(1:50, frequency = 4, start = 2010.999999999999)
> floor(time(seriesprec))
     Qtr1 Qtr2 Qtr3 Qtr4
2011 2010 2011 2011 2011
2012 2011 2012 2012 2012
2013 2012 2013 2013 2013
2014 2013 2014 2014 2014
2015 2014 2015 2015 2015
2016 2015 2016 2016 2016
2017 2016 2017 2017 2017
2018 2017 2018 2018 2018
2019 2018 2019 2019 2019
2020 2019 2020 2020 2020
2021 2020 2021 2021 2021
2022 2021 2022 2022 2022
2023 2022 2023    

现在我们看到浮点精度偏离了 returned 值,尽管:

> all.equal(time(seriesprec), time(series))
[1] TRUE

我发现似乎可以处理这些边缘情况的最简单的解决方案是:

round(time(series) - (cycle(series) - 1)*deltat(series))

但是对于一个非常简单的任务来说,这似乎是相当复杂的代码。特别是当 cycle() 是一个基函数时,似乎应该有另一个基函数来 return 时间定义的另一半。

顺便说一下,我知道一些包可以很好地处理日期和时间,但是由于我所做的很多事情最终都会被打包到包中,所以我宁愿不添加像 lubridate 这样的东西对可以用一行(非常麻烦的)基本 R 代码解决的事情的依赖。

谢谢!

一种方法可能是在取 floortrunc 之前将适当小的值添加到 time。正如评论中提到的G.Grothendieckdeltat(series)/2可以是一个合适的小值。将 offsettime 一起使用可以是增加该小值的一种方式。来自 ?time

offset

can be used to indicate when sampling took place in the time unit. 0 (the default) indicates the start of the unit, 0.5 the middle and 1 the end of the interval.

offset = 0.5添加到time等同于添加deltat(series)/2

因此,您应该能够使用

获得正确的句点部分
floor(time(seriesprec, offset = 0.5))