În lumea prognozării seriilor de timp, metodele de comparare cu competițiile consacrate sunt cruciale. Astăzi, împărtășesc rezultatele unei comparații cuprinzătoare între două abordări de prognoză: metoda clasică Theta (notoriu dificil de învins pe seturile de date de referință alese) și algoritmul mai nou Dynrmf (de la pachetele R și Python înainte), testat în cadrul a trei competiții majore de prognoză.
Configurarea
Am evaluat ambele metode pe:
- Competiția M3: 3.003 serii temporale diverse
- Concurs M1: Setul de date original M-competition (1001 serii temporale)
- Concurs de turism: Date despre serii temporale specifice turismului (1311 serii temporale)
Pentru fiecare set de date, am antrenat ambele modele pe date istorice și le-am evaluat previziunile față de seturi de teste reținute folosind metrici de precizie standard (ME, RMSE, MAE, MPE, MAPE, MASE, ACF1). Fiecare model își folosește parametrii impliciti.
Detalii de implementare
Analiza a folosit procesare paralelă cu 2 nuclee pentru a accelera calculele pe mii de serii. Ambele metode au primit împărțiri identice de tren/test pentru o comparație corectă – cod complet la sfârșitul postării.
# Example forecasting loop structure
metrics <- foreach(i = 1:n, .combine = rbind)%dopar%{
series <- dataset((i))
train <- series$x
test <- series$xx
fit <- method(y = train, h = length(test))
forecast::accuracy(fit)
}
Rezultate
Merită menționat că Theta a fost câștigătorul clar al competiției M3 (și a fost îmbunătățit în multe feluri) și, desigur, este întotdeauna mai ușor să învingi câștigătorul a posteriori.
Am efectuat teste t pereche privind diferența de valori (Theta – Dynrmf) în toate seriile din fiecare competiție. Iată ce dezvăluie cifrele:
Rezultatele competiției M3
| Metric | t-statistică | valoarea p | Interpretare |
|---|---|---|---|
| EU | 16.96 | <0,001 | Theta semnificativ mai părtinitoare |
| RMSE | 10.17 | <0,001 | Theta semnificativ mai rău |
| MAE | 7,65 | <0,001 | Theta semnificativ mai rău |
| MPE | -5,59 | <0,001 | Dynrmf mai părtinitoare |
| MAPE | 1.29 | 0,197 | Nicio diferență semnificativă |
| MASE | 14.09 | <0,001 | Theta semnificativ mai rău |
| ACF1 | -1,37 | 0,171 | Nicio diferență semnificativă |
Verdict: Dynrmf demonstrează o acuratețe substanțial mai bună pe datele M3 pentru majoritatea valorilor de eroare.
Rezultatele competiției M1
| Metric | t-statistică | valoarea p | Interpretare |
|---|---|---|---|
| EU | 2,56 | 0,011 | Theta mai părtinitoare |
| RMSE | 2,94 | 0,003 | Theta semnificativ mai rău |
| MAE | 2.28 | 0,023 | Theta semnificativ mai rău |
| MPE | -0,61 | 0,540 | Nicio diferență semnificativă |
| MAPE | 0,38 | 0,703 | Nicio diferență semnificativă |
| MASE | -0,74 | 0,461 | Nicio diferență semnificativă |
| ACF1 | -6,50 | <0,001 | Dynrmf reziduuri mai bine |
Verdict: Dynrmf prezintă îmbunătățiri moderate, dar semnificative statistic, în special în RMSE și MAE.
Rezultatele concursului de turism
| Metric | t-statistică | valoarea p | Interpretare |
|---|---|---|---|
| EU | 1,62 | 0,105 | Nicio diferență semnificativă |
| RMSE | 1,88 | 0,060 | Avantaj marginal pentru Dynrmf |
| MAE | 1.16 | 0,245 | Nicio diferență semnificativă |
| MPE | 4,52 | <0,001 | Theta mai puțin părtinitoare |
| MAPE | -5.03 | <0,001 | Dynrmf semnificativ mai bun |
| MASE | -5,17 | <0,001 | Dynrmf semnificativ mai bun |
| ACF1 | -8,65 | <0,001 | Dynrmf reziduuri mai bine |
Verdict: În ceea ce privește datele turistice, Dynrmf excelează la valorile scalate (MAPE, MASE) și produce reziduuri cu un comportament mai bun.
Recomandări cheie
- Dynrmf depășește în mod constant Theta privind valorile de precizie precum RMSE, MAE și MASE în cadrul competițiilor
- Avantajul este cel mai puternic pe M3sugerând că Dynrmf gestionează bine diverse tipuri de serii
- Datele turistice arată puterea Dynrmf în procente și valori de eroare scalate
- Autocorelație reziduală (ACF1) este în mod constant mai bun cu Dynrmf, indicând că captează modelele mai complet
- Flexibilitate independentă de model: Este important de menționat că, spre deosebire de abordările specifice metodei, Dynrmf ar accepta orice funcție de potrivire (iar implicită aici este regresia automată Ridge care minimizează eroarea de validare încrucișată generalizată) prin intermediul acestuia
fit_funcparametrul (vezi aici), permițând utilizarea regresiei Ridge (implicit), Random Forest, XGBoost, Support Vector Machines sau orice alt model cu interfețe standard de potrivire/predire
Disponibilitatea codului
Implementarea completă a R este disponibilă mai jos. Analiza folosește procesarea paralelă pentru eficiență pe seturi mari de date de concurență.
library(ahead)
library(Mcomp)
library(Tcomp)
library(foreach)
library(doParallel)
library(doSNOW)
setwd("~/Documents/Papers/to_submit/2026-01-01-dynrmf-vs-Theta-on-M1-M3-Tourism")
# 1. M3 comp. results --------------
data(M3)
n <- length(Mcomp::M3)
training_indices <- seq_len(n)
# Theta -----------
metrics_theta <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_theta <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- M3((i))
train <- series$x
test <- series$xx
fit <- forecast::thetaf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_theta)
# Dynrmf -----------
metrics_dynrmf <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_dynrmf <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- M3((i))
train <- series$x
test <- series$xx
fit <- ahead::dynrmf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_dynrmf)
diff_metrics <- metrics_theta - metrics_dynrmf
M3_results <- apply(diff_metrics, 2, t.test)
M3_results <- apply(diff_metrics, 2, function(x) {z <- t.test(x); return(c(z$statistic, z$p.value))})
rownames(M3_results) <- c("statistic", "p-value")
# 2. M1 comp. results -----------------
data(M1)
n <- length(Mcomp::M1)
training_indices <- seq_len(n)
# Theta -----------
metrics_theta <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_theta <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- M1((i))
train <- series$x
test <- series$xx
fit <- forecast::thetaf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_theta)
# Dynrmf -----------
metrics_dynrmf <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_dynrmf <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- M1((i))
train <- series$x
test <- series$xx
fit <- ahead::dynrmf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_dynrmf)
diff_metrics <- metrics_theta - metrics_dynrmf
M1_results <- apply(diff_metrics, 2, function(x) {z <- t.test(x); return(c(z$statistic, z$p.value))})
rownames(M1_results) <- c("statistic", "p-value")
# 2. Tourism comp. results -----------------
data(tourism)
n <- length(Tcomp::tourism)
training_indices <- seq_len(n)
# Theta -----------
metrics_theta <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_theta <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- tourism((i))
train <- series$x
test <- series$xx
fit <- forecast::thetaf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_theta)
# Dynrmf -----------
metrics_dynrmf <- rep(NA, n)
pb <- utils::txtProgressBar(max = n, style = 3)
doParallel::registerDoParallel(cl=2)
# looping on all the training set time series
metrics_dynrmf <- foreach::foreach(i = 1:n,
.combine = rbind, .verbose = TRUE)%dopar%{
series <- tourism((i))
train <- series$x
test <- series$xx
fit <- ahead::dynrmf(
y = train,
h = length(test))
utils::setTxtProgressBar(pb, i)
forecast::accuracy(fit)
}
close(pb)
print(metrics_dynrmf)
diff_metrics <- metrics_theta - metrics_dynrmf
diff_metrics <- diff_metrics(is.finite(diff_metrics(, 4)), )
Tourism_results <- apply(diff_metrics, 2, function(x) {z <- t.test(x); return(c(z$statistic, z$p.value))})
rownames(Tourism_results) <- c("statistic", "p-value")
# # Theta - dynrmf+default
#
# ```R
# kableExtra::kable(M3_results)
# kableExtra::kable(M1_results)
# kableExtra::kable(Tourism_results)
#
# | | ME| RMSE| MAE| MPE| MAPE| MASE| ACF1|
# |:---------|--------:|--------:|--------:|---------:|---------:|-------:|----------:|
# |statistic | 16.96265| 10.16816| 7.652445| -5.586289| 1.2900974| 14.0924| -1.3680305|
# |p-value | 0.00000| 0.00000| 0.000000| 0.000000| 0.1971162| 0.0000| 0.1714049|
#
# | | ME| RMSE| MAE| MPE| MAPE| MASE| ACF1|
# |:---------|---------:|---------:|---------:|----------:|---------:|----------:|---------:|
# |statistic | 2.5575962| 2.9406984| 2.2815166| -0.6129693| 0.3808239| -0.7378457| -6.497644|
# |p-value | 0.0106864| 0.0033502| 0.0227274| 0.5400360| 0.7034148| 0.4607813| 0.000000|
#
# | | ME| RMSE| MAE| MPE| MAPE| MASE| ACF1|
# |:---------|---------:|---------:|---------:|---------:|----------:|----------:|---------:|
# |statistic | 1.6239829| 1.8845405| 1.1628106| 4.5207962| -5.0276196| -5.1743478| -8.648504|
# |p-value | 0.1046342| 0.0597262| 0.2451306| 0.0000068| 0.0000006| 0.0000003| 0.000000|
#
# ```
Ce metode de prognoză ați găsit cele mai de încredere în munca dvs.? Împărtășește-ți experiențele în comentariile de mai jos.
Vă rugăm să semnați și să distribuiți această petiție https://www.change.org/stop_torturing_T_Moudiki – după ce mi-am cercetat în mod serios trecutul și contribuțiile în domeniu.

