1
votes

Consider the following code that creates two ts time-series foo & bar:

x = 1:22
foo = ts(x, start = 1.5, end = 106.5, frequency = 0.2)
bar = ts(x, start = 2.5, end = 107.5, frequency = 0.2)

The foo and bar objects are identical except for the start and end values: for bar they are both larger by 1. Neither start/end values are exactly multiples of the frequency, but that shouldn't pose a problem. Indeed, for both foo and bar, a window of an arbitrary size can be successfully extracted:

stats::window(foo, start = 20, end = 30)  # works fine
stats::window(bar, start = 20, end = 30)  # works fine too

But if I try to assign values to these windows, only foo works:

window(foo, start = 20, end = 30) <- NA  # works fine
window(bar, start = 20, end = 30) <- NA  # ERROR!!!

Error in attr(y, "tsp") <- c(ystart, yend, xfreq) : invalid time series parameters specified

the internal working of window<-.ts basically calls the stats::window function, so it should work just as well as calling the window() function explicitly.


My understanding is that in the ts definition, 'start' and 'end' are just in arbitrary units, eg: seconds. So ts(x, start = 1.5, end = 106.5, frequency = 0.2) may mean: a series that starts at second 1.5 and ends at second 106.5, where each number represents 5 seconds (1/frequency). The stat::window function then, just selects the values that are within its start-end boundaries, eg: from 20 to 30 seconds. And indeed the time() for both windows is the same and seems to confirm this:

time(window(foo, start = 20, end = 30))
[1] 21.5 26.5
time(window(bar, start = 20, end = 30))
[1] 22.5 27.5

The fact that one series starts at 1.5s and the other at 2.5s has absolutely no impact on the windowing procedure. Yet when assigning values to it, my logic breaks.

Things get even wilder by removing one cycle from bar:

qux = ts(1:21, start = 2.5, end = 102.5, frequency = 0.2)
window(qux, start = 20, end = 30) <- NA  #ERROR!!

Error in `window<-.ts`(`*tmp*`, start = 20, end = 30, value = NA) : times to be replaced do not match

A different error! I think I am failing to understand some fundamental concept. So what am I missing here?

1

1 Answers

1
votes

As you say window<-.ts() uses window() internally to create the new object. It's done via eval.parent(), where window() is called with extend=TRUE, and this is when the error occurs. As such we can simplify our analysis by instead considering the following pair

window(foo, start=20, end=30, extend=TRUE)  # works fine
# Time Series:
# Start = 20 
# End = 25 
# Frequency = 0.2 
# [1] 5 6

window(bar, start=20, end=30, extend=TRUE)  # error
# Error in attr(y, "tsp") <- c(ystart, yend, xfreq) : 
#   invalid time series parameters specified

the attr(y, "tsp") <- c(ystart, yend, xfreq) mentioned in the error message happens at the very end of stats:::window.default. The actual values used are

# for foo
y <- 5:6
attr(y, "tsp") <- c(20, 25, 0.2)

# for bar
y <- 5:6
attr(y, "tsp") <- c(20, 30, 0.2)

The 25/30 discrepancy is due to rounding earlier in the code, but why does one work, while the other doesn't? It's the frequency. A frequency of less than one seems a bit odd to me. See, if you set the frequency to 12, f.ex, you have 12 samples per period or cycle. Maybe once a month, or maybe every second hour, but every 12th sample should have something in common. If you set frequency to 1, you effectively have no period, you sample once a year and know of no significant cycles longer that are in multiple of years. What would a frequency of less than 1 mean? I guess a frequency of say 0.5 could mean that sampling is done every second year, and 0.2 then every fifth year? Maybe that's informative, I don't know.

But why the error? While both 25-20 and 30-20 divides by 5 just fine, the latter one is one element short. Use y <- 5:7 instead and it works just fine.
Why does it work for foo but not bar? Because rounding.
But why though? Probably because no-one tested the function using time series with frequency of less than one.


A possible fix could be to use zoo class time series, instead of standard ts. It works well in this case, but I haven't done any other tests.

library(zoo)

foo.z <- as.zoo(foo)
bar.z <- as.zoo(bar)

window(foo.z, start = 20, end = 30) <- NA  # works fine
window(bar.z, start = 20, end = 30) <- NA  # also works fine