vignettes/transformations.Rmd
transformations.RmdWhen working with time series data, transformations are often needed to:
Advantages:
log(), sqrt(),
^, etc.Known Issues with Julia transformations:
SquareRootTransform() has a bug in
ForecastBaselines.jltransform_model() is not implemented in
ForecastBaselines.jlThe general workflow for using transformations:
library(forecastbaselines)
#> Julia version 1.11.9 at location /opt/hostedtoolcache/julia/1.11.9/x64/bin will be used.
#> Loading setup script for JuliaCall...
#> Finish loading setup script for JuliaCall.
#> forecastbaselines: Julia backend loaded successfully
# Initialize Julia and ForecastBaselines
setup_ForecastBaselines()
#> Initializing Julia...
#> Julia initialized successfully
#> Checking ForecastBaselines.jl installation...
#> ForecastBaselines.jl is already installed
#> Loading R conversion helpers...
#> forecastbaselines setup complete!Best for: Multiplicative seasonality, exponential growth, stabilizing variance
# Original data (positive values required)
data <- c(10, 15, 22, 33, 50, 75, 112, 168)
# 1. Transform to log scale
log_data <- log(data)
# 2. Fit model on log scale
model <- ConstantModel()
fitted <- fit_baseline(log_data, model)
# 3. Generate forecasts on log scale
fc <- forecast(fitted,
interval_method = NoInterval(),
horizon = 1:4
)
# 4. Back-transform to original scale
fc$mean <- exp(fc$mean)
if (!is.null(fc$median)) fc$median <- exp(fc$median)
# Result: forecasts in original scale
print(fc$mean)
#> [1] 168 168 168 168Best for: Count data (Poisson-like), moderate variance stabilization
# Count data
data <- c(1, 4, 9, 16, 25, 36, 49, 64)
# 1. Transform
sqrt_data <- sqrt(data)
# 2. Fit model
model <- ARMAModel(p = 1, q = 0)
fitted <- fit_baseline(sqrt_data, model)
# 3. Forecast
fc <- forecast(fitted,
interval_method = NoInterval(),
horizon = 1:4
)
# 4. Back-transform
fc$mean <- fc$mean^2
if (!is.null(fc$median)) fc$median <- fc$median^2
print(fc$mean)
#> [1] 64 64 64 64Best for: Data with zeros, count data, non-negative data
# Data with zeros
data <- c(0, 1, 2, 5, 10, 15, 20, 25)
# 1. Transform (handles zeros gracefully)
log1p_data <- log1p(data) # log(1 + x)
# 2. Fit model
model <- ConstantModel()
fitted <- fit_baseline(log1p_data, model)
# 3. Forecast
fc <- forecast(fitted,
interval_method = NoInterval(),
horizon = 1:4
)
# 4. Back-transform
fc$mean <- expm1(fc$mean) # exp(x) - 1
if (!is.null(fc$median)) fc$median <- expm1(fc$median)
print(fc$mean)
#> [1] 25 25 25 25Best for: Custom variance stabilization, skewness correction
# Skewed data
data <- c(1, 2, 4, 8, 16, 32, 64, 128)
# Box-Cox parameter (λ)
lambda <- 0.3
# 1. Transform
if (lambda == 0) {
transformed_data <- log(data)
} else {
transformed_data <- (data^lambda - 1) / lambda
}
# 2. Fit model
model <- ConstantModel()
fitted <- fit_baseline(transformed_data, model)
# 3. Forecast
fc <- forecast(fitted,
interval_method = NoInterval(),
horizon = 1:4
)
# 4. Back-transform
if (lambda == 0) {
fc$mean <- exp(fc$mean)
} else {
fc$mean <- (fc$mean * lambda + 1)^(1 / lambda)
}
print(fc$mean)
#> [1] 128 128 128 128You can easily compose multiple transformations:
# Original data
data <- c(5, 10, 15, 20, 25, 30, 35, 40)
# 1. Apply multiple transformations
# First, add constant to avoid zeros
data_shifted <- data + 1
# Then log transform
data_transformed <- log(data_shifted)
# 2-3. Fit and forecast
model <- ConstantModel()
fitted <- fit_baseline(data_transformed, model)
fc <- forecast(fitted, interval_method = NoInterval(), horizon = 1:4)
# 4. Back-transform in reverse order
fc$mean <- exp(fc$mean) - 1
print(fc$mean)
#> [1] 40 40 40 40Create your own transformation functions:
# Define custom transformation
my_transform <- function(x) {
# Example: arcsinh transformation (good for data with negatives)
asinh(x)
}
my_inverse <- function(y) {
sinh(y)
}
# Use it
data <- c(-5, -2, 0, 3, 8, 15, 25, 40)
transformed <- my_transform(data)
model <- ConstantModel()
fitted <- fit_baseline(transformed, model)
fc <- forecast(fitted, interval_method = NoInterval(), horizon = 1:4)
fc$mean <- my_inverse(fc$mean)
print(fc$mean)
#> [1] 40 40 40 40When working with prediction intervals, be careful with transformations:
# Generate data
set.seed(123)
data <- exp(rnorm(50, mean = 3, sd = 0.5))
# 1. Log transform
log_data <- log(data)
# 2-3. Fit and forecast with intervals
model <- ConstantModel()
fitted <- fit_baseline(log_data, model)
fc <- forecast(fitted,
interval_method = EmpiricalInterval(n_trajectories = 1000),
horizon = 1:12,
levels = c(0.50, 0.90, 0.95)
)
# 4. Back-transform all components
fc$mean <- exp(fc$mean)
if (!is.null(fc$median)) fc$median <- exp(fc$median)
# Note: Intervals would need special handling if implemented
# For now, intervals are not fully supported in the R package
print(fc$mean)
#> [1] 19.26549 19.26549 19.26549 19.26549 19.26549 19.26549 19.26549 19.26549
#> [9] 19.26549 19.26549 19.26549 19.26549| Transformation | Forward | Inverse | Use Case | Notes |
|---|---|---|---|---|
| Log | log(x) |
exp(y) |
Multiplicative effects | x > 0 required |
| Log + 1 | log1p(x) |
expm1(y) |
Data with zeros | x ≥ 0 |
| Square root | sqrt(x) |
y^2 |
Count data | x ≥ 0 |
| Power | x^λ |
y^(1/λ) |
General variance stabilization | x > 0 |
| Box-Cox | (x^λ - 1)/λ |
(y*λ + 1)^(1/λ) |
Complex cases | x > 0, λ ≠ 0 |
| Arcsinh | asinh(x) |
sinh(y) |
Data with negatives | All x |
Check your data - Ensure transformations are appropriate (e.g., log requires positive data)
Visualize - Plot transformed data to verify it looks reasonable
Consider bias - Back-transforming introduces bias (forecasts of log(x) ≠ log(forecasts of x))
Document - Make transformations explicit in your code and comments
Use functions - Wrap transformation logic in functions for reusability:
forecast_with_log <- function(data, model, horizon) {
# Transform
log_data <- log(data)
# Fit
fitted <- fit_baseline(log_data, model)
# Forecast
fc <- forecast(fitted,
interval_method = NoInterval(),
horizon = horizon
)
# Back-transform
fc$mean <- exp(fc$mean)
if (!is.null(fc$median)) fc$median <- exp(fc$median)
return(fc)
}
# Use it
data <- c(10, 15, 22, 33, 50, 75, 112, 168)
fc <- forecast_with_log(data, ConstantModel(), 1:4)For more information on time series transformations, see: