Commit | Line | Data |
---|---|---|
3a38473a BA |
1 | #' Compute forecast |
2 | #' | |
3 | #' Predict time-series curves ("today" from predict_from to horizon) at the selected days | |
4 | #' indices ("today" from 1am to predict_from-1). This function just runs a loop over all | |
5 | #' requested indices, and stores the individual forecasts into a Forecast object. | |
6 | #' Note: in training stage ts_hat(day+1) = f(ts(day), exo(day+1)), | |
7 | #' and in production ts_hat(day+1) = f(ts(day), exo_hat(day+1)) | |
8 | #' | |
9 | #' @param data Object of class Data, output of \code{getData()}. | |
10 | #' @param indices Indices where to forecast (the day after); integers relative to the | |
11 | #' beginning of data, or (convertible to) Date objects. | |
12 | #' @param forecaster Name of the main forecaster; more details: ?F_<forecastername> | |
13 | #' \itemize{ | |
14 | #' \item Persistence : use last (similar) day | |
15 | #' \item Neighbors : weighted similar days | |
16 | #' \item Average : average curve of all same day-in-week | |
17 | #' \item Zero : just output 0 (benchmarking purpose) | |
18 | #' } | |
19 | #' @param pjump Function to predict the jump at the interface between two days; | |
20 | #' more details: ?J_<functionname> | |
21 | #' \itemize{ | |
22 | #' \item Persistence : use last (similar) day | |
23 | #' \item Neighbors: re-use the weights from F_Neighbors | |
24 | #' \item LastValue: start serie with last observed value | |
25 | #' \item Zero: no adjustment => use shape prediction only | |
26 | #' } | |
27 | #' @param predict_from First time step to predict. | |
28 | #' @param memory Data depth (in days) to be used for prediction. | |
29 | #' @param horizon Last time step to predict. | |
30 | #' @param ncores Number of cores for parallel execution (1 to disable). | |
31 | #' @param verbose TRUE to print basic traces (runs beginnings) | |
32 | #' @param ... Additional parameters for the forecasting models. | |
33 | #' | |
34 | #' @return An object of class Forecast | |
35 | #' | |
36 | #' @examples | |
37 | #' ts_data <- system.file("extdata","intraday_measures.csv",package="talweg") | |
38 | #' exo_data <- system.file("extdata","daily_exogenous.csv",package="talweg") | |
39 | #' data <- getData(ts_data, exo_data, date_format="%Y-%m-%d %H:%M:%S", limit=200) | |
40 | #' pred <- computeForecast(data, 100:130, "Persistence", "LastValue", | |
41 | #' predict_from=8, memory=50, horizon=12, ncores=1) | |
42 | #' \dontrun{ | |
43 | #' #Sketch for real-time mode: | |
44 | #' data <- Data$new() | |
45 | #' forecaster <- MyForecaster$new(myJumpPredictFunc) | |
46 | #' repeat { | |
47 | #' # As soon as daily predictions are available: | |
48 | #' data$append( | |
49 | #' level_hat=predicted_level, | |
50 | #' exo_hat=predicted_exogenous) | |
51 | #' # When a day ends: | |
52 | #' data$append( | |
53 | #' level=observed_level, | |
54 | #' exo=observed_exogenous) | |
55 | #' # And, at every hour: | |
56 | #' data$append( | |
57 | #' time=current_hour, | |
58 | #' value=current_PM10) | |
59 | #' # Finally, a bit before predict_from hour: | |
60 | #' pred <- forecaster$predictSerie(data, data$getSize(), ...) | |
61 | #' #do_something_with_pred | |
62 | #' } } | |
63 | #' @export | |
64 | computeForecast = function(data, indices, forecaster, pjump, predict_from, | |
65 | memory=Inf, horizon=length(data$getSerie(1)), ncores=3, verbose=FALSE, ...) | |
66 | { | |
67 | # (basic) Arguments sanity checks | |
68 | predict_from = as.integer(predict_from)[1] | |
69 | if (! predict_from %in% 1:length(data$getSerie(1))) | |
70 | stop("predict_from in [1,24] (hours)") | |
71 | if (hasArg("opera") && !list(...)$opera && memory < Inf) | |
72 | memory <- Inf #finite memory in training mode makes no sense | |
73 | horizon = as.integer(horizon)[1] | |
74 | if (horizon<=predict_from || horizon>length(data$getSerie(1))) | |
75 | stop("Horizon in [predict_from+1,24] (hours)") | |
76 | integer_indices = sapply(indices, function(i) dateIndexToInteger(i,data)) | |
77 | if (any(integer_indices<=0 | integer_indices>data$getSize())) | |
78 | stop("Indices out of range") | |
79 | if (!is.character(forecaster)) | |
80 | stop("forecaster (name): character") | |
81 | if (!is.character(pjump)) | |
82 | stop("pjump (function): character") | |
83 | ||
84 | pred = Forecast$new( sapply(indices, function(i) integerIndexToDate(i,data)) ) | |
85 | forecaster_class_name = getFromNamespace( | |
86 | paste(forecaster,"Forecaster",sep=""), "talweg") | |
87 | ||
88 | pjump <- getFromNamespace(paste("get",pjump,"JumpPredict",sep=""), "talweg") | |
89 | forecaster = forecaster_class_name$new(pjump) | |
90 | ||
91 | computeOneForecast <- function(i) | |
92 | { | |
93 | if (verbose) | |
94 | print(paste("Index",i)) | |
95 | list( | |
96 | "forecast" = forecaster$predictSerie(data,i,memory,predict_from,horizon,...), | |
97 | "params" = forecaster$getParameters(), | |
98 | "index" = i ) | |
99 | } | |
100 | ||
101 | p <- | |
102 | if (ncores > 1 && requireNamespace("parallel",quietly=TRUE)) | |
103 | parallel::mclapply(integer_indices, computeOneForecast, mc.cores=ncores) | |
104 | else | |
105 | lapply(integer_indices, computeOneForecast) | |
106 | ||
107 | # TODO: find a way to fill pred in //... | |
108 | for (i in seq_along(integer_indices)) | |
109 | { | |
110 | pred$append( | |
111 | forecast = p[[i]]$forecast, | |
112 | params = p[[i]]$params, | |
113 | index_in_data = p[[i]]$index | |
114 | ) | |
115 | } | |
116 | pred | |
117 | } |