forked from tidyverts/feasts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclassical.R
112 lines (99 loc) · 3.52 KB
/
classical.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
specials_classical <- fabletools::new_specials(
season = function(period = NULL){
period <- get_frequencies(period, self$data, .auto = "smallest")
if(length(period) > 1){
warn("Multiple seasonal decomposition is not supported by classical decomposition")
}
period[[1]]
},
.required_specials = c("season")
)
train_classical <- function(.data, formula, specials,
type = c("additive", "multiplicative"), ...){
stopifnot(is_tsibble(.data))
type <- match.arg(type)
resp <- measured_vars(.data)
y <- .data[[resp]]
m <- specials$season[[1]]
dcmp_op <- switch(type,
additive = "+",
multiplicative = "*")
dcmp_op_inv <- switch(type,
additive = "-",
multiplicative = "/")
dcmp <- decompose(ts(y, frequency = m), type = type, ...)[c("trend", "seasonal", "random")]
dcmp <- .data %>%
mutate(
!!!map(dcmp, as.numeric),
season_adjust = !!call2(dcmp_op_inv, sym(resp), sym("seasonal"))
)
seasonalities <- list(
seasonal = list(period = m, base = switch(dcmp_op, `+` = 0, 1))
)
aliases <- list2(
!!resp := reduce(syms(c("trend", "seasonal", "random")),
function(x,y) call2(dcmp_op, x, y)),
season_adjust = call2(dcmp_op_inv, sym(resp), sym("seasonal"))
)
structure(
list(decomposition = dcmp,
response = resp, method = "Classical",
seasons = seasonalities, aliases = aliases
),
class = "classical_decomposition"
)
}
#' @importFrom fabletools components as_dable
#' @export
components.classical_decomposition <- function(object, ...){
as_dable(object[["decomposition"]], response = !!sym(object[["response"]]),
method = object[["method"]], seasons = object[["seasons"]],
aliases = object[["aliases"]])
}
#' @importFrom fabletools model_sum
#' @export
model_sum.classical_decomposition <- function(x){
"DECOMPOSITION"
}
#' Classical Seasonal Decomposition by Moving Averages
#'
#' @inherit stats::decompose description details
#'
#' @param formula Decomposition specification (see "Specials" section).
#' @param ... Other arguments passed to [`stats::decompose()`].
#' @inheritParams stats::decompose
#'
#' @return A [`fabletools::dable()`] containing the decomposed trend, seasonality
#' and remainder from the classical decomposition.
#'
#' @section Specials:
#'
#' \subsection{season}{
#' The `season` special is used to specify seasonal attributes of the decomposition.
#' \preformatted{
#' season(period = NULL)
#' }
#'
#' \tabular{ll}{
#' `period` \tab The periodic nature of the seasonality. This can be either a number indicating the number of observations in each seasonal period, or text to indicate the duration of the seasonal window (for example, annual seasonality would be "1 year").
#' }
#' }
#'
#' @examples
#' as_tsibble(USAccDeaths) %>%
#' model(classical_decomposition(value)) %>%
#' components()
#'
#' as_tsibble(USAccDeaths) %>%
#' model(classical_decomposition(value ~ season(12), type = "mult")) %>%
#' components()
#'
#' @importFrom stats ts decompose
#' @importFrom fabletools new_model_class new_model_definition
#' @export
classical_decomposition <- function(formula, type = c("additive", "multiplicative"), ...){
dcmp <- new_model_class("Classical decomposition",
train = train_classical, specials = specials_classical,
check = all_tsbl_checks)
new_model_definition(dcmp, !!enquo(formula), type = type, ...)
}