qmodel <- R6::R6Class("qmodel", public = list( ####### Store Data and information for algorithm ##### info = list(), ####### Store Coefficients Data ####### beta = list(), ####### Fixed Parameters ###### ## Weighted W = NA, n_in_bin = NA, ## Number of predictiors K = NA, ## Quantiles tau = NA, ## Cold start size N1 = NA, debug = NA, ####### Quantile Information ######## ## Index of the columns of the X matrix of Xny IX = NA, ## Index of the column of y Iy = NA, ## The design matrix X = list(), ####### debug Information ######## listIH = list(), ####### Forecast Information ######## inputs = list(), kseq = NA, output = NA, prm = NA, regprmexpr = NA, regprm = NA, ## Offline parameters prmbounds = as.matrix(data.frame(lower=NA, init =NA, upper=NA)), datatr = NA, qrFIT = NA, maxlagAR = NA, yAR = NA, Ypred = NA, ## Initialise the model with the size of the cold start. ## We need some starting point for the iteration of the quantile fit, using simplex method. initialize = function(N1 = NULL, debug = FALSE){ if(is.null(N1)) stop("The number of data points for the cold start needs to be defined") self$N1 <- N1 self$debug <- debug }, ### Should be the same to forecastmodel.R.. maybe have an inheritance from that instead of rewrite. #---------------------------------------------------------------- # Get the transformation parameters get_prmbounds = function(nm){ if(nm == "init"){ if(is.null(dim(self$prmbounds))){ val <- self$prmbounds[nm] }else{ val <- self$prmbounds[ ,nm] if(is.null(nams(val))){ nams(val) <- rownames(self$prmbounds) } } } if(nm == "lower"){ if("lower" %in% nams(self$prmbounds)){ val <- self$prmbounds[,"lower"] if(is.null(nams(val))){ nams(val) <- rownames(self$prmbounds) } }else{ val <- -Inf } } if(nm == "upper"){ if("upper" %in% nams(self$prmbounds)){ val <- self$prmbounds[,"upper"] if(is.null(nams(val))){ nams(val) <- rownames(self$prmbounds) } }else{ val <- Inf } } names(val) <- row.names(self$prmbounds) return(val) }, #---------------------------------------------------------------- #---------------------------------------------------------------- # Add the transformation parameters and bounds for optimization add_prmbounds = function(...) { dots <- list(...) for (i in 1:length(dots)) { nm <- names(dots)[i] if (nm %in% rownames(self$prmbounds)) { self$prmbounds[nm, ] <- dots[[i]] } else { if(nrow(self$prmbounds) == 1 & is.na(self$prmbounds[1,2])){ self$prmbounds[1, ] <- dots[[i]] }else{ self$prmbounds <- rbind(self$prmbounds, dots[[i]]) } rownames(self$prmbounds)[nrow(self$prmbounds)] <- nm } } }, #---------------------------------------------------------------- #---------------------------------------------------------------- # Resets the input states reset_state = function(){ # Reset the inputs state lapply(self$inputs, function(input){ input$state_reset() }) # Reset stored data self$datatr <- NA #self$yAR <- NA }, #---------------------------------------------------------------- #---------------------------------------------------------------- # Insert the transformation parameters prm in the input expressions and regression expressions, and keep them (simply string manipulation) insert_prm = function(prm){ # If just NA or NULL given, then don't do anything if(is.null(prm) | (is.na(prm)[1] & length(prm) == 1)){ return(NULL) } # MUST INCLUDE SOME checks here and print useful messages if something is not right if(any(is.na(prm))){ stop(pst("None of the parameters (in prm) must be NA: prm=",prm)) } # Keep the prm self$prm <- prm # Find if any opt parameters, first the one with "__" hence for the inputs pinputs <- prm[grep("__",nams(prm))] # If none found for inputs, then the rest must be for regression if (length(pinputs) == 0 & length(prm) > 0) { preg <- prm } else { preg <- prm[-grep("__",nams(prm))] } # ################ # For the inputs, insert from prm if any found if (length(pinputs)) { pnms <- unlist(getse(strsplit(nams(pinputs),"__"), 1)) pprm <- unlist(getse(strsplit(nams(pinputs),"__"), 2)) # for(i in 1:length(self$inputs)){ for(ii in 1:length(pnms)){ # Find if the input i have prefix match with the opt. parameter ii if(pnms[ii]==nams(self$inputs)[i]){ # if the opt. parameter is in the expr, then replace self$inputs[[i]]$expr <- private$replace_value(name = pprm[ii], value = pinputs[ii], expr = self$inputs[[i]]$expr) } } } } # ################ # For the fit parameters, insert from prm if any found if (length(preg) & any(!is.na(self$regprmexpr))) { nams(preg) for(i in 1:length(preg)){ # if the opt. parameter is in the expr, then replace self$regprmexpr <- private$replace_value(name = nams(preg)[i], value = preg[i], expr = self$regprmexpr) } } self$regprm <- eval(parse(text = self$regprmexpr)) }, #---------------------------------------------------------------- #---------------------------------------------------------------- # Add inputs to the model add_inputs = function(...){ dots <- list(...) for (i in 1:length(dots)){ self$inputs[[ nams(dots)[i] ]] <- onlineforecast:::input_class$new(dots[[i]], model=self) } }, #---------------------------------------------------------------- # Add the expression (as character) which generates the regression parameters add_regprm = function(regprmexpr){ self$regprmexpr <- regprmexpr self$regprm <- eval(parse(text = self$regprmexpr)) }, #---------------------------------------------------------------- #---------------------------------------------------------------- # Function for transforming the input data to the regression data transform_data = function(data){ # Evaluate for each input the expresssion to generate the model input data L <- lapply(self$inputs, function(input){ # Evaluate the expression (input$expr) L <- input$evaluate(data) # Must return a list if(class(L)[1]=="matrix"){ return(list(as.data.frame(L))) } if(class(L)[1]=="data.frame"){ return(list(L)) } if(class(L)[1]!="list"){ stop(pst("The value returned from evaluating: ",input$expr,", was not a matrix, data.frame or a list of them."))} if(class(L[[1]])[1]=="matrix"){ return(lapply(L, function(mat){ return(as.data.frame(mat)) })) } return(L) }) # Put together in one data.list L <- structure(do.call(c, L), class="data.list") # return(L) } ), # Private functions private = list( #---------------------------------------------------------------- #---------------------------------------------------------------- # Replace the value in "name=value" in expr replace_value = function(name, value, expr){ # First make regex pattern <- gsub("\\.", ".*", name) # Try to find it in the input pos <- regexpr(pattern, expr) # Only replace if prm was found if(pos>0){ pos <- c(pos+attr(pos,"match.length")) # Find the substr to replace with the prm value (tmp <- substr(expr, pos, nchar(expr))) pos2 <- regexpr(",|)", tmp) # Insert the prm value and return expr <- pst(substr(expr,1,pos-1), "=", value, substr(expr,pos+pos2-1,nchar(expr))) # Print? Not used now #if(printout){ message(names(value),"=",value,", ",sep="")} } return(expr) } #---------------------------------------------------------------- ))