3
$\begingroup$

This question already has an answer here:

I want to detect presence of seasonality in time series data. I know one can achieve that by plotting the autocorrelation function but I need an automatic process if the series is seasonal or not, more like an algorithm that after I run the time series thought I get 'YES' for seasonal and 'NO' for nonseasonal.

Is there anything in R that I can use?

If not what is a way by knowing the autocorrelation function (ACF) to do this?

Thanks

$\endgroup$

marked as duplicate by Rob Hyndman, Andy W, whuber May 1 '13 at 5:17

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

12
$\begingroup$

The trouble with using the ACF is that there can be other reasons for significant spikes, not just seasonality. So it is indicative but cannot be conclusive.

If the data had a small seasonal period (such as 4 for quarterly data or 12 for monthly data) then a simple approach is to use the ets function in the forecast package for R. If there is a seasonal pattern, it will choose a seasonal model.

But since your data are weekly (according to the comments in the answer from Mark T Patterson), that won't work because the seasonal period is too long, and because it is non-integer. X12 also won't help you (as suggested by @toomuchpj) as it is only designed for quarterly and monthly data.

The non-integer period will be a problem for any solution that assumes period=52, because the difference between 52 and 365/7 will become apparent with long series.

One approach is to use the tbats model, also in the forecast package in R. It will handle weekly seasonality and will automatically determine if a seasonal pattern is present. For example:

x <- ts(data, frequency=365/7)
fit <- tbats(x)
seasonal <- !is.null(fit$seasonal)

Then seasonal will be TRUE if a seasonal model is chosen and otherwise FALSE.

$\endgroup$
  • $\begingroup$ Dr Hyndman- thanks for the response. Can you please explain why you use frequency=365/7? I am trying to understand tbats() in order to use it- what are the assumptions? I used it on data that I believe to be seasonal but I get warings $\endgroup$ – Eva May 7 '13 at 15:22
  • $\begingroup$ Warning messages: 1: In matrix(x[(nobsf - nobst + 1):nobsf], period, nyr) : data length exceeds size of matrix Error in cat(list(...), file, sep, fill, labels, append) : argument 2 (type 'list') cannot be handled by 'cat' $\endgroup$ – Eva May 7 '13 at 15:26
  • $\begingroup$ There are 365 days in a year (except leap years) and 7 days in a week. So 365/7 is the number of weeks in a year. If you can provide a reproducible example of the warning, I will take a look at it. $\endgroup$ – Rob Hyndman May 7 '13 at 23:51
  • $\begingroup$ Input data is 15 16 9 11 621 12 15 7 8 9 13 609 13 10 10 7 12 8 10 1133 9 8 14 2 931 12 9 12 8 1505 10 9 5 8 488 9 15 7 9 15 11 8 8 11 9 13 6 13 7 420 15 20 $\endgroup$ – Eva May 13 '13 at 15:34
  • $\begingroup$ Once I run the above R code I get 41 warnings that are:Warning messages: 1: In matrix(x[(nobsf - nobst + 1):nobsf], period, nyr) : data length exceeds size of matrix FALSE 2: In optimize(guer.cv, c(lower, upper), x = x, nonseasonal.length = nonseasonal.length) : NA/Inf replaced by maximum positive value FALSE $\endgroup$ – Eva May 13 '13 at 15:36
1
$\begingroup$

@Eva,

I definitely think R has the functionality to help you out here. The decision about which tool depends a bit on the kind of seasonality you're trying to detect -- can you tell us a bit more about the data you're modeling?

I would start with something simple -- for example, let's assume you have a single observation each day for 1000 days, and are interested in whether there's an effect of month.

You could start by writing a function that fits a model of your outcome variable on month (as a factor), and then reports a 1 if any of your months are significant at the 1% level. Note: be very careful about multiple hypothesis tests here..

Here's some example code, using a DV which we expect not to exhibit seasonality:

time = seq(from = 1, by = 1, length.out = 1000)
month = time %% 12

y = rnorm(1000,0,1)

df = data.frame(time, month, y)

seasonality.func = function(df){
  lm.1 = lm(y ~ factor(month), data = df)
  p.vals = summary(lm.1)$coefficients[,4]
  p.vals.lt.01 = as.numeric(sum(p.vals<.01)>0)
  return(p.vals.lt.01)
}

seasonality.func(df)
$\endgroup$
  • $\begingroup$ Mark, thanks for the response. The data is based on sales of particular part for 52 weeks. The idea is that I would be able to feed weekly sales data by part into the algorithm and get a yes or no for seasonal/nonseasonal. $\endgroup$ – Eva Apr 30 '13 at 15:20
  • $\begingroup$ Eva, sounds like a cool problem! Given your data, I'd modify the above code by starting with week rather than time, then defining season = week %/% 13. Finally, I'd regress your sales data on the season variable (e.g. y ~ factor(season)), then similarly extract the p-values from the regression, and add an indicator for significance below a certain threshold. Does this strategy make sense? $\endgroup$ – Mark T Patterson Apr 30 '13 at 16:03
  • $\begingroup$ Mark, can you please explain more on why you define month = time %% 12 or actually in my case when we talk about weeks season = week %/% 13? I am not sure I understand why we are assigning these values to month and season? $\endgroup$ – Eva Apr 30 '13 at 17:42
  • $\begingroup$ Sure -- my idea here was just to assign each week to a season (e.g. winter, spring, summer, fall), then ask whether there are differences in the outcome variable based on season. Another way to create this season variable would be season = rep(1:4, each = 13). With the season variable defined, you're ready to look for a relationship between y and season. This isn't the only way to look for time patterns in the data, but it might be a first thing to check. $\endgroup$ – Mark T Patterson Apr 30 '13 at 17:50
  • $\begingroup$ Input data is 15 16 9 11 621 12 15 7 8 9 13 609 13 10 10 7 12 8 10 1133 9 8 14 2 931 12 9 12 8 1505 10 9 5 8 488 9 15 7 9 15 11 8 8 11 9 13 6 13 7 420 15 20 $\endgroup$ – Eva May 13 '13 at 15:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.