Title: | Seasonal Trend Decomposition Using Regression |
---|---|
Description: | Methods for decomposing seasonal data: STR (a Seasonal-Trend time series decomposition procedure based on Regression) and Robust STR. In some ways, STR is similar to Ridge Regression and Robust STR can be related to LASSO. They allow for multiple seasonal components, multiple linear covariates with constant, flexible and seasonal influence. Seasonal patterns (for both seasonal components and seasonal covariates) can be fractional and flexible over time; moreover they can be either strictly periodic or have a more complex topology. The methods provide confidence intervals for the estimated components. The methods can also be used for forecasting. |
Authors: | Alexander Dokumentov [aut] , Rob Hyndman [aut, cre] |
Maintainer: | Rob Hyndman <[email protected]> |
License: | GPL-3 |
Version: | 0.7.0.9000 |
Built: | 2024-11-13 06:50:52 UTC |
Source: | https://github.com/robjhyndman/stR |
Automatically selects parameters for an STR decomposition of time series data.
The time series should be of class ts
or msts
.
AutoSTR( data, robust = FALSE, gapCV = NULL, lambdas = NULL, reltol = 0.001, confidence = NULL, nsKnots = NULL, trace = FALSE )
AutoSTR( data, robust = FALSE, gapCV = NULL, lambdas = NULL, reltol = 0.001, confidence = NULL, nsKnots = NULL, trace = FALSE )
data |
A time series of class |
robust |
When |
gapCV |
An optional parameter defining the length of the sequence of skipped values in the cross validation procedure. |
lambdas |
An optional parameter. A structure which replaces lambda parameters provided with predictors. It is used as either a starting point for the optimisation of parameters or as the exact model parameters. |
reltol |
An optional parameter which is passed directly to |
confidence |
A vector of percentiles giving the coverage of confidence intervals.
It must be greater than 0 and less than 1.
If |
nsKnots |
An optional vector parameter, defining the number of seasonal knots (per period) for each sesonal component. |
trace |
When |
A structure containing input and output data.
It is an S3 class STR
, which is a list with the following components:
output – contains decomposed data. It is a list of three components:
predictors – a list of components where each component corresponds to the input predictor. Every such component is a list containing the following:
data – fit/forecast for the corresponding predictor (trend, seasonal component, flexible or seasonal predictor).
beta – beta coefficients of the fit of the coresponding predictor.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
random – a list with one component data, which contains residuals of the model fit.
forecast – a list with two components:
data – fit/forecast for the model.
beta – beta coefficients of the fit.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
input – input parameters and lambdas used for final calculations.
data – input data.
predictors - input predictors.
lambdas – smoothing parameters used for final calculations (same as input lambdas for STR method).
cvMSE – optional cross validated (leave one out) Mean Squared Error.
optim.CV.MSE – best cross validated Mean Squared Error (n-fold) achieved during minimisation procedure.
nFold – the input nFold
parameter.
gapCV – the input gapCV
parameter.
method – always contains string "AutoSTR"
for this function.
Alexander Dokumentov
Dokumentov, A., and Hyndman, R.J. (2022) STR: Seasonal-Trend decomposition using Regression, INFORMS Journal on Data Science, 1(1), 50-62. https://robjhyndman.com/publications/str/
# Decomposition of a multiple seasonal time series decomp <- AutoSTR(calls) plot(decomp) # Decomposition of a monthly time series decomp <- AutoSTR(log(grocery)) plot(decomp)
# Decomposition of a multiple seasonal time series decomp <- AutoSTR(calls) plot(decomp) # Decomposition of a monthly time series decomp <- AutoSTR(log(grocery)) plot(decomp)
Number of call arrivals per 5-minute interval handled on weekdays between 7:00 am and 9:05 pm from March 3, 2003 in a large North American commercial bank.
calls
calls
A numerical time series of class msts
and ts
.
Forecasting time series with complex seasonal patterns using exponential smoothing A.M. De Livera, R.J. Hyndman & R.D. Snyder J American Statistical Association, 106(496), 1513-1527. https://robjhyndman.com/publications/complex-seasonality/
plot(calls, ylab = "Calls handled")
plot(calls, ylab = "Calls handled")
components
extracts components as time series from the result of an STR decomposition.
components(object)
components(object)
object |
Result of STR decomposition. |
Alexander Dokumentov
STRmodel
, RSTRmodel
, STR
, AutoSTR
fit <- AutoSTR(log(grocery)) comp <- components(fit) plot(comp)
fit <- AutoSTR(log(grocery)) comp <- components(fit) plot(comp)
The data set provides information about electricity consumption in Victoria, Australia during the 115 days starting on 10th of January, 2000, and comprises the maximum electricity demand in Victoria during 30-minute periods (48 observations per day). For each 30-minute period, the dataset also provides the air temperature in Melbourne.
electricity
electricity
An numerical matrix of class msts
and ts
.
Consumption
column contains maximum electricity consumption during 30 minute
periods
Temperature
column contains temperature in Melbourne during the corresponding
30 minute interval
Time
column contains number of 30 minute interval in the dataset
DailySeasonality
column contains positions of 30 minute interval inside days
WeeklySeasonality
column contains positions of 30 minute interval inside weeks
WorkingDaySeasonality
column contains positions of 30 minute intervals
inside working day/holiday transition diagram
plot(electricity[, 1:2], xlab = "Weeks", main = "Electricity demand and temperature in Melbourne, Australia" )
plot(electricity[, 1:2], xlab = "Weeks", main = "Electricity demand and temperature in Melbourne, Australia" )
Turnover of supermarkets and grocery stores in New South Wales, Australia.
grocery
grocery
An object of class ts
.
Australian Bureau of Statistics, CAT 8501.0. (TABLE 11. Retail Turnover, State by Industry Subgroup, Original)
plot(grocery, ylab = "NSW Grocery, $ 10^6")
plot(grocery, ylab = "NSW Grocery, $ 10^6")
Automatically selects parameters (lambda coefficients) for an STR decomposition of time series data.
Heuristic approach can give a better estimate compare to a standard optmisaton methods used in STR
.
If a parallel backend is registered for use before STR
call,
heuristicSTR
will use it for n-fold cross validation computations.
heuristicSTR( data, predictors, confidence = NULL, lambdas = NULL, pattern = extractPattern(predictors), nFold = 5, reltol = 0.005, gapCV = 1, solver = c("Matrix", "cholesky"), trace = FALSE, ratioGap = 1e+12, relCV = 0.01 )
heuristicSTR( data, predictors, confidence = NULL, lambdas = NULL, pattern = extractPattern(predictors), nFold = 5, reltol = 0.005, gapCV = 1, solver = c("Matrix", "cholesky"), trace = FALSE, ratioGap = 1e+12, relCV = 0.01 )
data |
Time series or a vector of length L. |
predictors |
List of predictors.
|
confidence |
A vector of percentiles giving the coverage of confidence intervals.
It must be greater than 0 and less than 1.
If |
lambdas |
An optional parameter. A structure which replaces lambda parameters provided with predictors. It is used as either a starting point for the optimisation of parameters or as the exact model parameters. |
pattern |
An optional parameter which has the same structure as |
nFold |
An optional parameter setting the number of folds for cross validation. |
reltol |
An optional parameter which is passed directly to |
gapCV |
An optional parameter defining the length of the sequence of skipped values in the cross validation procedure. |
solver |
A vector with two string values. The only supported combinations are: c("Matrix", "cholesky") (default), and c("Matrix", "qr"). The parameter is used to specify a particular library and method to solve the minimisation problem during STR decompositon. |
trace |
When |
ratioGap |
Ratio to define hyperparameter bounds for one-dimensional search. |
relCV |
Minimum improvement required after all predictors tried. It is used to exit heuristic serach of lambda parameters. |
A structure containing input and output data.
It is an S3 class STR
, which is a list with the following components:
output – contains decomposed data. It is a list of three components:
predictors – a list of components where each component corresponds to the input predictor. Every such component is a list containing the following:
data – fit/forecast for the corresponding predictor (trend, seasonal component, flexible or seasonal predictor).
beta – beta coefficients of the fit of the coresponding predictor.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
random – a list with one component data, which contains residuals of the model fit.
forecast – a list with two components:
data – fit/forecast for the model.
beta – beta coefficients of the fit.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
input – input parameters and lambdas used for final calculations.
data – input data.
predictors - input predictors.
lambdas – smoothing parameters used for final calculations (same as input lambdas for STR method).
cvMSE – optional cross validated (leave one out) Mean Squared Error.
optim.CV.MSE or optim.CV.MAE – best cross validated Mean Squared Error or Mean Absolute Error (n-fold) achieved during minimisation procedure.
nFold – the input nFold
parameter.
gapCV – the input gapCV
parameter.
method – contains strings "STR"
or "RSTR"
depending on used method.
Alexander Dokumentov
Dokumentov, A., and Hyndman, R.J. (2022) STR: Seasonal-Trend decomposition using Regression, INFORMS Journal on Data Science, 1(1), 50-62. https://robjhyndman.com/publications/str/
TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) StaticTempM <- list( name = "Temp Mel", data = TempM, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) StaticTempM2 <- list( name = "Temp Mel^2", data = TempM2, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) Predictors <- list(Trend, WDSeason, StaticTempM, StaticTempM2) elec.fit <- heuristicSTR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) ######################################## TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) DailySeasonalStructure <- list( segments = list(c(0, 48)), sKnots = c(as.list(1:47), list(c(48, 0))) ) WeeklySeasonalStructure <- list( segments = list(c(0, 336)), sKnots = c(as.list(seq(4, 332, 4)), list(c(336, 0))) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) DailySeasons <- as.vector(electricity[, "DailySeasonality"]) WeeklySeasons <- as.vector(electricity[, "WeeklySeasonality"]) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) SeasonTimeKnots2 <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 12) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WSeason <- list( name = "Weekly seas", data = SeasonData, times = Times, seasons = WeeklySeasons, timeKnots = SeasonTimeKnots2, seasonalStructure = WeeklySeasonalStructure, lambdas = c(0.8, 0.6, 100) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) TrendTempM <- list( name = "Trend temp Mel", data = TempM, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1e7, 0, 0) ) TrendTempM2 <- list( name = "Trend temp Mel^2", data = TempM2, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(0.01, 0, 0) ) # Starting parameter is too far from the optimal value Predictors <- list(Trend, WSeason, WDSeason, TrendTempM, TrendTempM2) elec.fit <- heuristicSTR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) plotBeta(elec.fit, predictorN = 4) plotBeta(elec.fit, predictorN = 5)
TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) StaticTempM <- list( name = "Temp Mel", data = TempM, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) StaticTempM2 <- list( name = "Temp Mel^2", data = TempM2, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) Predictors <- list(Trend, WDSeason, StaticTempM, StaticTempM2) elec.fit <- heuristicSTR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) ######################################## TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) DailySeasonalStructure <- list( segments = list(c(0, 48)), sKnots = c(as.list(1:47), list(c(48, 0))) ) WeeklySeasonalStructure <- list( segments = list(c(0, 336)), sKnots = c(as.list(seq(4, 332, 4)), list(c(336, 0))) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) DailySeasons <- as.vector(electricity[, "DailySeasonality"]) WeeklySeasons <- as.vector(electricity[, "WeeklySeasonality"]) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) SeasonTimeKnots2 <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 12) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WSeason <- list( name = "Weekly seas", data = SeasonData, times = Times, seasons = WeeklySeasons, timeKnots = SeasonTimeKnots2, seasonalStructure = WeeklySeasonalStructure, lambdas = c(0.8, 0.6, 100) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) TrendTempM <- list( name = "Trend temp Mel", data = TempM, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1e7, 0, 0) ) TrendTempM2 <- list( name = "Trend temp Mel^2", data = TempM2, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(0.01, 0, 0) ) # Starting parameter is too far from the optimal value Predictors <- list(Trend, WSeason, WDSeason, TrendTempM, TrendTempM2) elec.fit <- heuristicSTR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) plotBeta(elec.fit, predictorN = 4) plotBeta(elec.fit, predictorN = 5)
plot.STR
plots results of STR decomposition.
## S3 method for class 'STR' plot( x, xTime = NULL, dataPanels = 1, predictorPanels = as.list(seq_along(x$output$predictors)), randomPanels = length(x$output$predictors) + 1, forecastPanels = length(x$output$predictors) + 2, dataColor = "black", predictorColors = rep("red", length(x$output$predictors)), randomColor = "red", forecastColor = "blue", vLines = NULL, xlab = "Time", main = ifelse(x$method %in% c("STR", "STRmodel"), "STR decomposition", "Robust STR decomposition"), showLegend = TRUE, ... )
## S3 method for class 'STR' plot( x, xTime = NULL, dataPanels = 1, predictorPanels = as.list(seq_along(x$output$predictors)), randomPanels = length(x$output$predictors) + 1, forecastPanels = length(x$output$predictors) + 2, dataColor = "black", predictorColors = rep("red", length(x$output$predictors)), randomColor = "red", forecastColor = "blue", vLines = NULL, xlab = "Time", main = ifelse(x$method %in% c("STR", "STRmodel"), "STR decomposition", "Robust STR decomposition"), showLegend = TRUE, ... )
x |
Result of STR decomposition. |
xTime |
Times for data to plot. |
dataPanels |
Vector of panel numbers in which to plot the original data. Set to |
predictorPanels |
A list of vectors of numbers where every such vector describes which panels should be used for plotting the corresponding predictor. |
randomPanels |
Vector of panel numbers in which to plot the residuals. Set to |
forecastPanels |
Vector of panel numbers in which to plot the fit/forecast. Set to |
dataColor |
Color to plot data. |
predictorColors |
Vector of colors to plot components corresponding to the predictors. |
randomColor |
Color to plot the residuals. |
forecastColor |
Color to plot the fit/forecast. |
vLines |
Vector of times where vertical lines will be plotted. |
xlab |
Label for horizontal axis. |
main |
Main heading for plot. |
showLegend |
When |
... |
Other parameters to be passed directly to plot and lines functions in the implementation. |
Alexander Dokumentov
STRmodel
, RSTRmodel
, STR
, AutoSTR
fit <- AutoSTR(log(grocery)) plot(fit, forecastPanels = 0, randomColor = "DarkGreen", vLines = 2000:2010, lwd = 2)
fit <- AutoSTR(log(grocery)) plot(fit, forecastPanels = 0, randomColor = "DarkGreen", vLines = 2000:2010, lwd = 2)
plotBeta
plots the varying beta coefficients of STR decomposition.
It plots coefficients only only for independent seasons (one less season than defined).
plotBeta( x, xTime = NULL, predictorN = 1, dim = c(1, 2, 3), type = "o", pch = 20, palette = function(n) rainbow(n, start = 0, end = 0.7) )
plotBeta( x, xTime = NULL, predictorN = 1, dim = c(1, 2, 3), type = "o", pch = 20, palette = function(n) rainbow(n, start = 0, end = 0.7) )
x |
Result of STR decomposition. |
xTime |
Times for data to plot. |
predictorN |
Predictor number in the decomposition to plot the corresponding beta coefficiets. |
dim |
Dimensions to use to plot the beta coefficients.
When |
type |
Type of the graph for one dimensional plots. |
pch |
Symbol code to plot points in 1-dimensional charts. Default value is |
palette |
Color palette for 2 - and 3 - dimentional plots. |
Alexander Dokumentov
fit <- AutoSTR(log(grocery)) for (i in 1:2) plotBeta(fit, predictorN = i, dim = 2) ######################################## TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) DailySeasonalStructure <- list( segments = list(c(0, 48)), sKnots = c(as.list(1:47), list(c(48, 0))) ) WeeklySeasonalStructure <- list( segments = list(c(0, 336)), sKnots = c(as.list(seq(4, 332, 4)), list(c(336, 0))) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) DailySeasons <- as.vector(electricity[, "DailySeasonality"]) WeeklySeasons <- as.vector(electricity[, "WeeklySeasonality"]) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) SeasonTimeKnots2 <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 12) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WSeason <- list( name = "Weekly seas", data = SeasonData, times = Times, seasons = WeeklySeasons, timeKnots = SeasonTimeKnots2, seasonalStructure = WeeklySeasonalStructure, lambdas = c(0.8, 0.6, 100) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) TrendTempM <- list( name = "Trend temp Mel", data = TempM, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1e7, 0, 0) ) TrendTempM2 <- list( name = "Trend temp Mel^2", data = TempM2, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(0.01, 0, 0) ) # Starting parameter is too far from the optimal value Predictors <- list(Trend, WSeason, WDSeason, TrendTempM, TrendTempM2) elec.fit <- STR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) plotBeta(elec.fit, predictorN = 4) plotBeta(elec.fit, predictorN = 5) # Beta coefficients are too "wiggly"
fit <- AutoSTR(log(grocery)) for (i in 1:2) plotBeta(fit, predictorN = i, dim = 2) ######################################## TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) DailySeasonalStructure <- list( segments = list(c(0, 48)), sKnots = c(as.list(1:47), list(c(48, 0))) ) WeeklySeasonalStructure <- list( segments = list(c(0, 336)), sKnots = c(as.list(seq(4, 332, 4)), list(c(336, 0))) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) DailySeasons <- as.vector(electricity[, "DailySeasonality"]) WeeklySeasons <- as.vector(electricity[, "WeeklySeasonality"]) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) SeasonTimeKnots2 <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 12) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WSeason <- list( name = "Weekly seas", data = SeasonData, times = Times, seasons = WeeklySeasons, timeKnots = SeasonTimeKnots2, seasonalStructure = WeeklySeasonalStructure, lambdas = c(0.8, 0.6, 100) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) TrendTempM <- list( name = "Trend temp Mel", data = TempM, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1e7, 0, 0) ) TrendTempM2 <- list( name = "Trend temp Mel^2", data = TempM2, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(0.01, 0, 0) ) # Starting parameter is too far from the optimal value Predictors <- list(Trend, WSeason, WDSeason, TrendTempM, TrendTempM2) elec.fit <- STR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) plotBeta(elec.fit, predictorN = 4) plotBeta(elec.fit, predictorN = 5) # Beta coefficients are too "wiggly"
Robust Seasonal-Trend decomposition of time series data using Regression (robust version of STRmodel
).
RSTRmodel( data, predictors = NULL, strDesign = NULL, lambdas = NULL, confidence = NULL, nMCIter = 100, control = list(nnzlmax = 1e+06, nsubmax = 3e+05, tmpmax = 50000), reportDimensionsOnly = FALSE, trace = FALSE )
RSTRmodel( data, predictors = NULL, strDesign = NULL, lambdas = NULL, confidence = NULL, nMCIter = 100, control = list(nnzlmax = 1e+06, nsubmax = 3e+05, tmpmax = 50000), reportDimensionsOnly = FALSE, trace = FALSE )
data |
Time series or a vector of length L. |
predictors |
List of predictors.
|
strDesign |
An optional parameter used to create the design matrix. It is used internally in the library to improve performance when the design matrix does not require full recalculation. |
lambdas |
An optional parameter. A structure which replaces lambda parameters provided with predictors. It is used as either a starting point for the optimisation of parameters or as the exact model parameters. |
confidence |
A vector of percentiles giving the coverage of confidence intervals.
It must be greater than 0 and less than 1.
If |
nMCIter |
Number of Monte Carlo iterations used to estimate confidence intervals for Robust STR decomposition. |
control |
Passed directly to |
reportDimensionsOnly |
A boolean parameter. When TRUE the method constructs the design matrix and reports its dimensions without proceeding further. It is mostly used for debugging. |
trace |
When |
A structure containing input and output data.
It is an S3 class STR
, which is a list with the following components:
output – contains decomposed data. It is a list of three components:
predictors – a list of components where each component corresponds to the input predictor. Every such component is a list containing the following:
data – fit/forecast for the corresponding predictor (trend, seasonal component, flexible or seasonal predictor).
beta – beta coefficients of the fit of the coresponding predictor.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
random – a list with one component data, which contains residuals of the model fit.
forecast – a list with two components:
data – fit/forecast for the model.
beta – beta coefficients of the fit.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
input – input parameters and lambdas used for final calculations.
data – input data.
predictors - input predictors.
lambdas – smoothing parameters used for final calculations (same as input lambdas for STR method).
method – always contains string "RSTRmodel"
for this function.
Alexander Dokumentov
Dokumentov, A., and Hyndman, R.J. (2022) STR: Seasonal-Trend decomposition using Regression, INFORMS Journal on Data Science, 1(1), 50-62. https://robjhyndman.com/publications/str/
n <- 70 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 set.seed(1234567890) data <- data + rnorm(length(data), 0, 0.2) data[20] <- data[20] + 3 data[50] <- data[50] - 5 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(1, 0, 1) ) predictors <- list(trend, season) rstr <- RSTRmodel(data, predictors, confidence = 0.8) plot(rstr)
n <- 70 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 set.seed(1234567890) data <- data + rnorm(length(data), 0, 0.2) data[20] <- data[20] + 3 data[50] <- data[50] - 5 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(1, 0, 1) ) predictors <- list(trend, season) rstr <- RSTRmodel(data, predictors, confidence = 0.8) plot(rstr)
seasadj.STR
extracts seasonally adjusted data by removing the seasonal components from the result of STR decomposition.
## S3 method for class 'STR' seasadj(object, include = c("Trend", "Random"), ...)
## S3 method for class 'STR' seasadj(object, include = c("Trend", "Random"), ...)
object |
Result of STR decomposition. |
include |
Vector of component names to include in the result. The default is |
... |
Other arguments not currently used. |
Alexander Dokumentov
STRmodel
, RSTRmodel
, STR
, AutoSTR
fit <- AutoSTR(log(grocery)) plot(seasadj(fit))
fit <- AutoSTR(log(grocery)) plot(seasadj(fit))
Automatically selects parameters for an STR decomposition of time series data.
If a parallel backend is registered for use before STR
call,
STR
will use it for n-fold cross validation computations.
STR( data, predictors, confidence = NULL, robust = FALSE, lambdas = NULL, pattern = extractPattern(predictors), nFold = 5, reltol = 0.005, gapCV = 1, solver = c("Matrix", "cholesky"), nMCIter = 100, control = list(nnzlmax = 1e+06, nsubmax = 3e+05, tmpmax = 50000), trace = FALSE, iterControl = list(maxiter = 20, tol = 1e-06) )
STR( data, predictors, confidence = NULL, robust = FALSE, lambdas = NULL, pattern = extractPattern(predictors), nFold = 5, reltol = 0.005, gapCV = 1, solver = c("Matrix", "cholesky"), nMCIter = 100, control = list(nnzlmax = 1e+06, nsubmax = 3e+05, tmpmax = 50000), trace = FALSE, iterControl = list(maxiter = 20, tol = 1e-06) )
data |
Time series or a vector of length L. |
predictors |
List of predictors.
|
confidence |
A vector of percentiles giving the coverage of confidence intervals.
It must be greater than 0 and less than 1.
If |
robust |
When |
lambdas |
An optional parameter. A structure which replaces lambda parameters provided with predictors. It is used as either a starting point for the optimisation of parameters or as the exact model parameters. |
pattern |
An optional parameter which has the same structure as |
nFold |
An optional parameter setting the number of folds for cross validation. |
reltol |
An optional parameter which is passed directly to |
gapCV |
An optional parameter defining the length of the sequence of skipped values in the cross validation procedure. |
solver |
A vector with two string values. The only supported combinations are: c("Matrix", "cholesky") (default), and c("Matrix", "qr"). The parameter is used to specify a particular library and method to solve the minimisation problem during STR decompositon. |
nMCIter |
Number of Monte Carlo iterations used to estimate confidence intervals for Robust STR decomposition. |
control |
Passed directly to |
trace |
When |
iterControl |
Control parameters for some experimental features. This should not be used by an ordinary user. |
A structure containing input and output data.
It is an S3 class STR
, which is a list with the following components:
output – contains decomposed data. It is a list of three components:
predictors – a list of components where each component corresponds to the input predictor. Every such component is a list containing the following:
data – fit/forecast for the corresponding predictor (trend, seasonal component, flexible or seasonal predictor).
beta – beta coefficients of the fit of the coresponding predictor.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
random – a list with one component data, which contains residuals of the model fit.
forecast – a list with two components:
data – fit/forecast for the model.
beta – beta coefficients of the fit.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
input – input parameters and lambdas used for final calculations.
data – input data.
predictors - input predictors.
lambdas – smoothing parameters used for final calculations (same as input lambdas for STR method).
cvMSE – optional cross validated (leave one out) Mean Squared Error.
optim.CV.MSE or optim.CV.MAE – best cross validated Mean Squared Error or Mean Absolute Error (n-fold) achieved during minimisation procedure.
nFold – the input nFold
parameter.
gapCV – the input gapCV
parameter.
method – contains strings "STR"
or "RSTR"
depending on used method.
Alexander Dokumentov
Dokumentov, A., and Hyndman, R.J. (2022) STR: Seasonal-Trend decomposition using Regression, INFORMS Journal on Data Science, 1(1), 50-62. https://robjhyndman.com/publications/str/
TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) StaticTempM <- list( name = "Temp Mel", data = TempM, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) StaticTempM2 <- list( name = "Temp Mel^2", data = TempM2, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) Predictors <- list(Trend, WDSeason, StaticTempM, StaticTempM2) elec.fit <- STR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) ######################################################### n <- 70 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 set.seed(1234567890) data <- data + rnorm(length(data), 0, 0.2) data[20] <- data[20] + 3 data[50] <- data[50] - 5 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(1, 0, 1) ) predictors <- list(trend, season) rstr <- STR(data, predictors, reltol = 0.0000001, gapCV = 10, confidence = 0.95, nMCIter = 400, robust = TRUE ) plot(rstr)
TrendSeasonalStructure <- list( segments = list(c(0, 1)), sKnots = list(c(1, 0)) ) WDSeasonalStructure <- list( segments = list(c(0, 48), c(100, 148)), sKnots = c(as.list(c(1:47, 101:147)), list(c(0, 48, 100, 148))) ) TrendSeasons <- rep(1, nrow(electricity)) WDSeasons <- as.vector(electricity[, "WorkingDaySeasonality"]) Data <- as.vector(electricity[, "Consumption"]) Times <- as.vector(electricity[, "Time"]) TempM <- as.vector(electricity[, "Temperature"]) TempM2 <- TempM^2 TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116) SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24) TrendData <- rep(1, length(Times)) SeasonData <- rep(1, length(Times)) Trend <- list( name = "Trend", data = TrendData, times = Times, seasons = TrendSeasons, timeKnots = TrendTimeKnots, seasonalStructure = TrendSeasonalStructure, lambdas = c(1500, 0, 0) ) WDSeason <- list( name = "Dayly seas", data = SeasonData, times = Times, seasons = WDSeasons, timeKnots = SeasonTimeKnots, seasonalStructure = WDSeasonalStructure, lambdas = c(0.003, 0, 240) ) StaticTempM <- list( name = "Temp Mel", data = TempM, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) StaticTempM2 <- list( name = "Temp Mel^2", data = TempM2, times = Times, seasons = NULL, timeKnots = NULL, seasonalStructure = NULL, lambdas = c(0, 0, 0) ) Predictors <- list(Trend, WDSeason, StaticTempM, StaticTempM2) elec.fit <- STR( data = Data, predictors = Predictors, gapCV = 48 * 7 ) plot(elec.fit, xTime = as.Date("2000-01-11") + ((Times - 1) / 48 - 10), forecastPanels = NULL ) ######################################################### n <- 70 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 set.seed(1234567890) data <- data + rnorm(length(data), 0, 0.2) data[20] <- data[20] + 3 data[50] <- data[50] - 5 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(1, 0, 1) ) predictors <- list(trend, season) rstr <- STR(data, predictors, reltol = 0.0000001, gapCV = 10, confidence = 0.95, nMCIter = 400, robust = TRUE ) plot(rstr)
Seasonal-Trend decomposition of time series data using Regression.
STRmodel( data, predictors = NULL, strDesign = NULL, lambdas = NULL, confidence = NULL, solver = c("Matrix", "cholesky"), reportDimensionsOnly = FALSE, trace = FALSE )
STRmodel( data, predictors = NULL, strDesign = NULL, lambdas = NULL, confidence = NULL, solver = c("Matrix", "cholesky"), reportDimensionsOnly = FALSE, trace = FALSE )
data |
Time series or a vector of length L. |
predictors |
List of predictors.
|
strDesign |
An optional parameter used to create the design matrix. It is used internally in the library to improve performance when the design matrix does not require full recalculation. |
lambdas |
An optional parameter. A structure which replaces lambda parameters provided with predictors. It is used as either a starting point for the optimisation of parameters or as the exact model parameters. |
confidence |
A vector of percentiles giving the coverage of confidence intervals.
It must be greater than 0 and less than 1.
If |
solver |
A vector with two string values. The only supported combinations are: c("Matrix", "cholesky") (default), and c("Matrix", "qr"). The parameter is used to specify a particular library and method to solve the minimisation problem during STR decompositon. |
reportDimensionsOnly |
A boolean parameter. When TRUE the method constructs the design matrix and reports its dimensions without proceeding further. It is mostly used for debugging. |
trace |
When |
A structure containing input and output data.
It is an S3 class STR
, which is a list with the following components:
output – contains decomposed data. It is a list of three components:
predictors – a list of components where each component corresponds to the input predictor. Every such component is a list containing the following:
data – fit/forecast for the corresponding predictor (trend, seasonal component, flexible or seasonal predictor).
beta – beta coefficients of the fit of the coresponding predictor.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
random – a list with one component data, which contains residuals of the model fit.
forecast – a list with two components:
data – fit/forecast for the model.
beta – beta coefficients of the fit.
lower – optional (if requested) matrix of lower bounds of confidence intervals.
upper – optional (if requested) matrix of upper bounds of confidence intervals.
input – input parameters and lambdas used for final calculations.
data – input data.
predictors - input predictors.
lambdas – smoothing parameters used for final calculations (same as input lambdas for STR method).
cvMSE – optional cross validated (leave one out) Mean Squared Error.
method – always contains string "STRmodel"
for this function.
Alexander Dokumentov
Dokumentov, A., and Hyndman, R.J. (2022) STR: Seasonal-Trend decomposition using Regression, INFORMS Journal on Data Science, 1(1), 50-62. https://robjhyndman.com/publications/str/
n <- 50 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(10, 0, 0) ) predictors <- list(trend, season) str1 <- STRmodel(data, predictors) plot(str1) data[c(3, 4, 7, 20, 24, 29, 35, 37, 45)] <- NA plot(times, data, type = "l") str2 <- STRmodel(data, predictors) plot(str2)
n <- 50 trendSeasonalStructure <- list(segments = list(c(0, 1)), sKnots = list(c(1, 0))) ns <- 5 seasonalStructure <- list( segments = list(c(0, ns)), sKnots = c(as.list(1:(ns - 1)), list(c(ns, 0))) ) seasons <- (0:(n - 1)) %% ns + 1 trendSeasons <- rep(1, length(seasons)) times <- seq_along(seasons) data <- seasons + times / 4 plot(times, data, type = "l") timeKnots <- times trendData <- rep(1, n) seasonData <- rep(1, n) trend <- list( data = trendData, times = times, seasons = trendSeasons, timeKnots = timeKnots, seasonalStructure = trendSeasonalStructure, lambdas = c(1, 0, 0) ) season <- list( data = seasonData, times = times, seasons = seasons, timeKnots = timeKnots, seasonalStructure = seasonalStructure, lambdas = c(10, 0, 0) ) predictors <- list(trend, season) str1 <- STRmodel(data, predictors) plot(str1) data[c(3, 4, 7, 20, 24, 29, 35, 37, 45)] <- NA plot(times, data, type = "l") str2 <- STRmodel(data, predictors) plot(str2)