revise package structure: always predict from 1am to horizon, dataset not cut at...
authorBenjamin Auder <benjamin.auder@somewhere>
Mon, 24 Apr 2017 19:19:45 +0000 (21:19 +0200)
committerBenjamin Auder <benjamin.auder@somewhere>
Mon, 24 Apr 2017 19:19:45 +0000 (21:19 +0200)
20 files changed:
Etude_En_Cours_R_E_bis.R [new file with mode: 0644]
pkg/R/Data.R
pkg/R/F_Average.R
pkg/R/F_Neighbors.R
pkg/R/F_Persistence.R
pkg/R/F_Zero.R
pkg/R/Forecast.R
pkg/R/Forecaster.R
pkg/R/J_Neighbors.R
pkg/R/J_Persistence.R
pkg/R/computeError.R
pkg/R/computeForecast.R
pkg/R/getData.R
pkg/R/plot.R
pkg/R/utils.R
pkg/tests/testthat/helper.R
pkg/tests/testthat/test-DateIntegerConv.R
pkg/tests/testthat/test-Forecaster.R
pkg/tests/testthat/test-computeFilaments.R
reports/PackageR.gj

diff --git a/Etude_En_Cours_R_E_bis.R b/Etude_En_Cours_R_E_bis.R
new file mode 100644 (file)
index 0000000..69b1da0
--- /dev/null
@@ -0,0 +1,136 @@
+setwd("/Users/bp/Desktop/CONTRATS_AirNormand/2016/RapportFinalBruno")
+rm(list=ls())
+
+# Lecture des données
+pm  =  read.table("DATA/mesures_horaires_hloc_pm10_a_filer.csv",sep=";",dec=".",header=T) #,row.names=1)
+n     = dim(pm)[1]
+datedebut = "10/12/2008"
+
+# Chargement des données météo et indicateurs
+VarExp <- read.table("DATA/meteo_extra_jourMois.csv",sep=";",dec=".",header=T)
+VarExp <- VarExp[-1,]
+
+# Lecture des dates
+dates =  read.table("DATA/Dates_jours.csv",header=F,as.is=T)
+dates = dates[,1]
+
+# Contruction des matrices de données
+pm.h   <- matrix(pm[,2],ncol=24,byrow=TRUE)
+
+Nlignes = nrow(pm.h)
+Data = cbind(pm.h[1:(Nlignes -1), ], pm.h[2:Nlignes, ])
+dates2 = dates[2:Nlignes]
+rownames(Data) = dates2
+# df contient l'ensemble des données.
+#df <- cbind(Data,varexp[,-1])
+df <- Data
+PMjour <- apply(df[,25:48],1,mean,na.rm=T)
+dfexp <- cbind(VarExp,PMjour)
+
+Dates = c(
+"16/03/2015",
+"19/01/2015",
+"27/04/2015")
+
+Categorie = c("Epandage", "Chauffage", "Non Polluée")
+
+RepFig = "FIGURES_Etude"
+
+ResDates = NULL
+
+nbvois=10
+j=1 # numéro de semaine
+ij=6 # numéro du jour (0 = lundi)
+
+Err24 = NULL
+ErrPrev = NULL
+Kvois = NULL
+
+for (Hc in 5:24) {
+
+H=24+Hc
+fen=H
+#fen=12 ou 24 ou H
+L = (H-fen+1):H
+
+# Premier conditionnement : mois
+indcond <- dfexp[,"Mois"] == 2 | dfexp[,"Mois"] == 3 | dfexp[,"Mois"] == 4 | dfexp[,"Mois"] == 9 | dfexp[,"Mois"] == 10
+data = df[indcond,]
+varexp = dfexp[indcond,]
+
+nl = (1:nrow(data))[rownames(data)==Dates[j]]
+dateJPrev = rownames(data)[nl+ij]
+dataj = as.numeric(data[nl+ij, 1:48])
+data = data[-(nl + ij), ]
+varexp = varexp[-(nl + ij), ]
+indNA = attr(na.omit(data[, 1:48]),"na.action")
+data = data[-indNA,]
+varexp = varexp[-indNA,]
+
+# Conditionnement : les jours avec PMjour +/- large
+large = 1
+bornes = mean(dataj[25:48])+c(-large,large)
+indcond = varexp[,"PMjour"]>=bornes[1] & varexp[,"PMjour"]<=bornes[2]
+data = data[indcond,]
+varexp = varexp[indcond,]
+
+D = rep(0,nrow(data))
+for (k in 1:nrow(data)) {
+       #D[k] = sqrt(sum((1:H)*(dataj[L] -data[k,L])^2))
+       D[k] = sqrt(sum((dataj[L] -data[k,L])^2))
+}
+ind = order(D)[1:nbvois]
+w = 1/(D[ind]^2)
+w = w/sum(w)
+W = w%o%rep(1,48)
+JourMoy = apply(data[ind, 1:48], 2, mean)
+#JourMoy = apply(W*data[ind, 1:48], 2, sum)
+NomFile = paste("Voisins_Epandage_PMjour_Hc_",Hc,".png",sep="")
+Titre = paste("Jour à prévoir : ",dateJPrev," - ", length(ind)," voisins",sep="")
+#erreur = sqrt(sum((dataj[25:48] - JourMoy[25:48])^2))
+if(Hc==24){erreurPrev=NA}else{erreurPrev = mean(abs(dataj[(H+1):48] - JourMoy[(H+1):48]))}
+erreur24 = mean(abs(dataj[25:48] - JourMoy[25:48]))
+png(NomFile)
+matplot(t(data[ind, 1:48]), type = "l", lwd=1.4, lty=1, col=1:length(ind), 
+       cex.axis=1.4, cex.main = 1.7, cex.lab=1.5, 
+       xlab="Heures locales", ylab=paste0("PM10 - Erreurs = ",round(erreur24,1)," / ",round(erreurPrev,1)), main=Titre)
+legend("top",rownames(data)[ind],ncol=2,lwd=1.4, lty=1, col=1:length(ind))
+lines(1:48, dataj, lwd=2.5)
+lines(JourMoy, lty = 2, lwd=2)
+abline(v=c(24.5,H+0.5), lty = 2, lwd=1.2)
+xx=dev.off()
+
+
+
+  Err24 = c(Err24, erreur24)
+  ErrPrev = c(ErrPrev, erreurPrev)
+ResDates = cbind(ResDates, rownames(data)[ind])
+}
+
+
+rownames(ResDates) = 1:10
+
+Kvois = NULL
+for (Col in ncol(ResDates):1) {
+K = 0
+for (I in 1:10){
+    for (J in 1:10){
+       if (ResDates[I,1] == ResDates[J,Col]) K = K +1
+     }
+}
+Kvois = c(Kvois, K)
+}
+
+# pdf("Erreur_Epandage_PMjour.pdf")
+ymin = min(na.omit(ErrPrev), Err24)
+ymin = min(ymin, Kvois)
+ymax = max(na.omit(ErrPrev), Err24)
+ymax = max(ymax, Kvois)
+plot(5:24,Err24, type = "l", lwd = 2, cex.axis=1.4, cex.lab = 1.5,
+  ylab = "MAE",xlab = "Heures de prévision", ylim= c(ymin,ymax))
+lines(5:24,ErrPrev, lwd=2, lty = 2)
+legend("topright", legend=c("Erreur 24h", "Erreur prévision"), lty = c(1,2), lwd=2, cex=1.5)
+points(5:24, Kvois, cex=1.8, pch = 19)
+# xx = dev.off()
+
+length(D)
index 33db5c9..39e34de 100644 (file)
@@ -2,53 +2,47 @@
 #'
 #' Data encapsulation as a list (days) of lists (components).
 #'
