Skip to content
Snippets Groups Projects
Select Git revision
  • 8647ebf0070fc7c33b6eea0cf7d49d6d01386e2b
  • master default protected
2 results

__init__.cpython-38.pyc

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    rls_update.R 5.78 KiB
    #library(devtools)
    #document()
    #load_all(as.package("../../onlineforecast"))
    #?rls_update
    
    #' Calculates the RLS update of the model coefficients with the provived data.
    #'
    #' See vignette ??ref(recursive updating, not yet finished) on how to use the function. 
    #' 
    #' @title Updates the model fits
    #' @param model A model object
    #' @param datatr a data.list with transformed data (from model$transform_data(D))
    #' @param y A vector of the model output for the corresponding time steps in \code{datatr}
    #' @param runcpp Optional, default = TRUE. If TRUE, a c++ implementation of the update is run, otherwise a slower R implementation is used.
    #' @return
    #'
    #' Returns a named list for each horizon (\code{model$kseq}) containing the variables needed for the RLS fit (for each horizon, which is saved in model$Lfits):
    #'
    #' It will update variables in the forecast model object.
    #'
    #' @seealso
    #' See \code{\link{rls_predict}}.
    #' 
    #' @examples
    #'
    #' # See rls_predict examples
    #'
    #' @export
    
    rls_update <- function(model, datatr = NA, y = NA, runcpp=TRUE) {
        # Take the inputs data and bind with the kept inputs data in the fit
        #
        # The data must be kept for later updating, done below
        # The last part of the input data is needed for next update
    
        # Find the number of parameters for the regression
        np <- length(datatr)
    
        # Keep only the last kmax rows for next time
        kmax <- max(as.integer(gsub("k", "", nams(datatr[[1]]))))
    
        # Check if data was kept
        kept_input_data <- !is.na(model$datatr[1])
        #
        if (kept_input_data) {
            # Find the start index for iterating later (the index to start updating from)
            # How many points are kept plus one
            istart <- nrow(model$datatr[[1]]) + 1
            # Bind together new and kept data
            for (i in 1:length(datatr)) {
                # Bind them
                datatr[[i]] <- rbind(model$datatr[[i]], datatr[[i]])
                # Keep only the last kmax rows for next time
                # Done below: model$datatr[[i]] <- datatr[[i]][(n+1):(kmax+n), ]
            }
            # Also for y to sync with X
            y <- c(rep(NA,istart-1), y)
        } else {
            # Set later when nothing is kept (it must be set to k+1)
            istart <- NA
        }
    
        # The number of points
        n <- length(y)
    
        # Parameters for rls
        lambda <- model$regprm$lambda
    
        if(runcpp){
            L <- lapply(model$Lfits, function(fit) {
    
                # Take the needed values from the fit
                k <- fit$k
                theta <- fit$theta
                # The non cpp keeps R, see below
                if(is.null(fit$P)){
                    P <- solve(fit$R)
                }else{ P <- fit$P }
    
                # Form the regressor matrix, don't lag it
                X <- as.matrix(as.data.frame(subset(datatr, kseq=k)))
    
                # When nothing was kept
                if(!kept_input_data){ istart <- k + 1 }
                val <- rls_update_cpp(y, X, theta, P, lambda, k, n, np, istart, kmax)
                # Give names to the matrices (maybe faster if done in cpp function, see in the end)
                colnames(val$fit$P) <- names(datatr)
                colnames(val$result$Theta) <- names(datatr)
                # Give the result
                return(val)
            })
        }else{
            # Fit the model for each k
            L <- lapply(model$Lfits, function(fit) {
                # Take the needed values from the fit
                k <- fit$k
                theta <- fit$theta
                # The cpp keeps P
                if (is.null(fit$R)) {
                    R <- solve(fit$P)
                } else {
                    R <- fit$R
                }
    
                # Form the regressor matrix, don't lag it
                X <- as.data.frame(subset(datatr, kseq=k))
    
                # Prepare for keeping for the parameter estimates
                Theta <- matrix(as.numeric(NA), nrow = n, ncol = np)
    
                # Make vector for predictions k steps ahead
                yhat <- rep(NA,length(y))
                # If input data was kept (i.e. it is not a fresh update), NAs was added above in X and y, so insert the kept yhat
                if(kept_input_data){ yhat[1:length(fit$yhat)] <- fit$yhat}
    
                # When nothing was kept
                if(!kept_input_data){ istart <- k + 1 }
    
                # Iterate through
                for (i in istart:n) {
                    # Take the forecast k steps back to match it with y[i]
                    x <- t(as.matrix(X[i-k, ]))
    
                    if(!any(is.na(x)) & !is.na(y[i])){
                        # Update
                        R <- lambda * R + x %*% t(x)
                        theta <- theta + solve(R, x) %*% (y[i] - t(x) %*% theta)
                        Theta[i, ] <- t(theta)
                    }
    
                    # Make a prediction
                    yhat[i] <- as.matrix(X[i, ]) %*% theta
                }
                #
                # Give names to the matrices
                colnames(R) <- names(datatr)
                colnames(Theta) <- names(datatr)
                # Return the fit and result
                return(list(fit=list(k=k, theta=theta, R=R, yhat=yhat[(n-kmax+1):n]),
                            result=list(yhat=yhat, Theta=Theta)))
            })
        }
        #
        # Keep the last part of the transformed data for later
        model$datatr <- subset(datatr, (n-kmax+1):n)
        # Store the values of y if the model has AR term
        if(!is.na(model$maxlagAR)){
            # Was data kept?
            if(kept_input_data){
                # Yes, so put together with the kept
                tmpy <- c(model$yAR, y[istart:n])
            }else{
                # No, then just take from y
                tmpy <- y
            }
            # In case too few new values, then fill with NAs
            if((model$maxlagAR+1) > length(tmpy)){ tmpy <- c(rep(NA,(model$maxlagAR+1)-length(tmpy)), tmpy) }
            # Keep the needed
            model$yAR <- tmpy[(length(tmpy)-model$maxlagAR):length(tmpy)]
        }
        #
        # Keep the fit
        model$Lfits <- getse(L, "fit")
        # Return Theta in a list for each k
        invisible(getse(L, "result"))
    }