-#' The private field .data is a list where each cell contains the variables for a period
-#' of time of 24 hours, from time P+1 until P the next day where P is an integer between
-#' 0 and 23. .data[[1]] refers to the first measured data (serie and exogenous
-#' variables): the corresponding times can be accessed through the function
-#' \code{getTime()} below. Each cell .data[[i]] is itself a list containing five slots,
-#' as described in the 'field' section.
+#' The private field .tv is a list where each cell contains the hourly variables for a
+#' period of time of 24 hours, from 1am to next midnight. The other lists contain
+#' informations on series' levels and exogenous variables (both measured and predicted).
 #'
 #' @usage # Data$new()
 #'
-#' @field .data[[i]] List of
+#' @field .tv List of "time-values"; in each cell:
 #' \itemize{
 #'   \item time: vector of times
-#'   \item centered_serie: centered serie
-#'   \item level: corresponding level
-#'   \item exo: exogenous variables
-#'   \item exo_hat: predicted exogenous variables (for next day)
+#'   \item serie: (measured) serie
 #' }
+#' @field .level Vector of measured levels
+#' @field .level_hat Vector of predicted levels
+#' @field .exo List of measured exogenous variables, cell = numerical vector.
+#' @field .exo_hat List of predicted exogenous variables, cell = numerical vector.
 #'
 #' @section Methods:
 #' \describe{
 #' \item{\code{getSize()}}{
 #'   Number of series in dataset.}
-#' \item{\code{getStdHorizon()}}{
-#'   Number of time steps from serie[1] until midnight}
-#' \item{\code{append(time, serie, exo, exo_hat)}}{
+#' \item{\code{append(time, value, level_hat, exo, exo_hat)}}{
 #'   Measured data for given vector of times + exogenous predictions from
 #'   last midgnight.}
 #' \item{\code{getTime(index)}}{
 #'   Times (vector) at specified index.}
-#' \item{\code{getCenteredSerie(index)}}{
-#'   Centered serie at specified index.}
-#' \item{\code{getCenteredSeries(indices)}}{
-#'   Centered series at specified indices (in columns).}
-#' \item{\code{getLevel(index)}}{
-#'   Level at specified index.}
 #' \item{\code{getSerie(index)}}{
 #'   Serie (centered+level) at specified index.}
 #' \item{\code{getSeries(indices)}}{
 #'   Series at specified indices (in columns).}
-#' \item{\code{getExoHat(index)}}{
-#'   Predicted exogenous variables at specified index.}
+#' \item{\code{getLevel(index)}}{
+#'   Measured level at specified index.}
+#' \item{\code{getLevelHat(index)}}{
+#'   Predicted level at specified index.}
+#' \item{\code{getCenteredSerie(index)}}{
+#'   Centered serie at specified index.}
+#' \item{\code{getCenteredSeries(indices)}}{
+#'   Centered series at specified indices (in columns).}
 #' \item{\code{getExo(index)}}{
 #'   Measured exogenous variables at specified index.}
-#' \item{\code{removeFirst()}}{
-#'   Remove first list element (if truncated).}
-#' \item{\code{removeLast()}}{
-#'   Remove last list element (if truncated).}
+#' \item{\code{getExoHat(index)}}{
+#'   Predicted exogenous variables at specified index.}
 #' }
 #'
 #' @docType class
 #'
 Data = R6::R6Class("Data",
        private = list(
-               .data = list()
+               .tv = list(),
+               .level = vector("double",0),
+               .level_hat = vector("double",0),
+               .exo = list(),
+               .exo_hat = list()
        ),
        public = list(
                getSize = function()
-                       length(private$.data)
-               ,
-               getStdHorizon = function()
-                       24 - as.POSIXlt( private$.data[[1]]$time[1] )$hour + 1
+                       length(private$.tv)
                ,
-               append = function(time, serie, exo, exo_hat)
+               append = function(time=NULL, value=NULL, level_hat=NULL, exo=NULL, exo_hat=NULL)
                {
-                       level = mean(serie, na.rm=TRUE)
-                       centered_serie = serie - level
-                       private$.data[[length(private$.data)+1]] <- list(
-                               "time"=time, #H-24 --> H-1
-                               "centered_serie"=centered_serie, #at 'time'
-                               "level"=level, #at 'time'
-                               "exo"=exo, #at 'time' (yersteday 0am to last midnight)
-                               "exo_hat"=exo_hat) #today 0am to next midnight
+                       if (!is.null(time) && !is.null(value))
+                       {
+                               L = length(private$.tv)
+                               if (L == 0 || strftime( tail(private$.tv[[L]]$time,1),
+                                       format="%H:%M:%S", tz="GMT" ) == "00:00:00")
+                               {
+                                       # Append a new cell
+                                       private$.tv[[L+1]] <- list("time"=time, "serie"=value)
+                               }
+                               else
+                               {
+                                       # Complete current cell
+                                       private$.tv[[L]]$time = c(private$.tv[[L]]$time, time)
+                                       private$.tv[[L]]$serie = c(private$.tv[[L]]$serie, value)
+                               }
+                       }
+                       if (strftime( tail(private$.tv[[length(private$.tv)]]$time,1),
+                                       format="%H:%M:%S", tz="GMT" ) == "00:00:00")
+                       {
+                               private$.level = c(private$.level,
+                                       mean(private$.tv[[length(private$.tv)]]$serie, na.rm=TRUE))
+                       }
+                       if (!is.null(level_hat))
+                               private$.level_hat = c(private$.level_hat, level_hat)
+                       if (!is.null(exo))
+                               private$.exo[[length(private$.exo)+1]] = exo
+                       if (!is.null(exo_hat))
+                               private$.exo_hat[[length(private$.exo_hat)+1]] = exo_hat
                },
                getTime = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$time
+                       private$.tv[[index]]$time
                },
-               getCenteredSerie = function(index)
+               getSerie = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$centered_serie
+                       private$.tv[[index]]$serie
                },
-               getCenteredSeries = function(indices)
-                       sapply(indices, function(i) self$getCenteredSerie(i))
+               getSeries = function(indices)
+                       sapply(indices, function(i) self$getSerie(i))
                ,
                getLevel = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$level
+                       private$.level[index]
                },
-               getSerie = function(index)
+               getLevelHat = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$centered_serie + private$.data[[index]]$level
+                       private$.level_hat[index]
                },
-               getSeries = function(indices)
-                       sapply(indices, function(i) self$getSerie(i))
-               ,
-               getExoHat = function(index)
+               getCenteredSerie = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$exo_hat
+                       private$.tv[[index]]$serie - private$.level[index]
                },
+               getCenteredSeries = function(indices)
+                       sapply(indices, function(i) self$getCenteredSerie(i))
+               ,
                getExo = function(index)
                {
                        index = dateIndexToInteger(index, self)
-                       private$.data[[index]]$exo
+                       private$.exo[[index]]
                },
-               removeFirst = function()
-                       private$.data <- private$.data[2:length(private$.data)]
-               ,
-               removeLast = function()
-                       private$.data <- private$.data[1:(length(private$.data)-1)]
+               getExoHat = function(index)
+               {
+                       index = dateIndexToInteger(index, self)
+                       private$.exo_hat[[index]]
+               }
        )
 )
index d0b40b4..6cd2d6e 100644 (file)
@@ -17,25 +17,23 @@ AverageForecaster = R6::R6Class("AverageForecaster",
        inherit = Forecaster,
 
        public = list(
-               predictShape = function(data, today, memory, horizon, ...)
+               predictShape = function(data, today, memory, predict_from, horizon, ...)
                {
-                       avg = rep(0., horizon)
+                       avg = rep(0., (horizon-predict_from+1))
                        first_day = max(1, today-memory)
-                       index = today-7 + 1
+                       index <- today
                        nb_no_na_series = 0
                        repeat
                        {
-                               {
-                                       serie_on_horizon = data$getCenteredSerie(index)[1:horizon]
-                                       index = index - 7
-                               };
+                               index = index - 7
+                               if (index < first_day)
+                                       break
+                               serie_on_horizon = data$getCenteredSerie(index)[predict_from:horizon]
                                if (!any(is.na(serie_on_horizon)))
                                {
                                        avg = avg + serie_on_horizon
                                        nb_no_na_series = nb_no_na_series + 1
-                               };
-                               if (index < first_day)
-                                       break
+                               }
                        }
                        avg / nb_no_na_series
                }
index 1437442..ea18bb6 100644 (file)
@@ -4,14 +4,15 @@
 #' where days in the past are chosen and weighted according to some similarity measures.
 #'
 #' The main method is \code{predictShape()}, taking arguments data, today, memory,
-#' horizon respectively for the dataset (object output of \code{getData()}), the current
-#' index, the data depth (in days) and the number of time steps to forecast.
+#' predict_from, horizon respectively for the dataset (object output of
+#' \code{getData()}), the current index, the data depth (in days), the first predicted
+#' hour and the last predicted hour.
 #' In addition, optional arguments can be passed:
 #' \itemize{
 #'   \item local : TRUE (default) to constrain neighbors to be "same days within same
 #'     season"
 #'   \item simtype : 'endo' for a similarity based on the series only,<cr>
-#'             'exo' for a similaruty based on exogenous variables only,<cr>
+#'             'exo' for a similarity based on exogenous variables only,<cr>
 #'             'mix' for the product of 'endo' and 'exo',<cr>
 #'             'none' (default) to apply a simple average: no computed weights
 #'   \item window : A window for similarities computations; override cross-validation
@@ -38,17 +39,20 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
        inherit = Forecaster,
 
        public = list(
-               predictShape = function(data, today, memory, horizon, ...)
+               predictShape = function(data, today, memory, predict_from, horizon, ...)
                {
                        # (re)initialize computed parameters
                        private$.params <- list("weights"=NA, "indices"=NA, "window"=NA)
 
                        # Do not forecast on days with NAs (TODO: softer condition...)
-                       if (any(is.na(data$getCenteredSerie(today))))
+                       if (any(is.na(data$getSerie(today-1)))
+                               || any(is.na(data$getSerie(today)[1:(predict_from-1)])))
+                       {
                                return (NA)
+                       }
 
                        # Determine indices of no-NAs days followed by no-NAs tomorrows
-                       fdays = .getNoNA2(data, max(today-memory,1), today-1)
+                       fdays = .getNoNA2(data, max(today-memory,1), today-2)
 
                        # Get optional args
                        local = ifelse(hasArg("local"), list(...)$local, TRUE) #same level + season?
@@ -56,7 +60,7 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                        if (hasArg("window"))
                        {
                                return ( private$.predictShapeAux(data,
-                                       fdays, today, horizon, local, list(...)$window, simtype, TRUE) )
+                                       fdays, today, predict_from, horizon, local, list(...)$window, simtype, TRUE) )
                        }
 
                        # Indices of similar days for cross-validation; TODO: 20 = magic number
@@ -71,13 +75,13 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                for (i in seq_along(cv_days))
                                {
                                        # mix_strategy is never used here (simtype != "mix"), therefore left blank
-                                       prediction = private$.predictShapeAux(data, fdays, cv_days[i], horizon, local,
-                                               window, simtype, FALSE)
+                                       prediction = private$.predictShapeAux(data, fdays, cv_days[i], predict_from,
+                                               horizon, local, window, simtype, FALSE)
                                        if (!is.na(prediction[1]))
                                        {
                                                nb_jours = nb_jours + 1
                                                error = error +
-                                                       mean((data$getSerie(cv_days[i]+1)[1:horizon] - prediction)^2)
+                                                       mean((data$getSerie(cv_days[i]+1)[predict_from:horizon] - prediction)^2)
                                        }
                                }
                                return (error / nb_jours)
@@ -105,14 +109,14 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                else #none: value doesn't matter
                                        1
 
-                       return(private$.predictShapeAux(data, fdays, today, horizon, local,
-                               best_window, simtype, TRUE))
+                       return( private$.predictShapeAux(data, fdays, today, predict_from, horizon, local,
+                               best_window, simtype, TRUE) )
                }
        ),
        private = list(
                # Precondition: "today" is full (no NAs)
-               .predictShapeAux = function(data, fdays, today, horizon, local, window, simtype,
-                       final_call)
+               .predictShapeAux = function(data, fdays, today, predict_from, horizon, local, window,
+                       simtype, final_call)
                {
                        fdays_cut = fdays[ fdays < today ]
                        if (length(fdays_cut) <= 1)
@@ -135,7 +139,7 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                                private$.params$indices <- fdays
                                                private$.params$window <- 1
                                        }
-                                       return ( data$getSerie(fdays[1])[1:horizon] )
+                                       return ( data$getSerie(fdays[1]+1)[predict_from:horizon] )
                                }
                        }
                        else
@@ -147,10 +151,10 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                window_endo = ifelse(simtype=="mix", window[1], window)
 
                                # Distances from last observed day to days in the past
-                               serieToday = data$getSerie(today)
+                               lastSerie = c( data$getSerie(today-1), data$getSerie(today)[1:(predict_from-1)] )
                                distances2 = sapply(fdays, function(i) {
-                                       delta = serieToday - data$getSerie(i)
-                                       mean(delta^2)
+                                       delta = lastSerie - c(data$getSerie(i),data$getSerie(i+1)[1:(predict_from-1)])
+                                       sqrt(mean(delta^2))
                                })
 
                                simils_endo <- .computeSimils(distances2, window_endo)
@@ -161,12 +165,12 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                # Compute exogen similarities using given window
                                window_exo = ifelse(simtype=="mix", window[2], window)
 
-                               M = matrix( nrow=1+length(fdays), ncol=1+length(data$getExo(today)) )
-                               M[1,] = c( data$getLevel(today), as.double(data$getExo(today)) )
+                               M = matrix( ncol=1+length(fdays), nrow=1+length(data$getExo(1)) )
+                               M[,1] = c( data$getLevelHat(today), as.double(data$getExoHat(today)) )
                                for (i in seq_along(fdays))
-                                       M[i+1,] = c( data$getLevel(fdays[i]), as.double(data$getExo(fdays[i])) )
+                                       M[,i+1] = c( data$getLevel(fdays[i]), as.double(data$getExo(fdays[i])) )
 
-                               sigma = cov(M) #NOTE: robust covariance is way too slow
+                               sigma = cov(t(M)) #NOTE: robust covariance is way too slow
                                # TODO: 10 == magic number; more robust way == det, or always ginv()
                                sigma_inv =
                                        if (length(fdays) > 10)
@@ -176,7 +180,7 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
 
                                # Distances from last observed day to days in the past
                                distances2 = sapply(seq_along(fdays), function(i) {
-                                       delta = M[1,] - M[i+1,]
+                                       delta = M[,1] - M[,i+1]
                                        delta %*% sigma_inv %*% delta
                                })
 
@@ -194,9 +198,12 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                                        rep(1, length(fdays))
                        similarities = similarities / sum(similarities)
 
-                       prediction = rep(0, horizon)
+                       prediction = rep(0, horizon-predict_from+1)
                        for (i in seq_along(fdays))
-                               prediction = prediction + similarities[i] * data$getSerie(fdays[i]+1)[1:horizon]
+                       {
+                               prediction = prediction +
+                                       similarities[i] * data$getSerie(fdays[i]+1)[predict_from:horizon]
+                       }
 
                        if (final_call)
                        {
@@ -230,10 +237,13 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
 #
 .getConstrainedNeighbs = function(today, data, fdays, min_neighbs=10, max_neighbs=12)
 {
-       levelToday = data$getLevel(today)
-       distances = sapply(fdays, function(i) abs(data$getLevel(i)-levelToday))
-       #TODO: 2, +3 : magic numbers
-       dist_thresh = 2
+       levelToday = data$getLevelHat(today)
+       levelYersteday = data$getLevel(today-1)
+       distances = sapply(fdays, function(i) {
+               sqrt((data$getLevel(i)-levelYersteday)^2 + (data$getLevel(i+1)-levelToday)^2)
+       })
+       #TODO: 1, +1, +3 : magic numbers
+       dist_thresh = 1
        min_neighbs = min(min_neighbs,length(fdays))
        repeat
        {
@@ -241,15 +251,14 @@ NeighborsForecaster = R6::R6Class("NeighborsForecaster",
                nb_neighbs = sum(same_pollution)
                if (nb_neighbs >= min_neighbs) #will eventually happen
                        break
-               dist_thresh = dist_thresh + 3
+               dist_thresh = dist_thresh + ifelse(dist_thresh>1,3,1)
        }
        fdays = fdays[same_pollution]
        max_neighbs = 12
        if (nb_neighbs > max_neighbs)
        {
                # Keep only max_neighbs closest neighbors
-               fdays = fdays[
-                       sort(distances[same_pollution],index.return=TRUE)$ix[1:max_neighbs] ]
+               fdays = fdays[ order(distances[same_pollution])[1:max_neighbs] ]
        }
        fdays
 }
index dde8612..7035231 100644 (file)
@@ -18,23 +18,21 @@ PersistenceForecaster = R6::R6Class("PersistenceForecaster",
        inherit = Forecaster,
 
        public = list(
-               predictShape = function(data, today, memory, horizon, ...)
+               predictShape = function(data, today, memory, predict_from, horizon, ...)
                {
                        # Return centered last (similar) day curve, avoiding NAs until memory is run
                        first_day = max(1, today-memory)
                        same_day = ifelse(hasArg("same_day"), list(...)$same_day, TRUE)
-                       # If 'same_day', get the last known future of similar day: -7 + 1 == -6
-                       index = today - ifelse(same_day,6,0)
+                       index <- today
                        repeat
                        {
-                               {
-                                       last_serie = data$getCenteredSerie(index)[1:horizon]
-                                       index = index - ifelse(same_day,7,1)
-                               };
-                               if (!any(is.na(last_serie)))
-                                       return (last_serie);
+                               # If 'same_day', get the last known future of similar day
+                               index = index - ifelse(same_day,7,1)
                                if (index < first_day)
                                        return (NA)
+                               last_serie = data$getCenteredSerie(index)[predict_from:horizon]
+                               if (!any(is.na(last_serie)))
+                                       return (last_serie)
                        }
                }
        )
index 56bb4a5..4e1ae11 100644 (file)
@@ -13,7 +13,7 @@ ZeroForecaster = R6::R6Class("ZeroForecaster",
        inherit = Forecaster,
 
        public = list(
-               predictShape = function(data, today, memory, horizon, ...)
-                       rep(0, horizon)
+               predictShape = function(data, today, memory, predict_from, horizon, ...)
+                       rep(0, (horizon-predict_from+1))
        )
 )
index 323ebfb..a983046 100644 (file)
@@ -3,11 +3,9 @@
 #' Forecast encapsulation as a list (days where prediction occur) of lists (components).
 #'
 #' The private field .pred is a list where each cell contains the predicted variables for
-#' a period of time of H<=24 hours, from hour P+1 until P+H, where P+1 is taken right
-#' after the end of the period designated by \code{getIndexInData()}. In other terms,
-#' \code{forecast$getForecast(i)} return forecasts for \code{data$getSerie(i+1)}.
-#' Each cell .pred[[i]] is itself a list containing three slots, as described in the
-#' 'field' section.
+#' a period of time of H<=24 hours, from hour P until P+H-1, where P == predict_from.
+#' \code{forecast$getForecast(i)} output forecasts for
+#' \code{data$getSerie(forecast$getIndexInData(i))}.
 #'
 #' @usage # Forecast$new(dates)
 #'
index cefa1ea..5258760 100644 (file)
@@ -52,15 +52,20 @@ Forecaster = R6::R6Class("Forecaster",
                        private$.pjump <- pjump
                        invisible(self)
                },
-               predictSerie = function(data, today, memory, horizon, ...)
+               predictSerie = function(data, today, memory, predict_from, horizon, ...)
                {
                        # Parameters (potentially) computed during shape prediction stage
-                       predicted_shape = self$predictShape(data, today, memory, horizon, ...)
-                       predicted_delta = private$.pjump(data,today,memory,horizon,private$.params,...)
-                       # Predicted shape is aligned it on the end of current day + jump
-                       predicted_shape+tail(data$getSerie(today),1)-predicted_shape[1]+predicted_delta
+                       predicted_shape = self$predictShape(data,today,memory,predict_from,horizon,...)
+                       predicted_delta = private$.pjump(data, today, memory, predict_from, horizon,
+                               private$.params, ...)
+
+                       # Predicted shape is aligned on the end of current day + jump
+                       c( data$getSerie(today)[if (predict_from>=2) 1:(predict_from-1) else c()],
+                               predicted_shape - predicted_shape[1] + predicted_delta +
+                                       ifelse(predict_from>=2,
+                                               data$getSerie(today)[predict_from-1], tail(data$getSerie(today-1),1)) )
                },
-               predictShape = function(data, today, memory, horizon, ...)
+               predictShape = function(data, today, memory, predict_from, horizon, ...)
                        NULL #empty default implementation: to implement in inherited classes
                ,
                getParameters = function()
index 40341d9..58453ea 100644 (file)
@@ -10,7 +10,8 @@
 #'
 #' @aliases J_Neighbors
 #'
-getNeighborsJumpPredict = function(data, today, memory, horizon, params, ...)
+getNeighborsJumpPredict = function(data, today, memory, predict_from, horizon,
+       params, ...)
 {
        first_day = max(1, today-memory)
        filter = (params$indices >= first_day)
@@ -18,7 +19,10 @@ getNeighborsJumpPredict = function(data, today, memory, horizon, params, ...)
        weights = params$weights[filter]
 
        gaps = sapply(indices, function(i) {
-               head( data$getSerie(i+1),1 ) - tail( data$getSerie(i),1 )
+               if (predict_from >= 2)
+                       data$getSerie(i+1)[predict_from] - data$getSerie(i+1)[predict_from-1]
+               else
+                       head(data$getSerie(i+1),1) - tail(data$getSerie(i),1)
        })
        scal_product = weights * gaps
        norm_fact = sum( weights[!is.na(scal_product)] )
index 9e56742..8298a89 100644 (file)
 #'
 #' @aliases J_Persistence
 #'
-getPersistenceJumpPredict = function(data, today, memory, horizon, params, ...)
+getPersistenceJumpPredict = function(data, today, memory, predict_from,
+       horizon, params, ...)
 {
        #return gap between end of similar day curve and first day of tomorrow (in the past)
        first_day = max(1, today-memory)
        same_day = ifelse(hasArg("same_day"), list(...)$same_day, TRUE)
-       index = today - ifelse(same_day,7,1)
+       index <- today
        repeat
        {
-               {
-                       last_serie_end = tail( data$getSerie(index), 1)
-                       last_tomorrow_begin = head( data$getSerie(index+1), 1)
-                       index = index - ifelse(same_day,7,1)
-               };
-               if (!is.na(last_serie_end) && !is.na(last_tomorrow_begin))
-                       return (last_tomorrow_begin - last_serie_end);
+               # If 'same_day', get the last known future of similar day
+               index = index - ifelse(same_day,7,1)
                if (index < first_day)
                        return (NA)
+               gap <-
+                       if (predict_from >= 2)
+                               data$getSerie(index)[predict_from] - data$getSerie(index)[predict_from-1]
+                       else
+                               head(data$getSerie(index),1) - tail(data$getSerie(index-1),1)
+               if (!is.na(gap))
+                       return (gap)
        }
 }
index 3aa028f..0b1771f 100644 (file)
@@ -13,7 +13,7 @@
 #'   step, averaged on the L forecasting days.
 #'
 #' @export
-computeError = function(data, pred, horizon=data$getStdHorizon())
+computeError = function(data, pred, predict_from, horizon=length(data$getSerie(1)))
 {
        L = pred$getSize()
        mape_day = rep(0, horizon)
@@ -25,8 +25,8 @@ computeError = function(data, pred, horizon=data$getStdHorizon())
        for (i in seq_len(L))
        {
                index = pred$getIndexInData(i)
-               serie = data$getSerie(index+1)[1:horizon]
-               forecast = pred$getForecast(i)[1:horizon]
+               serie = data$getSerie(index)[predict_from:horizon]
+               forecast = pred$getForecast(i)[predict_from:horizon]
                if (!any(is.na(serie)) && !any(is.na(forecast)))
                {
                        nb_no_NA_data = nb_no_NA_data + 1
index a4a539a..e967cc7 100644 (file)
 #'   #do_something_with_pred
 #' }}
 #' @export
-computeForecast = function(data, indices, forecaster, pjump,
-       memory=Inf, horizon=data$getStdHorizon(), ncores=3, ...)
+computeForecast = function(data, indices, forecaster, pjump, predict_from,
+       memory=Inf, horizon=length(data$getSerie(1)), ncores=3, ...)
 {
        # (basic) Arguments sanity checks
+       predict_from = as.integer(predict_from)[1]
+       if (! predict_from %in% 1:length(data$getSerie(1)))
+               stop("predict_from in [1,24] (hours)")
        horizon = as.integer(horizon)[1]
-       if (horizon<=0 || horizon>length(data$getCenteredSerie(1)))
-               stop("Horizon too short or too long")
+       if (horizon<=predict_from || horizon>length(data$getSerie(1)))
+               stop("Horizon in [predict_from+1,24] (hours)")
        integer_indices = sapply(indices, function(i) dateIndexToInteger(i,data))
        if (any(integer_indices<=0 | integer_indices>data$getSize()))
                stop("Indices out of range")
@@ -73,7 +76,7 @@ computeForecast = function(data, indices, forecaster, pjump,
                p <- parallel::mclapply(seq_along(integer_indices), function(i) {
                        list(
                                "forecast" = forecaster$predictSerie(
-                                       data, integer_indices[i], memory, horizon, ...),
+                                       data, integer_indices[i], memory, predict_from, horizon, ...),
                                "params"= forecaster$getParameters(),
                                "index" = integer_indices[i] )
                        }, mc.cores=ncores)
@@ -83,7 +86,7 @@ computeForecast = function(data, indices, forecaster, pjump,
                p <- lapply(seq_along(integer_indices), function(i) {
                        list(
                                "forecast" = forecaster$predictSerie(
-                                       data, integer_indices[i], memory, horizon, ...),
+                                       data, integer_indices[i], memory, predict_from, horizon, ...),
                                "params"= forecaster$getParameters(),
                                "index" = integer_indices[i] )
                        })
index a6401f9..f1f8861 100644 (file)
 #' @param exo_data Exogenous variables, as a data frame or a CSV file; first column is
 #'   dates, next block are measurements for the day, and final block are exogenous
 #'   forecasts (for the same day).
-#' @param input_tz Timezone in the input files ("GMT" or e.g. "Europe/Paris")
 #' @param date_format How date/time are stored (e.g. year/month/day hour:minutes;
 #'   see ?strptime)
-#' @param working_tz Timezone to work with ("GMT" or e.g. "Europe/Paris")
-#' @param predict_at When does the prediction take place? Integer, in hours. Default: 0
 #' @param limit Number of days to extract (default: Inf, for "all")
 #'
 #' @return An object of class Data
 #' exo_data = read.csv(system.file("extdata","meteo_extra_noNAs.csv",package="talweg"))
 #' data = getData(ts_data, exo_data, limit=120)
 #' @export
-getData = function(ts_data, exo_data, input_tz="GMT", date_format="%d/%m/%Y %H:%M",
-       working_tz="GMT", predict_at=0, limit=Inf)
+getData = function(ts_data, exo_data, date_format="%d/%m/%Y %H:%M", limit=Inf)
 {
        # Sanity checks (not full, but sufficient at this stage)
-       if (!is.character(input_tz) || !is.character(working_tz))
-               stop("Bad timezone (see ?timezone)")
-       input_tz = input_tz[1]
-       working_tz = working_tz[1]
        if ( (!is.data.frame(ts_data) && !is.character(ts_data)) ||
                        (!is.data.frame(exo_data) && !is.character(exo_data)) )
                stop("Bad time-series / exogenous input (data frame or CSV file)")
@@ -39,22 +31,20 @@ getData = function(ts_data, exo_data, input_tz="GMT", date_format="%d/%m/%Y %H:%
                ts_data = ts_data[1]
        if (is.character(exo_data))
                exo_data = exo_data[1]
-       predict_at = as.integer(predict_at)[1]
-       if (predict_at<0 || predict_at>23)
-               stop("Bad predict_at (0-23)")
        if (!is.character(date_format))
                stop("Bad date_format (character)")
        date_format = date_format[1]
+       if (!is.numeric(limit) || limit < 0)
+               stop("limit: positive integer")
 
        ts_df =
                if (is.character(ts_data))
                        read.csv(ts_data)
                else
                        ts_data
-       # Convert to the desired timezone (usually "GMT" or "Europe/Paris")
-       formatted_dates_POSIXlt = strptime(as.character(ts_df[,1]), date_format, tz=input_tz)
-       ts_df[,1] = format(
-               as.POSIXct(formatted_dates_POSIXlt, tz=input_tz), tz=working_tz, usetz=TRUE)
+       # Convert to GMT (pretend it's GMT; no impact)
+       dates_POSIXlt = strptime(as.character(ts_df[,1]), date_format, tz="GMT")
+       ts_df[,1] = format(as.POSIXct(dates_POSIXlt, tz="GMT"), tz="GMT", usetz=TRUE)
 
        exo_df =
                if (is.character(exo_data))
@@ -80,29 +70,18 @@ getData = function(ts_data, exo_data, input_tz="GMT", date_format="%d/%m/%Y %H:%
                                line = line + 1
                        };
                        if (line >= nb_lines + 1
-                               || as.POSIXlt(ts_df[line-1,1],tz=working_tz)$hour == predict_at)
+                               || as.POSIXlt(ts_df[line-1,1],tz="GMT")$hour == 0)
                        {
                                break
                        }
                }
 
-               exo = as.data.frame( exo_df[i,2:(1+nb_exos)] )
-               exo_hat =
-                       if (i < nrow(exo_df))
-                               as.data.frame( exo_df[i+1,(1+nb_exos+1):(1+2*nb_exos)] )
-                       else
-                               NA #exogenous prediction for next day are useless on last day
-               data$append(time, serie, exo, exo_hat)
+               # TODO: 2 modes, "operational" and "testing"; would need PM10 predictions
+               data$append(time=time, value=serie, level_hat=mean(serie,na.rm=TRUE),
+                       exo=exo_df[i,2:(1+nb_exos)], exo_hat=exo_df[i,(1+nb_exos+1):(1+2*nb_exos)])
                if (i >= limit)
                        break
                i = i + 1
        }
-       if (length(data$getCenteredSerie(1)) < length(data$getCenteredSerie(2)))
-               data$removeFirst()
-       if (length(data$getCenteredSerie(data$getSize()))
-               < length(data$getCenteredSerie(data$getSize()-1)))
-       {
-               data$removeLast()
-       }
        data
 }
index fe2fb4e..59a26a7 100644 (file)
@@ -82,9 +82,8 @@ plotError <- function(err, cols=seq_along(err))
 #' @export
 plotPredReal <- function(data, pred, index)
 {
-       horizon = length(pred$getForecast(1))
-       measure = data$getSerie( pred$getIndexInData(index)+1 )[1:horizon]
        prediction = pred$getForecast(index)
+       measure = data$getSerie( pred$getIndexInData(index) )[length(prediction)]
        yrange = range(measure, prediction)
        par(mar=c(4.7,5,1,1), cex.axis=1.5, cex.lab=1.5, lwd=3)
        plot(measure, type="l", ylim=yrange, xlab="Time (hours)", ylab="PM10")
@@ -144,6 +143,7 @@ plotFbox <- function(data, indices=seq_len(data$getSize()))
 #' @param index Index in forecast (integer or date)
 #' @param limit Number of neighbors to consider
 #' @param plot Should the result be plotted?
+#' @param predict_from First prediction instant
 #'
 #' @return A list with
 #' \itemize{
@@ -153,10 +153,9 @@ plotFbox <- function(data, indices=seq_len(data$getSize()))
 #' }
 #'
 #' @export
-computeFilaments <- function(data, pred, index, limit=60, plot=TRUE)
+computeFilaments <- function(data, pred, index, predict_from, limit=60, plot=TRUE)
 {
-       ref_serie = data$getCenteredSerie( pred$getIndexInData(index) )
-       if (any(is.na(ref_serie)))
+       if (is.null(pred$getParams(index)$weights) || is.na(pred$getParams(index)$weights[1]))
                stop("computeFilaments requires a serie without NAs")
 
        # Compute colors for each neighbor (from darkest to lightest)
@@ -170,7 +169,8 @@ computeFilaments <- function(data, pred, index, limit=60, plot=TRUE)
        if (plot)
        {
                # Complete series with (past and present) tomorrows
-               ref_serie = c(ref_serie, data$getCenteredSerie( pred$getIndexInData(index)+1 ))
+               ref_serie = c( data$getCenteredSerie( pred$getIndexInData(index)-1 ),
+                       data$getCenteredSerie( pred$getIndexInData(index) ) )
                centered_series = rbind(
                        data$getCenteredSeries( pred$getParams(index)$indices ),
                        data$getCenteredSeries( pred$getParams(index)$indices+1 ) )
@@ -185,7 +185,7 @@ computeFilaments <- function(data, pred, index, limit=60, plot=TRUE)
                }
                # Also plot ref curve, in red
                plot(ref_serie, ylim=yrange, type="l", col="#FF0000", xlab="", ylab="")
-               abline(v=24, lty=2, col=colors()[56], lwd=1)
+               abline(v=24+predict_from-0.5, lty=2, col=colors()[56], lwd=1)
        }
 
        list(
@@ -202,7 +202,7 @@ computeFilaments <- function(data, pred, index, limit=60, plot=TRUE)
 #' @param fil Output of \code{computeFilaments}
 #'
 #' @export
-plotFilamentsBox = function(data, fil)
+plotFilamentsBox = function(data, fil, predict_from)
 {
        if (!requireNamespace("rainbow", quietly=TRUE))
                stop("Functional boxplot requires the rainbow package")
@@ -220,7 +220,7 @@ plotFilamentsBox = function(data, fil)
        par(new=TRUE)
        plot(c(data$getSerie(fil$index),data$getSerie(fil$index+1)), type="l", lwd=2, lty=2,
                ylim=c(usr[3] + yr, usr[4] - yr), xlab="", ylab="")
-       abline(v=24, lty=2, col=colors()[56])
+       abline(v=24+predict_from-0.5, lty=2, col=colors()[56])
 }
 
 #' Plot relative conditional variability / absolute variability
@@ -232,7 +232,7 @@ plotFilamentsBox = function(data, fil)
 #' @inheritParams plotFilamentsBox
 #'
 #' @export
-plotRelVar = function(data, fil)
+plotRelVar = function(data, fil, predict_from)
 {
        ref_var = c( apply(data$getSeries(fil$neighb_indices),1,sd),
                apply(data$getSeries(fil$neighb_indices+1),1,sd) )
@@ -247,5 +247,5 @@ plotRelVar = function(data, fil)
                xlab="Time (hours)", ylab="Standard deviation")
        par(new=TRUE)
        plot(global_var, type="l", col=2, lwd=3, ylim=yrange, xlab="", ylab="")
-       abline(v=24, lty=2, col=colors()[56])
+       abline(v=24+predict_from-0.5, lty=2, col=colors()[56])
 }
index b0d0ae0..96ec601 100644 (file)
@@ -127,6 +127,6 @@ getSimilarDaysIndices = function(index, data, limit, same_season, days_in=NULL)
 .getNoNA2 = function(data, first, last)
 {
        (first:last)[ sapply(first:last, function(i)
-               !any( is.na(data$getCenteredSerie(i)) | is.na(data$getCenteredSerie(i+1)) )
+               !any( is.na(data$getSerie(i)) | is.na(data$getSerie(i+1)) )
        ) ]
 }
index 491cf9c..af98c0b 100644 (file)
@@ -25,7 +25,7 @@ getDataTest = function(n)
                time = as.POSIXct((i-1)*60*60*24+15*60*(1:96), origin="2007-01-01", tz="GMT")
                exo = runif(4)
                exo_hat = runif(4)
-               data$append(time, serie, exo, exo_hat)
+               data$append(time=time, value=serie, exo=exo, exo_hat=exo_hat)
        }
        data
 }
index 99e5fa5..b3d12fb 100644 (file)
@@ -2,10 +2,8 @@ context("Date <--> integer conversions")
 
 ts_data = system.file("testdata","ts_test.csv",package="talweg")
 exo_data = system.file("testdata","exo_test.csv",package="talweg")
-data0 <<- getData(ts_data, exo_data, input_tz="GMT", date_format="%Y-%m-%d %H:%M",
-       working_tz="GMT", predict_at=0, limit=Inf)
-data7 <<- getData(ts_data, exo_data, input_tz="GMT", date_format="%Y-%m-%d %H:%M",
-       working_tz="GMT", predict_at=7, limit=Inf)
+data0 <<- getData(ts_data, exo_data, date_format="%Y-%m-%d %H:%M", limit=Inf)
+data7 <<- getData(ts_data, exo_data, date_format="%Y-%m-%d %H:%M", limit=Inf)
 
 test_that("dateIndexToInteger works as expected",
 {
index 09b6f0a..78e387a 100644 (file)
@@ -2,18 +2,15 @@ context("Check that forecasters behave as expected")
 
 ts_data = system.file("testdata","ts_test.csv",package="talweg")
 exo_data = system.file("testdata","exo_test.csv",package="talweg")
-data00 <<- getData(ts_data, exo_data, input_tz="GMT", date_format="%Y-%m-%d %H:%M",
-       working_tz="GMT", predict_at=0, limit=Inf)
-data13 <<- getData(ts_data, exo_data, input_tz="GMT", date_format="%Y-%m-%d %H:%M",
-       working_tz="GMT", predict_at=13, limit=Inf)
-#Forecast at sunday to saturday (series 7 to 1), for monday to sunday (series 1 to 7)
-indices <<- seq(as.Date("2007-04-01"),as.Date("2007-04-07"),"days")
+data_p <<- getData(ts_data, exo_data, date_format="%Y-%m-%d %H:%M", limit=Inf)
+#Forecasts from monday to sunday (series 1 to 7)
+indices <<- seq(as.Date("2007-04-02"),as.Date("2007-04-08"),"days")
 pred_order = c(7,1:6) #will facilitate tests
 
 test_that("Average method behave as expected",
 {
-       pred00_z = computeForecast(data00, indices, "Average", "Zero", Inf, 24)
-       pred00_p = computeForecast(data00, indices, "Average", "Persistence", Inf, 24)
+       pred00_z = computeForecast(data_p, indices, "Average", "Zero", 1, Inf, 24, ncores=1)
+       pred00_p = computeForecast(data_p, indices, "Average", "Persistence", 1, Inf, 24)
        for (i in 1:7)
        {
                #zero jump: should predict true values minus 1
@@ -22,30 +19,30 @@ test_that("Average method behave as expected",
                expect_equal( pred00_p$getForecast(i), rep(i,24) )
        }
 
-       #NOTE: days become
+       #NOTE: 24h-block become
        #1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 (14h-->0h then 1h-->13h)
        #No jump between days, thus zero and persistence are equivalent (and correct)
-       pred13_z = computeForecast(data13, indices, "Average", "Zero", Inf, 24)
-       pred13_p = computeForecast(data13, indices, "Average", "Persistence", Inf, 24)
+       pred13_z = computeForecast(data_p, indices, "Average", "Zero", 14, Inf, 24)
+       pred13_p = computeForecast(data_p, indices, "Average", "Persistence", 14, Inf, 24)
        for (i in 1:7)
        {
-               expect_equal( pred13_z$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
-               expect_equal( pred13_p$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
+               expect_equal( pred13_z$getForecast(i), rep(i,24) )
+               expect_equal( pred13_p$getForecast(i), rep(i,24) )
        }
 
        #A few extra checks
-       expect_equal( pred00_p$getIndexInData(2), dateIndexToInteger("2007-04-02",data00) )
-       expect_equal( pred00_z$getIndexInData(2), dateIndexToInteger("2007-04-02",data00) )
-       expect_equal( pred13_p$getIndexInData(5), dateIndexToInteger("2007-04-05",data13) )
-       expect_equal( pred13_z$getIndexInData(5), dateIndexToInteger("2007-04-05",data13) )
+       expect_equal( pred00_p$getIndexInData(2), dateIndexToInteger("2007-04-03",data_p) )
+       expect_equal( pred00_z$getIndexInData(2), dateIndexToInteger("2007-04-03",data_p) )
+       expect_equal( pred13_p$getIndexInData(5), dateIndexToInteger("2007-04-06",data_p) )
+       expect_equal( pred13_z$getIndexInData(5), dateIndexToInteger("2007-04-06",data_p) )
 })
 
 test_that("Persistence method behave as expected",
 {
        #Situation A: +Zero; (generally) correct if jump, wrong otherwise
-       pred00_sd = computeForecast(data00, indices, "Persistence", "Zero", Inf, 24,
+       pred00_sd = computeForecast(data_p, indices, "Persistence", "Zero", 1, Inf, 24,
                ncores=1, same_day=TRUE)
-       pred00_dd = computeForecast(data00, indices, "Persistence", "Zero", Inf, 24,
+       pred00_dd = computeForecast(data_p, indices, "Persistence", "Zero", 1, Inf, 24,
                ncores=1, same_day=FALSE)
        for (i in 1:7)
        {
@@ -53,25 +50,20 @@ test_that("Persistence method behave as expected",
                expect_equal(pred00_dd$getForecast(i), rep(pred_order[i],24))
        }
 
-       pred13_sd = computeForecast(data13, indices, "Persistence", "Zero", Inf, 24,
+       pred13_sd = computeForecast(data_p, indices, "Persistence", "Zero", 14, Inf, 24,
                ncores=1, same_day=TRUE)
-       pred13_dd = computeForecast(data13, indices, "Persistence", "Zero", Inf, 24,
+       pred13_dd = computeForecast(data_p, indices, "Persistence", "Zero", 14, Inf, 24,
                ncores=1, same_day=FALSE)
-       for (i in 2:6)
+       for (i in 1:7)
        {
-               expect_equal(pred13_sd$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
-               expect_equal(pred13_dd$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
+               expect_equal(pred13_sd$getForecast(i), rep(i,24) )
+               expect_equal(pred13_dd$getForecast(i), rep(i,24) )
        }
-       #boundaries are special cases: OK if same day, quite wrong otherwise
-       expect_equal(pred13_sd$getForecast(1), c( rep(1,11), rep(2,13) ) )
-       expect_equal(pred13_dd$getForecast(1), c( rep(1,11), rep(-5,13) ) )
-       expect_equal(pred13_sd$getForecast(7), c( rep(7,11), rep(1,13) ) )
-       expect_equal(pred13_dd$getForecast(7), c( rep(7,11), rep(8,13) ) )
 
        #Situation B: +Persistence, (generally) correct
-       pred00_sd = computeForecast(data00, indices, "Persistence", "Persistence", Inf, 24,
+       pred00_sd = computeForecast(data_p, indices, "Persistence", "Persistence", 1, Inf, 24,
                ncores=1, same_day=TRUE)
-       pred00_dd = computeForecast(data00, indices, "Persistence", "Persistence", Inf, 24,
+       pred00_dd = computeForecast(data_p, indices, "Persistence", "Persistence", 1, Inf, 24,
                ncores=1, same_day=FALSE)
        for (i in 3:7)
        {
@@ -84,55 +76,50 @@ test_that("Persistence method behave as expected",
        expect_equal(pred00_sd$getForecast(2), rep(2,24) )
        expect_equal(pred00_dd$getForecast(2), rep(-5,24) )
 
-       pred13_sd = computeForecast(data13, indices, "Persistence", "Persistence", Inf, 24,
+       pred13_sd = computeForecast(data_p, indices, "Persistence", "Persistence", 14, Inf, 24,
                ncores=1, same_day=TRUE)
-       pred13_dd = computeForecast(data13, indices, "Persistence", "Persistence", Inf, 24,
+       pred13_dd = computeForecast(data_p, indices, "Persistence", "Persistence", 14, Inf, 24,
                ncores=1, same_day=FALSE)
-       for (i in 2:6)
+       for (i in 1:7)
        {
-               expect_equal(pred13_sd$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
-               expect_equal(pred13_dd$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
+               expect_equal(pred13_sd$getForecast(i), rep(i,24) )
+               expect_equal(pred13_dd$getForecast(i), rep(i,24) )
        }
-       #boundaries are special cases: OK if same day, quite wrong otherwise
-       expect_equal(pred13_sd$getForecast(1), c( rep(1,11), rep(2,13) ) )
-       expect_equal(pred13_dd$getForecast(1), c( rep(1,11), rep(-5,13) ) )
-       expect_equal(pred13_sd$getForecast(7), c( rep(7,11), rep(1,13) ) )
-       expect_equal(pred13_dd$getForecast(7), c( rep(7,11), rep(8,13) ) )
 
        #A few extra checks
-       expect_equal( pred00_sd$getIndexInData(3), dateIndexToInteger("2007-04-03",data00) )
-       expect_equal( pred00_dd$getIndexInData(6), dateIndexToInteger("2007-04-06",data00) )
-       expect_equal( pred13_sd$getIndexInData(3), dateIndexToInteger("2007-04-03",data13) )
-       expect_equal( pred13_dd$getIndexInData(6), dateIndexToInteger("2007-04-06",data13) )
+       expect_equal( pred00_sd$getIndexInData(3), dateIndexToInteger("2007-04-04",data_p) )
+       expect_equal( pred00_dd$getIndexInData(6), dateIndexToInteger("2007-04-07",data_p) )
+       expect_equal( pred13_sd$getIndexInData(3), dateIndexToInteger("2007-04-04",data_p) )
+       expect_equal( pred13_dd$getIndexInData(6), dateIndexToInteger("2007-04-07",data_p) )
 })
 
 test_that("Neighbors method behave as expected",
 {
        #Situation A: +Zero; correct if jump, wrong otherwise
-       pred00 = computeForecast(data00, indices, "Neighbors", "Zero", Inf, 24,
+       pred00 = computeForecast(data_p, indices, "Neighbors", "Zero", 1, Inf, 24,
                simtype="mix", local=FALSE)
        for (i in 1:7)
                expect_equal(pred00$getForecast(i), rep(pred_order[i],24))
 
-       pred13 = computeForecast(data13, indices, "Persistence", "Zero", Inf, 24,
+       pred13 = computeForecast(data_p, indices, "Persistence", "Zero", 14, Inf, 24,
                simtype="mix", local=FALSE)
        for (i in 1:7)
-               expect_equal(pred13$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
+               expect_equal(pred13$getForecast(i), rep(i,24) )
 
        #Situation B: +Neighbors == too difficult to eval in a unit test
-#      pred00 = computeForecast(data00, indices, "Neighbors", "Neighbors", Inf, 24,
+#      pred00 = computeForecast(data_p, indices, "Neighbors", "Neighbors", 1, Inf, 24,
 #              simtype="endo", local=FALSE)
 #      jumps = ...
 #      for (i in 1:7)
 #              expect_equal(pred00$getForecast(i), rep(pred_order[i]+jumps[i],24))
-#      pred13 = computeForecast(data13, indices, "Neighbors", "Neighbors", Inf, 24,
+#      pred13 = computeForecast(data_p, indices, "Neighbors", "Neighbors", 14, Inf, 24,
 #              simtype="endo", local=FALSE)
 #      for (i in 1:7)
 #              expect_equal(pred13$getForecast(i), c( rep(i,11), rep(i%%7+1,13) ) )
 
        #A few extra checks
-       expect_equal( pred00$getIndexInData(1), dateIndexToInteger("2007-04-01",data00) )
-       expect_equal( pred00$getIndexInData(4), dateIndexToInteger("2007-04-04",data00) )
-       expect_equal( pred13$getIndexInData(1), dateIndexToInteger("2007-04-01",data13) )
-       expect_equal( pred13$getIndexInData(4), dateIndexToInteger("2007-04-04",data13) )
+       expect_equal( pred00$getIndexInData(1), dateIndexToInteger("2007-04-02",data_p) )
+       expect_equal( pred00$getIndexInData(4), dateIndexToInteger("2007-04-05",data_p) )
+       expect_equal( pred13$getIndexInData(1), dateIndexToInteger("2007-04-02",data_p) )
+       expect_equal( pred13$getIndexInData(4), dateIndexToInteger("2007-04-05",data_p) )
 })
index 7e1cafa..6ddd2c5 100644 (file)
@@ -4,15 +4,15 @@ test_that("output is as expected on simulated series",
 {
        data = getDataTest(150)
 
-       # index 143 : serie type 2
-       pred = computeForecast(data, 143, "Neighbors", "Zero",
+       # index 144-1 == 143 : serie type 2
+       pred = computeForecast(data, 144, "Neighbors", "Zero", predict_from=8,
                horizon=length(data$getSerie(1)), simtype="endo", local=FALSE, h_window=1)
-       f = computeFilaments(data, pred, 1, limit=60, plot=FALSE)
+       f = computeFilaments(data, pred, 1, 8, limit=60, plot=FALSE)
 
        # Expected output: 50-3-10 series of type 2, then 23 series of type 3 (closest next)
        expect_identical(length(f$neighb_indices), as.integer(60))
        expect_identical(length(f$colors), as.integer(60))
-       expect_equal(f$index, 143)
+       expect_equal(f$index, 144)
        expect_true(all(I(f$neighb_indices) >= 2))
        for (i in 1:37)
        {
@@ -27,16 +27,16 @@ test_that("output is as expected on simulated series",
        expect_match(f$colors[1], "#1*")
        expect_match(f$colors[38], "#E*")
 
-       # index 142 : serie type 1
-       pred = computeForecast(data, 142, "Neighbors", "Zero",
+       # index 143-1 == 142 : serie type 1
+       pred = computeForecast(data, 143, "Neighbors", "Zero", predict_from=8,
                horizon=length(data$getSerie(1)), simtype="endo", local=FALSE, h_window=1)
-       f = computeFilaments(data, pred, 1, limit=50, plot=FALSE)
+       f = computeFilaments(data, pred, 1, 8, limit=50, plot=FALSE)
 
        # Expected output: 50-10-3 series of type 1, then 13 series of type 3 (closest next)
        # NOTE: -10 because only past days with no-NAs tomorrow => exclude type 1 in [60,90[
        expect_identical(length(f$neighb_indices), as.integer(50))
        expect_identical(length(f$colors), as.integer(50))
-       expect_equal(f$index, 142)
+       expect_equal(f$index, 143)
        expect_true(all(I(f$neighb_indices) != 2))
        for (i in 1:37)
        {
index d62dc36..567bfd6 100644 (file)
@@ -25,18 +25,17 @@ ts_data <- read.csv(system.file("extdata","pm10_mesures_H_loc.csv",
        package="talweg"))
 exo_data <- read.csv(system.file("extdata","meteo_extra_noNAs.csv",
        package="talweg"))
-data <- getData(ts_data, exo_data, input_tz="GMT",
-       date_format="%d/%m/%Y %H:%M", working_tz="GMT",
-       predict_at=7, limit=120)
+data <- getData(ts_data, exo_data,
+       date_format="%d/%m/%Y %H:%M", limit=120)
 # Plus de détails à la section 1 ci-après.
 
 # Prédiction de 10 courbes (jours 102 à 111)
-pred <- computeForecast(data, 101:110, "Persistence", "Zero", memory=50,
-       horizon=12, ncores=1)
+pred <- computeForecast(data, 101:110, "Persistence", "Zero",
+       predict_from=8, memory=50, horizon=24, ncores=1)
 # Plus de détails à la section 2 ci-après.
 
 # Calcul des erreurs (sur un horizon arbitraire <= horizon de prédiction)
-err <- computeError(data, pred, horizon=6)
+err <- computeError(data, pred, predict_from=8, horizon=20)
 # Plus de détails à la section 3 ci-après.
 
 # Puis voir ?plotError et les autres plot dans le paragraphe 'seealso'
@@ -51,14 +50,9 @@ première colonne contient les heures, la seconde les valeurs.
 première colonne contient les jours, les $m$ suivantes les variables mesurées pour ce
 jour, et les $m$ dernières les variables prédites pour ce même jour. Dans notre cas $m=4$
 : pression, température, gradient de température, vitesse du vent.
- 3. **input_tz** : zone horaire pour ts_data (défaut : "GMT").
- 4. **date_format** : format des heures dans ts_data (défaut : "%d/%m/%Y %H:%M", format
-du fichier transmis par Michel).
- 5. **working_tz** : zone horaire dans laquelle on souhaite travailler avec les données
-(défaut : "GMT").
- 6. **predict_at** : heure à laquelle s'effectue la prévision $-$ et donc dernière heure
-d'un bloc de 24h, relativement à working_tz. data`$`getSerie(3) renvoit ainsi les 24
-valeurs de 8h à 7h pour le $3^{eme}$ bloc de 24h présent dans le jeu de données.
+ 3. **date_format** : format des heures dans ts_data (défaut : "%d/%m/%Y %H:%M", format
+du fichier transmis par Michel Bobbia).
+ 4. **limit** : nombre de séries à récupérer.
 -----r
 print(data)
 #?Data
@@ -76,10 +70,11 @@ blocs de 24h) ; peut être donnée sous forme d'un vecteur de dates ou d'entiers
 ?computeForecast
  5. **memory** : le nombre de jours à prendre en compte dans le passé pour chaque
 prévision (par défaut : Inf, c'est-à-dire tout l'historique pris en compte).
- 6. **horizon** : le nombre d'heures à prédire ; par défaut "data`$`getStdHorizon()",
-c'est-à-dire le nombre d'heures restantes à partir de l'instant de prévision + 1 jusqu'à
-minuit (17 pour predict_at=7 par exemple).
- 7. **ncores** : le nombre de processus parallèles (utiliser 1 pour une exécution
+ 6. **predict_from** : première heure de prévision. Les séries prévues démarrent
+cependant toutes à 1h du matin (en reprenant les premières valeurs connues).
+ 7. **horizon** : dernière heure de prévision ; maximum 24 == minuit (valeur par défaut).
+pred`$`getForecast(i) retourne une journée complète de 01:00 à 00:00 si horizon=24.
+ 8. **ncores** : le nombre de processus parallèles (utiliser 1 pour une exécution
 séquentielle)
 -----r
 print(pred)
@@ -91,9 +86,10 @@ Les arguments de cette fonction sont, dans l'ordre :
 
  1. **data** : le jeu de données renvoyé par getData()
  2. **pred** : les prédictions renvoyées par computeForecast()
- 3. **horizon** : le nombre d'heures à considérer pour le calcul de l'erreur ; doit être
-inférieur ou égal à l'horizon utilisé pour la prédiction (même valeur par défaut :
-"data`$`getStdHorizon()")
+ 3. **predict_from** : première heure de prévision ; peut être différente de l'analogue
+dans l'appel à *computeForecast()*.
+ 4. **horizon** : dernière heure de prévision à considérer pour le calcul de l'erreur ;
+inférieure ou égale à la valeur de l'argument analogue dans *computeForecast()*
 -----r
 summary(err)
 summary(err$abs)