From 2478dbfe03ff436cc7a4e9ee741b84810dff89c5 Mon Sep 17 00:00:00 2001 From: Peder <pbac@dtu.dk> Date: Mon, 16 Aug 2021 16:00:19 +0200 Subject: [PATCH] Added NAMESPACE and man, otherwise the install from the git is not working --- .gitignore | 5 - NAMESPACE | 114 ++++++++++++++ man/AR.Rd | 70 +++++++++ man/Dbuilding.Rd | 33 +++++ man/as.data.frame.data.list.Rd | 37 +++++ man/as.data.list.Rd | 57 +++++++ man/aslt.Rd | 62 ++++++++ man/bs.Rd | 91 ++++++++++++ man/cache_name.Rd | 89 +++++++++++ man/cache_save.Rd | 19 +++ man/check.Rd | 23 +++ man/check.data.list.Rd | 51 +++++++ man/complete_cases.Rd | 65 ++++++++ man/ct.Rd | 128 ++++++++++++++++ man/data.list.Rd | 41 ++++++ man/depth.Rd | 20 +++ man/equals-.data.list.Rd | 37 +++++ man/flattenlist.Rd | 21 +++ man/forecastmodel.Rd | 171 +++++++++++++++++++++ man/fs.Rd | 44 ++++++ man/getse.Rd | 71 +++++++++ man/gof.Rd | 11 ++ man/grapes-times-times-grapes.Rd | 57 +++++++ man/in_range.Rd | 61 ++++++++ man/input_class.Rd | 105 +++++++++++++ man/lagdf.Rd | 81 ++++++++++ man/lagdl.Rd | 26 ++++ man/lagvec.Rd | 35 +++++ man/lapply_cbind.Rd | 16 ++ man/lapply_cbind_df.Rd | 16 ++ man/lapply_rbind.Rd | 16 ++ man/lapply_rbind_df.Rd | 16 ++ man/lm_fit.Rd | 91 ++++++++++++ man/lm_optim.Rd | 84 +++++++++++ man/lm_predict.Rd | 60 ++++++++ man/long_format.Rd | 41 ++++++ man/lp.Rd | 45 ++++++ man/lp_vector_cpp.Rd | 13 ++ man/make_input.Rd | 32 ++++ man/make_periodic.Rd | 44 ++++++ man/make_tday.Rd | 41 ++++++ man/nams.Rd | 43 ++++++ man/one.Rd | 31 ++++ man/onlineforecast.Rd | 14 ++ man/pairs.data.list.Rd | 65 ++++++++ man/par_ts.Rd | 94 ++++++++++++ man/pbspline.Rd | 42 ++++++ man/persistence.Rd | 39 +++++ man/plot_ts.Rd | 245 +++++++++++++++++++++++++++++++ man/print.forecastmodel.Rd | 19 +++ man/print_to_message.Rd | 14 ++ man/pst.Rd | 14 ++ man/resample.Rd | 76 ++++++++++ man/residuals.Rd | 66 +++++++++ man/rls_fit.Rd | 136 +++++++++++++++++ man/rls_optim.Rd | 89 +++++++++++ man/rls_predict.Rd | 76 ++++++++++ man/rls_prm.Rd | 52 +++++++ man/rls_summary.Rd | 78 ++++++++++ man/rls_update.Rd | 36 +++++ man/rls_update_cpp.Rd | 30 ++++ man/rmse.Rd | 43 ++++++ man/score.Rd | 59 ++++++++ man/setpar.Rd | 50 +++++++ man/stairs.Rd | 53 +++++++ man/state_getval.Rd | 36 +++++ man/state_setval.Rd | 33 +++++ man/step_optim.Rd | 201 +++++++++++++++++++++++++ man/subset.data.list.Rd | 79 ++++++++++ 69 files changed, 3948 insertions(+), 5 deletions(-) create mode 100644 NAMESPACE create mode 100644 man/AR.Rd create mode 100644 man/Dbuilding.Rd create mode 100644 man/as.data.frame.data.list.Rd create mode 100644 man/as.data.list.Rd create mode 100644 man/aslt.Rd create mode 100644 man/bs.Rd create mode 100644 man/cache_name.Rd create mode 100644 man/cache_save.Rd create mode 100644 man/check.Rd create mode 100644 man/check.data.list.Rd create mode 100644 man/complete_cases.Rd create mode 100644 man/ct.Rd create mode 100644 man/data.list.Rd create mode 100644 man/depth.Rd create mode 100644 man/equals-.data.list.Rd create mode 100644 man/flattenlist.Rd create mode 100644 man/forecastmodel.Rd create mode 100644 man/fs.Rd create mode 100644 man/getse.Rd create mode 100644 man/gof.Rd create mode 100644 man/grapes-times-times-grapes.Rd create mode 100644 man/in_range.Rd create mode 100644 man/input_class.Rd create mode 100644 man/lagdf.Rd create mode 100644 man/lagdl.Rd create mode 100644 man/lagvec.Rd create mode 100644 man/lapply_cbind.Rd create mode 100644 man/lapply_cbind_df.Rd create mode 100644 man/lapply_rbind.Rd create mode 100644 man/lapply_rbind_df.Rd create mode 100644 man/lm_fit.Rd create mode 100644 man/lm_optim.Rd create mode 100644 man/lm_predict.Rd create mode 100644 man/long_format.Rd create mode 100644 man/lp.Rd create mode 100644 man/lp_vector_cpp.Rd create mode 100644 man/make_input.Rd create mode 100644 man/make_periodic.Rd create mode 100644 man/make_tday.Rd create mode 100644 man/nams.Rd create mode 100644 man/one.Rd create mode 100644 man/onlineforecast.Rd create mode 100644 man/pairs.data.list.Rd create mode 100644 man/par_ts.Rd create mode 100644 man/pbspline.Rd create mode 100644 man/persistence.Rd create mode 100644 man/plot_ts.Rd create mode 100644 man/print.forecastmodel.Rd create mode 100644 man/print_to_message.Rd create mode 100644 man/pst.Rd create mode 100644 man/resample.Rd create mode 100644 man/residuals.Rd create mode 100644 man/rls_fit.Rd create mode 100644 man/rls_optim.Rd create mode 100644 man/rls_predict.Rd create mode 100644 man/rls_prm.Rd create mode 100644 man/rls_summary.Rd create mode 100644 man/rls_update.Rd create mode 100644 man/rls_update_cpp.Rd create mode 100644 man/rmse.Rd create mode 100644 man/score.Rd create mode 100644 man/setpar.Rd create mode 100644 man/stairs.Rd create mode 100644 man/state_getval.Rd create mode 100644 man/state_setval.Rd create mode 100644 man/step_optim.Rd create mode 100644 man/subset.data.list.Rd diff --git a/.gitignore b/.gitignore index df6682c..27fe0b9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,19 +3,14 @@ .RData .Ruserdata -NAMESPACE - *.o src/onlineforecast\.so -inst/doc modifications_old_notstaged/ cache/ -man/ - misc-R/*cache* vignettes/*cache* diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..8cdc590 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,114 @@ +# Generated by roxygen2: do not edit by hand + +S3method("==",data.list) +S3method(as.data.frame,data.list) +S3method(as.data.list,data.frame) +S3method(aslt,POSIXct) +S3method(aslt,POSIXlt) +S3method(aslt,character) +S3method(aslt,numeric) +S3method(check,data.list) +S3method(complete_cases,data.frame) +S3method(complete_cases,list) +S3method(ct,POSIXct) +S3method(ct,POSIXlt) +S3method(ct,character) +S3method(ct,numeric) +S3method(lagdf,character) +S3method(lagdf,data.frame) +S3method(lagdf,factor) +S3method(lagdf,logical) +S3method(lagdf,matrix) +S3method(lagdf,numeric) +S3method(pairs,data.list) +S3method(plot_ts,data.frame) +S3method(plot_ts,data.list) +S3method(plot_ts,matrix) +S3method(plot_ts,rls_fit) +S3method(plotly_ts,data.frame) +S3method(plotly_ts,data.list) +S3method(print,forecastmodel) +S3method(resample,data.frame) +S3method(residuals,data.frame) +S3method(residuals,forecastmodel_fit) +S3method(residuals,list) +S3method(residuals,matrix) +S3method(score,data.frame) +S3method(score,list) +S3method(subset,data.list) +S3method(summary,rls_fit) +export("%**%") +export("nams<-") +export(AR) +export(as.data.list) +export(aslt) +export(bspline) +export(cache_name) +export(cache_save) +export(check) +export(complete_cases) +export(ct) +export(data.list) +export(forecastmodel) +export(fs) +export(getse) +export(gof) +export(in_range) +export(lagdf) +export(lagdl) +export(lagvec) +export(lapply_cbind) +export(lapply_cbind_df) +export(lapply_rbind) +export(lapply_rbind_df) +export(lm_fit) +export(lm_optim) +export(lm_predict) +export(long_format) +export(lp) +export(make_input) +export(make_periodic) +export(make_tday) +export(nams) +export(one) +export(par_ts) +export(pbspline) +export(persistence) +export(plot_ts) +export(plotly_ts) +export(pst) +export(resample) +export(rls_fit) +export(rls_optim) +export(rls_predict) +export(rls_prm) +export(rls_summary) +export(rls_update) +export(rmse) +export(score) +export(setpar) +export(stairs) +export(step_optim) +importFrom(Rcpp,sourceCpp) +importFrom(grDevices,colorRampPalette) +importFrom(grDevices,graphics.off) +importFrom(graphics,axis) +importFrom(graphics,axis.POSIXct) +importFrom(graphics,legend) +importFrom(graphics,lines) +importFrom(graphics,mtext) +importFrom(graphics,pairs) +importFrom(graphics,panel.smooth) +importFrom(graphics,par) +importFrom(graphics,plot) +importFrom(graphics,points) +importFrom(graphics,title) +importFrom(parallel,mclapply) +importFrom(stats,aggregate) +importFrom(stats,complete.cases) +importFrom(stats,lm) +importFrom(stats,optim) +importFrom(stats,predict) +importFrom(stats,residuals) +importFrom(stats,sd) +useDynLib(onlineforecast) diff --git a/man/AR.Rd b/man/AR.Rd new file mode 100644 index 0000000..251c3b2 --- /dev/null +++ b/man/AR.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/AR.R +\name{AR} +\alias{AR} +\title{Auto-Regressive (AR) input} +\usage{ +AR(lags) +} +\arguments{ +\item{lags}{integer vector: The lags of the AR to include.} +} +\value{ +A list of matrices, one for each lag in lags, each with columns according to model$kseq. +} +\description{ +Generate auto-regressive (AR) inputs in a model +} +\details{ +The AR function can be used in an onlineforecast model formulation. It +creates the input matrices for including AR inputs in a model during the +transformation stage. It takes the values from the model output in the provided data +does the needed lagging. + +The lags must be given according to the one-step ahead model, e.g.: + +\code{AR(lags=c(0,1))} will give: Y_{t+1|t} = \eqn{\phi_1} y_{t-0} + \eqn{\phi_2} y_{t-1} + \eqn{\epsilon}_{t+1} + +and: + +\code{AR(lags=c(0,3,12))} will give: Y_{t+1|t} = \eqn{\phi}_1 y_{t-0} + \eqn{\phi}_2 y_{t-3} + \eqn{\phi}_3 y_{t-12} + \eqn{\epsilon}_{t+1} + +Note, that + +For k>1 the coefficients will be fitted individually for each horizon, e.g.: + +\code{AR(lags=c(0,1))} will be the multi-step AR: Y_{t+k|t} = \eqn{\phi}_{1,k} y_{t-0} + \eqn{\phi}_{2,k} y_{t-1} + \eqn{\epsilon}_{t+k|t} + +See the details in ??(ref til vignette). +} +\examples{ + +# Setup data and a model for the example +D <- Dbuilding +model <- forecastmodel$new() +model$output = "heatload" +# Use the AR in the transformation stage +model$add_inputs(AR = "AR(c(0,1))") +# Regression parameters +model$add_regprm("rls_prm(lambda=0.9)") +# kseq must be added +model$kseq <- 1:4 +# In the transformation stage the AR input will be generated +# See that it generates two input matrices, simply with the lagged heat load at t for every k +model$transform_data(subset(D, 1:10)) + +# Fit with recursive least squares (no parameters prm in the model) +fit <- rls_fit(c(lambda=0.99), model, D, returnanalysis=TRUE) + +# Plot the result, see "?plot_ts.rls_fit" +plot_ts(fit, xlim=c(ct("2010-12-20"),max(D$t))) +# Plot for a short period with peaks +plot_ts(fit, xlim=c("2011-01-05","2011-01-07")) + +# For online updating, see ??ref{vignette, not yet available}: +# the needed lagged output values are stored in the model for next time new data is available +model$yAR +# The maximum lag needed is also kept +model$maxlagAR + +} diff --git a/man/Dbuilding.Rd b/man/Dbuilding.Rd new file mode 100644 index 0000000..666d466 --- /dev/null +++ b/man/Dbuilding.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{Dbuilding} +\alias{Dbuilding} +\title{Observations and weather forecasts from a single-family building, weather station and Danish Meteorological Institute (DMI)} +\format{ +A data list with 1854 rows and 7 variables: +\describe{ + \item{t}{Time in GMT as POSIXct} + \item{heatload}{The heatload of a single family building in W} + \item{heatloadtotal}{The average heatload of a 16 single family buildings in W} + \item{Taobs}{Observed ambient temperature at the weather station in Celcius} + \item{Iobs}{Observed global radiation at the weather station in W/m^2} + \item{Ta}{Weather forecasts of ambient temperature up to 36 hours ahead from DMI in Celcius} + \item{Ta}{Weather forecasts of global radiation up to 36 hours ahead from DMI in W/m^2} +} +} +\source{ +See \url{https://onlineforecasting.org/examples/datasets.html}. +} +\usage{ +Dbuilding +} +\description{ +Data of the period from 2010-12-15 to 2011-03-01. The weather station was located within a range of 10 km from the building. +} +\details{ +Hourly average values. The time point is set in the end of the hour. + +Set in the format of a data.list used as input to forecast models in the onlineforecast package. +} +\keyword{datasets} diff --git a/man/as.data.frame.data.list.Rd b/man/as.data.frame.data.list.Rd new file mode 100644 index 0000000..5b3e712 --- /dev/null +++ b/man/as.data.frame.data.list.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{as.data.frame.data.list} +\alias{as.data.frame.data.list} +\title{Convert to data.frame} +\usage{ +\method{as.data.frame}{data.list}(x, row.names = NULL, optional = FALSE, ...) +} +\arguments{ +\item{x}{The data.list to be converted.} + +\item{row.names}{Not used.} + +\item{optional}{Not used.} + +\item{...}{Not used.} +} +\value{ +A data.frame +} +\description{ +Converts a data.list to a data.frame. +} +\details{ +The forecasts in the data.list will result in columns named \code{varname.kxx} in the data.frame. +} +\examples{ + +#' # Use the data.list with building heat load +D <- Dbuilding +# Take a subset +D <- subset(D, 1:5, nms=c("t","Taobs","Ta","Iobs","I"), kseq=1:3) + +# Convert to a data.frame, note the names of the forecasts are appended .kxx (i.e. for Ta and I) +as.data.frame(D) + +} diff --git a/man/as.data.list.Rd b/man/as.data.list.Rd new file mode 100644 index 0000000..14c2928 --- /dev/null +++ b/man/as.data.list.Rd @@ -0,0 +1,57 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/as.data.list.R +\name{as.data.list} +\alias{as.data.list} +\alias{as.data.list.data.frame} +\title{Convert to data.list class} +\usage{ +as.data.list(object) + +\method{as.data.list}{data.frame}(object) +} +\arguments{ +\item{object}{The data.frame to be converted.} +} +\value{ +a value of class data.list + +a data.list +} +\description{ +These functions will convert the object into a data.list. + +Convert a data.frame into a data.list +} +\details{ +A data.list is simply a list of vectors and data.frames. For the use in the +onlineforecast package the following format must be kept: + + - t: A vector of time. + + - vectors with same length as t: Holds observations and values synced to time t. + + - data.frames with number of rows as time t: Holds forecasts in each column named by \code{kxx} where \code{xx} is the + horizon, e.g. \code{k0} is synced as observations, and \code{k1} is one-step ahead. + +The convention is that columns with forecasts are postfixed with \code{.kxx} where +\code{xx} is the horizon. See the examples. +} +\examples{ +# Convert a dataframe with time and two observed variables +X <- data.frame(t=1:10, x=1:10, y=1:10) +as.data.list(X) + +# Convert a dataframe with time, forecast and an observed variable +X <- data.frame(t=1:10, x.k1=1:10, x.k2=10:1, yobs=1:10, y.k1=1:10, y.k2=1:10) +as.data.list(X) + +# Can be converted back and forth +X +as.data.frame(as.data.list(X)) + +} +\seealso{ +\code{For specific detailed info see the children, e.g. \link{onlinefocast:::as.data.list.data.frame} } + +as.data.list +} diff --git a/man/aslt.Rd b/man/aslt.Rd new file mode 100644 index 0000000..aa86128 --- /dev/null +++ b/man/aslt.Rd @@ -0,0 +1,62 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aslt.R +\name{aslt} +\alias{aslt} +\alias{aslt.character} +\alias{aslt.POSIXct} +\alias{aslt.POSIXlt} +\alias{aslt.numeric} +\title{Convertion to POSIXlt} +\usage{ +aslt(object, ...) + +\method{aslt}{character}(object, tz = "GMT", ...) + +\method{aslt}{POSIXct}(object, tz = NA, ...) + +\method{aslt}{POSIXlt}(object, tz = NA, ...) + +\method{aslt}{numeric}(object, ...) +} +\arguments{ +\item{object}{The character, POSIXct, POSIClt, or numeric which is converted to POSIXct.} + +\item{...}{Arguments to be passed to methods.} + +\item{tz}{Timezone. If set, then the time zone will be changed of the object.} +} +\value{ +An object of class POSIXlt +} +\description{ +The argument is converted into POSIXlt with tz="GMT". +} +\section{Methods}{ + +#' @examples + +# Create a POSIXlt with tz="GMT" +aslt("2019-01-01") +class(aslt("2019-01-01")) +aslt("2019-01-01 01:00:05") + +# Convert between time zones +x <- aslt("2019-01-01", tz="CET") +aslt(x,tz="GMT") + +# To seconds and back again +aslt(as.numeric(x, units="sec")) + + + - aslt.character: Simply a wrapper for \code{as.POSIXlt} + + + - aslt.POSIXct: Converts to POSIXct. + + + - aslt.POSIXlt: Changes the time zone of the object if tz is given. + + + - aslt.numeric: Converts from UNIX time in seconds to POSIXlt. +} + diff --git a/man/bs.Rd b/man/bs.Rd new file mode 100644 index 0000000..1356ccf --- /dev/null +++ b/man/bs.Rd @@ -0,0 +1,91 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bspline.R +\name{bspline} +\alias{bspline} +\title{Compute base splines of a variable using the R function \code{splines::bs}, use in the transform stage.} +\usage{ +bspline( + X, + Boundary.knots = NA, + intercept = FALSE, + df = NULL, + knots = NULL, + degree = 3, + bknots = NA, + periodic = FALSE +) +} +\arguments{ +\item{X}{data.frame (as part of data.list) with horizons as columns named \code{kxx} (i.e. one for each horizon)} + +\item{Boundary.knots}{The value is NA: then the boundaries are set to the range of each horizons (columns in X). See \code{?splines::bs}} + +\item{intercept}{See \code{?splines::bs}.} + +\item{df}{See \code{?splines::bs}} + +\item{knots}{See \code{?splines::bs}} + +\item{degree}{See \code{?splines::bs}} + +\item{bknots}{Is just a short for Boundary.knots and replace Boundary.knots (if Boundary.knots is not given)} + +\item{periodic}{Default FALSE. If TRUE, then \code{pbs::pbs} is called and periodic splines are generated.} +} +\value{ +List of data frames with the computed base splines, each with columns for the same horizons as in X +} +\description{ +Simply wraps the \code{splines::bs}, such that it can be used in the transformation stage. +} +\details{ +See the help for all arguments with \code{?splines::bs}. NOTE that two arguments have different default values. + +See the example \url{https://onlineforecasting.org/examples/solar-power-forecasting.html} where the function is used in a model. +} +\examples{ + +# How to make a diurnal curve using splines + # Select first 54 hours from the load data + D <- subset(Dbuilding, 1:76, kseq=1:4) + # Make the hour of the day as a forecast input + D$tday <- make_tday(D$t, kseq=1:4) + D$tday + + # Calculate the base splines for each column in tday + L <- bspline(D$tday) + + # Now L holds a data.frame for each base spline + str(L) + # Hence this will result in four inputs for the regression model + + # Plot (note that the splines period starts at tday=0) + plot(D$t, L$bs1$k1, type="s") + for(i in 2:length(L)){ + lines(D$t, L[[i]]$k1, col=i, type="s") + } + + # In a model formulation it will be: + model <- forecastmodel$new() + model$add_inputs(mutday = "bspline(tday)") + # Such that at the transform stage will give the same as above + model$transform_data(D) + +# Periodic splines are useful for modelling a diurnal harmonical functions +L <- bspline(D$tday, bknots=c(0,24), df=4, periodic=TRUE) +# or +L <- pbspline(D$tday, bknots=c(0,24), df=4) +# Note, how it has to have high enough df, else it generates an error + +# Plot +plot(D$t, L$bs1$k1, type="s") +for(i in 2:length(L)){ + lines(D$t, L[[i]]$k1, col=i, type="s") +} + +} +\seealso{ +Other Transform stage functions: +\code{\link{pbspline}()} +} +\concept{Transform stage functions} diff --git a/man/cache_name.Rd b/man/cache_name.Rd new file mode 100644 index 0000000..84e82bb --- /dev/null +++ b/man/cache_name.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cache_name.R +\name{cache_name} +\alias{cache_name} +\title{Generation of a name for a cache file for the value of a function.} +\usage{ +cache_name(..., cachedir = "cache") +} +\arguments{ +\item{...}{The objects from which to calculate cache file name. +If no objects given, then all the objects of the calling function are used for generating the checksum for the file name.} + +\item{cachedir}{Path for saving the cache, i.e. prefixed to the generated name, remember to end with '/' to make a directory.} +} +\value{ +A generated cache file name. +} +\description{ +Caching of the value returned by a function +} +\details{ +Use it in the beginning of a function, which runs a time consuming calculation, like fitting a model using optimization. + +It makes a cache name, which can be used to save a unique cache file (see \code{\link{cache_save}()}). + +The \code{cache_name} function must receive all the objects (in \code{...}) which influence the value of the function. It simply calculates a checksum using the \code{digest} package. + +Further, it finds the name of the calling function and its definition, such that if anything changes in the function definition, then the cache file name changes too. +} +\examples{ +# A function for demonstrating the using caching +fun <- function(x, y){ + # Generate the cache name (no argument given, so both x and y is used) + nm <- cache_name(cachedir=cachedir) + # If the result is cached, then just return it + if(file.exists(nm)){ return(readRDS(nm)) } + # Do the calculation + res <- x^2 + y + 1 + # Wait 1 sec + Sys.sleep(1) + # Save for cache + cache_save(res, nm) + # Return + return(res) +} + +# For this example use a temporary directory +# In real use this should not be temporary! (changes between R sessions with tempdir()) +cachedir <- tempdir() + +# Uncomment to run: +# First time it takes at least 1 sec. +#fun(x=2,y=2) +# Second time it loads the cache and is much faster +#fun(x=2,y=2) +# Try changing the arguments (x,y) and run again + +# See the cache file(s) +#dir(cachedir) +# Delete the cache folder +#unlink(cachedir, recursive=TRUE) + +# Demonstrate how cache_name() is functioning +# Cache using the all objects given in the function calling, i.e. both x and y +fun <- function(x,y){ + x^2 + y + 1 + return(cache_name()) +} +# These are the same (same values) +fun(x=1,y=2) +fun(1,2) +fun(y=2,x=1) +# But this one is different +fun(x=2,y=1) + +# Test: cache using the values specified in the cache_name call +fun2 <- function(x,y){ + x^2 + y + 1 + return(cache_name(x)) +} + +# So now its only the x value that change the name +fun2(1,2) +fun2(1,3) +# But this one is different +fun2(3,3) +# And the function named changed the name + +} diff --git a/man/cache_save.Rd b/man/cache_save.Rd new file mode 100644 index 0000000..23cbcaa --- /dev/null +++ b/man/cache_save.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cache_save.R +\name{cache_save} +\alias{cache_save} +\title{Save a cache file (name generated with \code{code_name()}} +\usage{ +cache_save(object, filename) +} +\arguments{ +\item{object}{The object to cache (i.e. the value of the evaluating function).} + +\item{filename}{The cache file name (i.e. use the one generated by cache_name, see examples).} +} +\description{ +Saves the object as an .RDS file with the filename +} +\details{ +See the examples for \code{\link{cache_name}()}. +} diff --git a/man/check.Rd b/man/check.Rd new file mode 100644 index 0000000..50f6de5 --- /dev/null +++ b/man/check.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{check} +\alias{check} +\title{Checking the object for appropriate form.} +\usage{ +check(object) +} +\arguments{ +\item{object}{The object to be checked.} +} +\value{ +The tables generated. + +# Check a data.list (see \code{?\link{check.data.list}}) +check(Dbuilding) +} +\description{ +Checking the object for appropriate form. +} +\details{ +Prints on table form the result of the check. +} diff --git a/man/check.data.list.Rd b/man/check.data.list.Rd new file mode 100644 index 0000000..7651654 --- /dev/null +++ b/man/check.data.list.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{check.data.list} +\alias{check.data.list} +\title{Checking the data.list for appropriate form.} +\usage{ +\method{check}{data.list}(object) +} +\arguments{ +\item{object}{The object to be checked.} +} +\value{ +The tables generated. + +# Check a data.list (see \code{?\link{check.data.list}}) +check(Dbuilding) + +# Vector with observations not same length as t +D <- Dbuilding +D$heatload <- D$heatload[1:10] +check(D) + +# Some NAs in k1 forecast +D <- Dbuilding +D$Ta$k1[1:1500] <- NA +check(D) + +# Wrong column names +names(D$Ta) +} +\description{ +Checking the data.list for appropriate form. +} +\details{ +Prints a check of the time vector t, which must have equidistant time points and no NAs. + +Then the results of checking vectors (observations): + - ok: A 'V' indicates a successful check + - maxNAs: Proportion of NAs + - length: printed if not the same as the 't' vector + - class: the class + +Then the results of checking data.frames and matrices (forecasts): + - ok: a 'V' indicates a successful check + - maxNAs: the proportion of NAs for the horizon (i.e. column) with the highest proportion of NAs + - meanNAs: the proportion of NAs of the entire data.frame + - nrow: printed if not the same as the 't' vector length + - colnames: columns must be names 'kxx', where 'xx' is the horizon + - sameclass: 'X' if not all columns are the same class + - class: prints the class of the columns if they are all the same +} diff --git a/man/complete_cases.Rd b/man/complete_cases.Rd new file mode 100644 index 0000000..8a53bb6 --- /dev/null +++ b/man/complete_cases.Rd @@ -0,0 +1,65 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/complete_cases.R +\name{complete_cases} +\alias{complete_cases} +\alias{complete_cases.list} +\alias{complete_cases.data.frame} +\title{Find complete cases in forecast matrices} +\usage{ +complete_cases(object, kseq = NA) + +\method{complete_cases}{list}(object, kseq = NA) + +\method{complete_cases}{data.frame}(object, kseq = NA) +} +\arguments{ +\item{object}{A data.frame (with columns named 'kxx') or a list of +data.frames.} + +\item{kseq}{integer vector: If given then only these horizons are processed.} +} +\value{ +A logical vector specifying if there is no missing + values across all horizonsd. +} +\description{ +Returns a logical vector indicating the time points which +} +\details{ +Given a forecast matrix the forecasts are lagged "+k" steps to align them and +then 'complete.cases()' is run on that . + +Gieven a list of forecast matrices the points where all are complete (also all horizons) are complete are TRUE. +} +\examples{ +# Take a small data set +D <- subset(Dbuilding, 1:20, kseq=1:5) +# Check the forecast matrix of ambient temperature +D$Ta +# Which are complete over all horizons? The first are not since not all horizons +# have a value there (after lagging) +complete_cases(D$Ta) +# Same goes if given as a list +complete_cases(D["Ta"]) +# and if more than one is given +complete_cases(D[c("Ta","I")]) + +# Set some NA of some horizon +D$I$k3[8:9] <- NA +# Now they are recognized as not complete +complete_cases(D[c("Ta","I")]) + +# If we deal with residuals, which are observations and there for have column names "hxx" +Resid <- residuals(D$Ta, D$Taobs) +names(Resid) +# With columns with "h" instead of "k" no lagging occurs in complete_cases +complete_cases(Resid) +# +Resid2 <- Resid +Resid$h3[8:9] <- NA +complete_cases(list(Resid,Resid2)) + +} +\author{ +Peder Bacher +} diff --git a/man/ct.Rd b/man/ct.Rd new file mode 100644 index 0000000..5783673 --- /dev/null +++ b/man/ct.Rd @@ -0,0 +1,128 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ct.R +\name{ct} +\alias{ct} +\alias{ct.character} +\alias{ct.POSIXct} +\alias{ct.POSIXlt} +\alias{ct.numeric} +\title{Convertion to POSIXct} +\usage{ +ct(object, ...) + +\method{ct}{character}(object, tz = "GMT", ...) + +\method{ct}{POSIXct}(object, tz = NA, duplicatedadd = NA, ...) + +\method{ct}{POSIXlt}(object, tz = NA, duplicatedadd = NA, ...) + +\method{ct}{numeric}(object, ...) +} +\arguments{ +\item{object}{The object to convert can be: character, numeric, POSIXct or POSIXlt} + +\item{...}{Arguments to be passed to methods.} + +\item{tz}{Timezone. If set, then the time zone will be changed of the object.} + +\item{duplicatedadd}{Seconds to be added to duplicated time stamps, to mitigate the problem of duplicated timestamps at the shift to winter time. So the second time a time stamp occurs (identified with \code{duplicated}) then the seconds will be added.} +} +\value{ +An object of class POSIXct +} +\description{ +The object is converted into POSIXct with tz="GMT". +} +\details{ +A simple helper, which wraps \code{\link{as.POSIXct}}` and sets the time zone to "GMT" per default. +} +\section{Methods}{ + + + + - ct.character: Simply a wrapper for \code{as.POSIXct} with default \code{tz} + + + - ct.POSIXct: Changes the time zone of the object if \code{tz} is given. + + + - ct.POSIXlt: Converts to POSIXct. + + + - ct.numeric: Converts from UNIX time in seconds to POSIXct with \code{tz} as GMT. +} + +\examples{ + + +# Create a POSIXct with tz="GMT" +ct("2019-01-01") +class(ct("2019-01-01")) +ct("2019-01-01 01:00:05") + + +# Convert to POSIXct +class(ct(as.POSIXlt("2019-01-01"))) + +# To seconds and back again +ct(as.numeric(1000, units="sec")) + + +# -------- +# Convert character of time which has summer time leaps +# Example from CET (with CEST which is winter time) +# +# The point of shifting to and from summer time: +# DST Start (Clock Forward) DST End (Clock Backward) +# Sunday, March 31, 02:00 Sunday, October 27, 03:00 + +# -------- +# From to winter time to summer time +txt <- c("2019-03-31 01:00", + "2019-03-31 01:30", + "2019-03-31 03:00", + "2019-03-31 03:30") +x <- ct(txt, tz="CET") +x +ct(x, tz="GMT") + +# BE AWARE of this conversion of the 02:00: to 02:59:59 (exact time of shift) will lead to a +# wrong conversion +txt <- c("2019-03-31 01:30", + "2019-03-31 02:00", + "2019-03-31 03:30") +x <- ct(txt, tz="CET") +x +ct(x, tz="GMT") +# Which a diff on the time can detect, since all steps are not equal +plot(diff(ct(x, tz="GMT"))) + +# -------- +# Shift to winter time is more problematic +# It works like this +txt <- c("2019-10-27 01:30", + "2019-10-27 02:00", + "2019-10-27 02:30", + "2019-10-27 03:00", + "2019-10-27 03:30") +x <- ct(txt, tz="CET") +x +ct(x, tz="GMT") + +# however, timestamps can be given like this +txt <- c("2019-10-27 01:30", + "2019-10-27 02:00", + "2019-10-27 02:30", + "2019-10-27 02:00", + "2019-10-27 02:30", + "2019-10-27 03:00", + "2019-10-27 03:30") +x <- ct(txt, tz="CET") +x +ct(x, tz="GMT") +# Again can be detected, since all steps are not equal +plot(diff(ct(x, tz="GMT"))) +# This can be fixed by (note that it can go wrong, e.g. with gaps around convertion etc.) +ct(x, tz="GMT", duplicatedadd=3600) + +} diff --git a/man/data.list.Rd b/man/data.list.Rd new file mode 100644 index 0000000..81840c4 --- /dev/null +++ b/man/data.list.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{data.list} +\alias{data.list} +\title{Make a data.list} +\usage{ +data.list(...) +} +\arguments{ +\item{...}{Should hold: time t, observations as vectors and forecasts as data.frames} +} +\value{ +a data.list. +} +\description{ +Make a data.list of the vectors and data.frames given. +} +\details{ +See the vignette 'setup-data' on how a data.list must be setup. + +It's simply a list of class \code{data.list} holding: + - vector \code{t} + - vector(s) of observations + - data.frames (or matrices) of forecast inputs +} +\examples{ +# Put together a data.list +# The time vector +time <- seq(ct("2019-01-01"),ct("2019-01-02"),by=3600) +# Observations time series (as vector) +xobs <- rnorm(length(time)) +# Forecast input as data.frame +X <- data.frame(matrix(rnorm(length(time)*3), ncol=3)) +names(X) <- pst("k",1:3) + +D <- data.list(t=time, xobs=xobs, X=X) + +# Check it +check(D) + +} diff --git a/man/depth.Rd b/man/depth.Rd new file mode 100644 index 0000000..859ba15 --- /dev/null +++ b/man/depth.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/depth.R +\name{depth} +\alias{depth} +\title{Depth of a list} +\usage{ +depth(this) +} +\arguments{ +\item{this}{list} +} +\value{ +integer +} +\description{ +Depth of a list +} +\details{ +Returns the depth of a list +} diff --git a/man/equals-.data.list.Rd b/man/equals-.data.list.Rd new file mode 100644 index 0000000..c45f61a --- /dev/null +++ b/man/equals-.data.list.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{==.data.list} +\alias{==.data.list} +\title{Determine if two data.lists are identical} +\usage{ +\method{==}{data.list}(x, y) +} +\arguments{ +\item{x}{first data.list} + +\item{y}{second data.list} +} +\value{ +logical +} +\description{ +Compare two data.lists +} +\details{ +Returns TRUE if the two data.lists are fully identical, so all data, order of variables etc. must be fully identical +} +\examples{ + +Dbuilding == Dbuilding + +D <- Dbuilding +D$Ta$k2[1] <- NA +Dbuilding == D + +D <- Dbuilding +names(D)[5] <- "I" +names(D)[6] <- "Ta" +Dbuilding == D + + +} diff --git a/man/flattenlist.Rd b/man/flattenlist.Rd new file mode 100644 index 0000000..c5d1c53 --- /dev/null +++ b/man/flattenlist.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/flattenlist.R +\name{flattenlist} +\alias{flattenlist} +\title{Flattens list} +\usage{ +flattenlist(x) +} +\arguments{ +\item{x}{List to flatten.} +} +\value{ +A flatten list +} +\description{ +Flattens list in a single list of data.frames +} +\details{ +Flattens list. Can maybe be made better. It might end up copying data in +memory!? It might change the order of the elements. +} diff --git a/man/forecastmodel.Rd b/man/forecastmodel.Rd new file mode 100644 index 0000000..92b7d88 --- /dev/null +++ b/man/forecastmodel.Rd @@ -0,0 +1,171 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/forecastmodel.R-documentation.R +\name{forecastmodel} +\alias{forecastmodel} +\title{Class for forecastmodels} +\description{ +R6 class for a forecastmodel +} +\details{ +This class holds the variables and functions needed for defining and setting up a forecast model - independent of the fitting scheme. +See the vignettes on how to setup and use a model and the website \url{https://onlineforecasting.org} for more info. + + + +Holds all the information needed independently of the fitting scheme (e.g. lm_fit or rls_fit), see the fields and functions below. + +The fields are separated into: + - Fields for setting up the model + - Fields used when fitting (e.g. which horizons to fit for is set in \code{kseq} + +See the fields description below. + +Note, it's an R6 class, hence an object variable is a pointer (reference), which means two important points: + - In order to make a copy, the function clone_deep() must be used (usually \code{clone(deep=TRUE)}, but that will end in an infinite loop). + - It can be manimulated directly in functions (without return). The code is written such that no external functions manipulate the model object, except for online updating. + +For online updating (i.e. receiving new data and updating the fit), then the model definition and the data becomes entangled, since transformation functions like low-pass filtering with \code{\link{lp}()} requires past values. +See the vignette ??(ref to online vignette, not yet available) and note that \code{\link{rls_fit}()} resets the state, which is also done in all \code{xxx_fit} functions (e.g. \code{\link{rls_fit}}. +} +\section{Public fields used for setting up the model}{ + + + - output = NA, character: Name of the output. + + - inputs = list(), add them with add_inputs(): List of inputs (which are R6 objects) (note the "cloning of list of reference objects" issue below in deep_clone function) + + - regprmexpr = NA: The expression (as character) used for generating the regprm, e.g. "\code{\link{rls_prm}()}" for RLS. + + - regprm = list(): Regression parameters calculated by evaluating the \code{regprmexpr}. + + - prmbounds = as.matrix(data.frame(lower=NA, init=NA, upper=NA)): The bounds for optimization of the parameters, e.g. with \code{\link{rls_optim}()}. + + - outputrange = NA, numeric vector of length 2: Limits of the predictions cropped in the range, e.g. outputrange = c(0,Inf) removes all negative output predictions. +} + +\section{Public fields used when the model is fitted}{ + + + - kseq = NA: The horizons to fit for. + + - kseqopt = NA: The horizons to fit for when optimizing. + + - p = NA: The (transformation stage) parameters used for the fit. + + - Lfits = list(): The regression fits, one for each k in kseq (simply a list with the latest fit). + + - datatr = NA: Transformed input data (data.list with all inputs for regression) +} + +\section{Public methods}{ + +All public functions are described below and in examples a section for each is included: +} + +\section{\code{$new()}}{ + +Create a new `forecastmodel` object. + +Returns a forecastmodel object. +} + +\section{\code{$add_inputs(...)}}{ + + Add inputs to the model. + + - \code{...}: The inputs are given as arguments, see examples. +} + +\section{\code{$add_regprm(regprm_expr)}}{ + +Add expression (as character) which generates regression parameters. +} + +\section{\code{$add_prmbounds(...)}}{ + +Add the transformation parameters and bounds for optimization. +} + +\section{\code{$get_prmbounds(...)}}{ + +Get the transformation parameter bounds, used by optimization functions e.g. \code{\link{rls_optim}()}. +} + +\section{\code{$insert_prm(prm)}}{ + +Insert the transformation parameters prm in the input expressions and regression expressions, and keep them in $prm (simply string manipulation). +} + +\section{\code{$transform_data(data)}}{ + +Function for transforming the input data to the regression stage input data (see \code{vignette("setup-data", package = "onlineforecast")}). +} + +\section{\code{$reset_state()}}{ + +Resets the input states and stored data for iterative fitting (datatr rows and yAR) (see ??(ref to online updating vignette, not yet available). +} + +\section{\code{$check(data = NA)}}{ + +Check if the model is setup correctly. +} + +\examples{ +# New object +model <- forecastmodel$new() + +# Print it +model + + +# Add model inputs +model$add_inputs(Ta = "lp(Ta)") +# See it +model$inputs +# Update to use no low-pass filter +model$add_inputs(Ta = "Ta") +model$inputs +# Add another +model$add_inputs(I = "lp(I)") +model$inputs + +# Simply a list, so manipulate directly +class(model$inputs$Ta) +model$inputs$Ta$expr <- "lp(Ta, a1=0.9)" + +# Add the parameters for the regression stage +model$add_regprm("rls_prm(lambda=0.99)") +# The evaluation is a list, which is set in +model$regprm + + +# Set the lambda to be optimized between 0.9 and 0.999, starting at 0.99 +model$add_prmbounds(lambda = c(0.9, 0.99, 0.999)) +# Note the "__" syntax to set parameters for inputs: "input__prm" +model$add_prmbounds(Ta__a1 = c(0.8, 0.95, 0.99)) + +# Get the lower bounds +model$get_prmbounds("lower") + +# Insert the init parameters +prm <- model$get_prmbounds("init") +prm +# Before +model$inputs$Ta$expr +# After +model$insert_prm(prm) +model$inputs$Ta$expr + +# Check if the model is setup and can be used with a given data.list +# An error is thrown +try(model$check(Dbuilding)) +# Add the model output +model$output <- "heatload" +# Still not error free +try(model$check(Dbuilding)) +# Add the horizons to fit for +model$kseq <- 1:4 +# Finally, no errors :) +model$check(Dbuilding) +} diff --git a/man/fs.Rd b/man/fs.Rd new file mode 100644 index 0000000..e9c35fb --- /dev/null +++ b/man/fs.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fs.R +\name{fs} +\alias{fs} +\title{Generation of Fourrier series.} +\usage{ +fs(X, nharmonics) +} +\arguments{ +\item{X}{must be a dataframe with columns k1,k2,..., . One period is from 0 to 1 +(so for example if X is hour of day, then divide X by 24 to obtain a daily period).} + +\item{nharmonics}{the number of harmonics, so creates double as many inputs! i.e. one sine and one cos for each harmonic.} +} +\value{ +Returns a list of dataframes (two for each i in \code{1:nharmonics}) with same number of columns as X. +} +\description{ +Function for generating Fourrier series as a function of x E.g. use for +harmonic functions for modelling the diurnal patterns or for basis functions. +} +\examples{ +# Make a data.frame with time of day in hours for different horizons +tday <- make_tday(seq(ct("2019-01-01"), ct("2019-01-04"), by=3600), kseq=1:5) +# See whats in it +str(tday) +head(tday) + +# Now use the function to generate Fourier series +L <- fs(tday/24, nharmonics=2) +# See what is in it +str(L) + +# Make a plot to see the harmonics +par(mfrow=c(2,1)) +# The first harmonic +plot(L$sin1$k1, type="l") +lines(L$cos1$k1, type="l") +# The second harmonic +plot(L$sin2$k1, type="l") +lines(L$cos2$k1, type="l") + + +} diff --git a/man/getse.Rd b/man/getse.Rd new file mode 100644 index 0000000..c4d3b22 --- /dev/null +++ b/man/getse.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/getse.R +\name{getse} +\alias{getse} +\title{Getting subelement from list.} +\usage{ +getse(L, inm = NA, depth = 2, useregex = FALSE, fun = NA) +} +\arguments{ +\item{L}{The list to get sub elements from.} + +\item{inm}{Either an integer index or a name of the subelements to return.} + +\item{depth}{The depth of the subelements to match names in: +- 1: is directly in the list. +- 2: is in list of each element in the list. +- 3 and more: simply deeper in the sublists.} + +\item{useregex}{logical: should inm be used as regex pattern for returning elements matching, in the specified layer.} + +\item{fun}{function: if given, then it will be applied to all the matched subelements before returning them.} +} +\value{ +A list of the matched elements. +} +\description{ +A helping function for getting subelemlts from a list. +} +\details{ +Often it is needed to get a subelement from a list, which can be done using lapply. +But to make life easiere here is a small function for getting subelements in a nested list at a certain debth. +} +\examples{ +# Make a nested list +L <- list(x1=list(x=list("val11","val112"), + y=list("val12"), + test=list("testlist2")), + x2=list(x=list("val21","val212"), + y=list("val22"), + test=list("testlist2")), + x3=list(x=list("val31","val312"), + y=list("val32"), + test=list("testlist3"))) + +# Get the subelement "x1" +str(getse(L, "x1", depth=1)) +# Same as +str(L[["x1"]]) + +# Get the element named x in second layer +str(getse(L, "x", depth=2)) +# Depth is default to 2 +str(getse(L, "y")) + +# Nice when splitting string +x <- strsplit(c("x.k1","y.k2"), "\\\\.") +# Get all before the split "\\." +getse(x, 1) +# Get after +getse(x, 2) + +# Get an element with an integer index +x <- strsplit(c("x.k1","y.k2","x2"), "\\\\.") +getse(x, 1) +# if the element is not there, then an error is thrown +try(getse(x, 2)) + +# Use regex pattern for returning elements matching in the specified layer +getse(L, "^te", depth=2, useregex=TRUE) + +} diff --git a/man/gof.Rd b/man/gof.Rd new file mode 100644 index 0000000..d5432bb --- /dev/null +++ b/man/gof.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gof.R +\name{gof} +\alias{gof} +\title{Simple wrapper for graphics.off()} +\usage{ +gof() +} +\description{ +Simple wrapper for graphics.off() +} diff --git a/man/grapes-times-times-grapes.Rd b/man/grapes-times-times-grapes.Rd new file mode 100644 index 0000000..aad3f99 --- /dev/null +++ b/man/grapes-times-times-grapes.Rd @@ -0,0 +1,57 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/operator_multiply.R +\name{\%**\%} +\alias{\%**\%} +\title{Multiplication of list with y, elementwise} +\usage{ +x \%**\% y +} +\arguments{ +\item{x}{a list of matrices, data.frames, etc.} + +\item{y}{a vector, data.frame or matrix} +} +\value{ +A list of same length of x +} +\description{ +Multiplication of each element in a list (x) with y +} +\details{ +Each element of x is multiplied with y using the usual elementwise '*' operator. + +Typical use is when a function, e.g. \code{\link{bspline}()}, returns a list of matrices (e.g. one for each base spline) and they should individually be multiplied with y (a vector, matrix, etc.). + +Since this is intended to be used for forecast models in the transformation stage +then there are some percularities: + +If the number of columns or the names of the columns are not equal for one element in x +and y, then only the columns with same names are used, hence the resulting matrices can be +of lower dimensions. + +See the example \url{https://onlineforecasting.org/examples/solar-power-forecasting.html} where the operator is used. +} +\examples{ + +x <- list(matrix(1:9,3), matrix(9:1,3)) +x + +y <- matrix(2,3,3) +y + +x \%**\% y + +y <- 1:3 + +x \%**\% y + +# Naming percularity +nams(x[[1]]) <- c("k1","k2","k3") +nams(x[[2]]) <- c("k2","k3","k4") +y <- matrix(2,3,3) +nams(y) <- c("k1","k3","k7") + +# Now the only the horizons matching will be used +x \%**\% y + +} diff --git a/man/in_range.Rd b/man/in_range.Rd new file mode 100644 index 0000000..658c200 --- /dev/null +++ b/man/in_range.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/in_range.R +\name{in_range} +\alias{in_range} +\title{Selects a period} +\usage{ +in_range(tstart, time, tend = NA) +} +\arguments{ +\item{tstart}{The start of the period.} + +\item{time}{The timestamps as POSIX.} + +\item{tend}{The end of the period. If not given then the period will have no end.} + +\item{timezone}{The timezone of the timestamps, time.} +} +\value{ +A logical vector indicating the selected period with TRUE +} +\description{ +Returns a logical vector of boolean values where TRUE indicates if timestamp is within the +specified period. +} +\details{ +Returns a logical vector of boolean values where TRUE indicates if timestamp is within the +specified period spanned by tstart and tend. + +Note the convention of time stamp in the end of the time intervals causes the time point +which equals \code{tstart} not to be included. See last example. + +The times can be given as character or POSIX, per default in tz='GMT'. +} +\examples{ + +# Take a subset +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) + +# Just a logical returning TRUE in a specified period +in_range("2010-12-20", D$t, "2010-12-22") + +# Set which period to evaluate when optimizing parameters, like in rls_optim() +# (the points with scoreperiod == false are not included in the score evaluation) +D$scoreperiod <- in_range("2010-12-20", D$t) +D$scoreperiod + +# Further, excluding a small period by +D$scoreperiod[in_range("2010-12-26", D$t, "2010-12-27")] <- FALSE +D$scoreperiod + +# Note the convention of time stamp in the end of the time intervals +# causes the point with t = 2010-12-26 00:00:00 not to be included +# since it's covering to "2010-12-25 23:00:00" to "2010-12-26 00:00:00" +D$t[in_range("2010-12-26", D$t, "2010-12-27")] + +# When characters are given, then they are translated to the time zone of the time vector +D <- subset(Dbuilding, c("2010-12-15", "2010-12-16")) +D$t <- ct(D$t, tz="CET") +D$t[in_range("2010-12-15 02:00", D$t, "2010-12-15 05:00")] + +} diff --git a/man/input_class.Rd b/man/input_class.Rd new file mode 100644 index 0000000..33d459b --- /dev/null +++ b/man/input_class.Rd @@ -0,0 +1,105 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/input_class.R-documentation.R +\name{input_class} +\alias{input_class} +\title{Class for forecastmodel inputs} +\description{ +R6 class for for forecastmodel inputs +} +\details{ +Holds variables and functions needed for an input, as added by \code{\link{forecastmodel}$add_inputs()}. + + +Details of the class. +} +\section{Public fields}{ + + + - expr = NA: The expression as string for transforming the input. + + - state_L = list(): The list holding potential state values kept by the function evaluated in the expression. + + - state_i = integer(1): index counter for the state list. +} + +\section{Public methods}{ + +All public functions are described below and in examples a section for each is included: +} + +\section{\code{$new(expr)}}{ + +Create a new input with the expression \code{expr}. +} + +\section{\code{$evaluate(data}}{ + +Generate (transform) the input by evaluating the expr with the \code{data} (data.list) attached. +} + +\section{\code{$state_reset()}}{ + +Each function in the expressions (lp, fs, etc.) have the possibility to save a state, which can be read next time the are called. + +Reset the state by deleting \code{state_L} and setting \code{state_i} to 0. + + +# After running +model$inputs[[1]]$evaluate(D) +# the lp() has saved it's state for next time +model$inputs[[1]]$state_L +# New data arrives +Dnew <- subset(Dbuilding, 11, kseq=1:4) +# So in lp() the state is read and it continues +model$inputs[[1]]$evaluate(Dnew) + +# If we want to reset the state, which is done in all _fit() functions (e.g. rls_fit), such that all transformations starts from scratch +# Reset the state +model$inputs[[1]]$evaluate(D) +# Test resetting +model$inputs[[1]]$state_reset() +# Now there is no state +model$inputs[[1]]$evaluate(Dnew) +# So lp() starts by taking the first data point +Dnew$Ta +} + +\section{\code{$state_getval(initval)}}{ + +Get the saved value in state. This function can be used in the beginning of transformation functions to get the current state value. +First time called return the \code{initval}. + +Note that since all transformation functions are called in the same order, +then the state can be read and saved by keeping a counter internally, the value is saved in the field $state_i. + +See example of use in \code{\link{lp}()}. +} + +\section{\code{$state_setval(val)}}{ + +Set the state value, done in the end of a transformation function, see above. + +See example of use in \code{\link{lp}()}. +} + +\examples{ +# new: + +# An input is created in a forecastmodel +model <- forecastmodel$new() +model$add_inputs(Ta = "lp(Ta, a1=0.9)") +# The 'inputs' is now a list +model$inputs +# With the input object +class(model$inputs[[1]]) + +# Now the transformation stage can be carried out to create the regression stage data +# Take a data.list subset for the example +D <- subset(Dbuilding, 1:10, kseq=1:4) +# Transform the data +model$inputs[[1]]$evaluate(D) +# What happens is simply that the expression is evaluated with the data +# (Note that since not done in the model some functions are missing) +eval(parse(text=model$inputs[[1]]$expr), D) + +} diff --git a/man/lagdf.Rd b/man/lagdf.Rd new file mode 100644 index 0000000..a072d02 --- /dev/null +++ b/man/lagdf.Rd @@ -0,0 +1,81 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lagdf.R +\name{lagdf} +\alias{lagdf} +\alias{lagdf.data.frame} +\title{Lagging which returns a data.frame} +\usage{ +lagdf(x, lagseq) + +\method{lagdf}{data.frame}(x, lagseq) +} +\arguments{ +\item{x}{The data.frame to have columns lagged} + +\item{lagseq}{The sequence of lags as an integer. Alternatively, as a character "+k", "-k", "+h" or "-h", e.g. "k12" will with "+k" be lagged 12.} +} +\value{ +A data.frame. + +A data.frame with columns that are lagged +} +\description{ +Lagging by shifting the values back or fourth always returning a data.frame. + +Lagging of a data.frame +} +\details{ +This function lags (shifts) the values of the vector. A data.frame is always returned with the columns +as the vectors lagged with the values in lagseq. The column names are set to "kxx", where xx are the lag of the column. + +This function lags the columns with the integer values specified with the argument \code{lagseq}. +} +\examples{ +# The values are simply shifted +# Ahead in time +lagdf(1:10, 3) +# Back in time +lagdf(1:10, -3) +# Works but returns a numric +lagdf(as.factor(1:10), 3) +# Works and returns a character +lagdf(as.character(1:10), 3) +# Giving several lag values +lagdf(1:10, c(1:3)) +lagdf(1:10, c(5,3,-1)) + +# See also how to lag a forecast data.frame with: ?lagdf.data.frame + + + +# dataframe of forecasts +X <- data.frame(k1=1:10, k2=1:10, k3=1:10) +X + +# Lag all columns +lagdf(X, 1) +\dontshow{if(!all(is.na(lagdf(X, 1)[1, ]))){stop("Lag all columns didn't work")}} + +# Lag each column different steps +lagdf(X, 1:3) +# Lag each columns with its k value from the column name +lagdf(X, "+k") +\dontshow{ + if(any(lagdf(X, 1:3) != lagdf(X, "+k"),na.rm=TRUE)){stop("Couldn't lag +k")} +} +# Also works for columns named hxx +names(X) <- gsub("k", "h", names(X)) +lagdf(X, "-h") + +# If lagseq must have length as columns in X, it doesn't know how to lag and an error is thrown +try(lagdf(X, 1:2)) + +\dontshow{ +if(!class(lagdf(data.frame(k1=1:10), 2)) == "data.frame"){stop("Trying to lag data.frame with 1 column, but return is not class data.frame")} +if(!all(dim(lagdf(data.frame(k1=1:10), "+k")) == c(10,1))){stop("Trying to lag data.frame with 1 column, but return is not class data.frame")} +} + +} +\seealso{ +\code{\link{lagdf.data.frame}} which is run when \code{x} is a data.frame. +} diff --git a/man/lagdl.Rd b/man/lagdl.Rd new file mode 100644 index 0000000..7698f34 --- /dev/null +++ b/man/lagdl.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lagdl.R +\name{lagdl} +\alias{lagdl} +\title{Lagging which returns a data.list} +\usage{ +lagdl(DL, lagseq) +} +\arguments{ +\item{DL}{The data.list to be lagged.} + +\item{lagseq}{The integer(s) setting the lag steps.} +} +\value{ +A data.list. +} +\description{ +Lagging by shifting the values back or fourth always returning a data.list. +} +\details{ +This function lags (shifts) the values of the vector. A data.list is always returned with each data.frame lagged with \code{lagdf}. +} +\examples{ +# The values are simply shifted in each data.frame with lagdf + +} diff --git a/man/lagvec.Rd b/man/lagvec.Rd new file mode 100644 index 0000000..e2bad3c --- /dev/null +++ b/man/lagvec.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lagvec.R +\name{lagvec} +\alias{lagvec} +\title{Lag by shifting} +\usage{ +lagvec(x, lag) +} +\arguments{ +\item{x}{The vector to lag} + +\item{lag}{(integer) The steps to lag.} +} +\value{ +The shifted vector +} +\description{ +Lag by shifting the vecter +} +\details{ +A positive value of \code{lag} shifts the values to the right in the vector. +} +\examples{ + +# The values are simply shifted +# Ahead in time +lagvec(1:10, 3) +# Back in time +lagvec(1:10, -3) +# Works but returns a numric +lagvec(as.factor(1:10), 3) +# Works and returns a character +lagvec(as.character(1:10), 3) + +} diff --git a/man/lapply_cbind.Rd b/man/lapply_cbind.Rd new file mode 100644 index 0000000..fd57b1d --- /dev/null +++ b/man/lapply_cbind.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lapply.R +\name{lapply_cbind} +\alias{lapply_cbind} +\title{Helper which does lapply and then cbind} +\usage{ +lapply_cbind(X, FUN, ...) +} +\arguments{ +\item{X}{object to apply on} + +\item{FUN}{function to apply} +} +\description{ +Helper which does lapply and then cbind +} diff --git a/man/lapply_cbind_df.Rd b/man/lapply_cbind_df.Rd new file mode 100644 index 0000000..5b8e5a6 --- /dev/null +++ b/man/lapply_cbind_df.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lapply.R +\name{lapply_cbind_df} +\alias{lapply_cbind_df} +\title{Helper which does lapply, cbind and then as.data.frame} +\usage{ +lapply_cbind_df(X, FUN, ...) +} +\arguments{ +\item{X}{object to apply on} + +\item{FUN}{function to apply} +} +\description{ +Helper which does lapply, cbind and then as.data.frame +} diff --git a/man/lapply_rbind.Rd b/man/lapply_rbind.Rd new file mode 100644 index 0000000..a4e3939 --- /dev/null +++ b/man/lapply_rbind.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lapply.R +\name{lapply_rbind} +\alias{lapply_rbind} +\title{Helper which does lapply and then rbind} +\usage{ +lapply_rbind(X, FUN, ...) +} +\arguments{ +\item{X}{object to apply on} + +\item{FUN}{function to apply} +} +\description{ +Helper which does lapply and then rbind +} diff --git a/man/lapply_rbind_df.Rd b/man/lapply_rbind_df.Rd new file mode 100644 index 0000000..83a114a --- /dev/null +++ b/man/lapply_rbind_df.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lapply.R +\name{lapply_rbind_df} +\alias{lapply_rbind_df} +\title{Helper which does lapply, rbind and then as.data.frame} +\usage{ +lapply_rbind_df(X, FUN, ...) +} +\arguments{ +\item{X}{object to apply on} + +\item{FUN}{function to apply} +} +\description{ +Helper which does lapply, rbind and then as.data.frame +} diff --git a/man/lm_fit.Rd b/man/lm_fit.Rd new file mode 100644 index 0000000..1e7399b --- /dev/null +++ b/man/lm_fit.Rd @@ -0,0 +1,91 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lm_fit.R +\name{lm_fit} +\alias{lm_fit} +\title{Fit an onlineforecast model with \code{\link{lm}}} +\usage{ +lm_fit( + prm = NA, + model, + data, + scorefun = NA, + returnanalysis = TRUE, + printout = TRUE +) +} +\arguments{ +\item{prm}{as numeric with the parameters to be used when fitting.} + +\item{model}{object of class forecastmodel with the model to be fitted.} + +\item{data}{as data.list with the data to fit the model on.} + +\item{scorefun}{Optional. If scorefun is given, e.g. \code{\link{rmse}}, then the value of this is also returned.} + +\item{returnanalysis}{as logical determining if the analysis should be returned. See below.} + +\item{printout}{Defaults to TRUE. Prints the parameters for model.} +} +\value{ +Depends on: + + - If \code{returnanalysis} is TRUE a list containing: + + * \code{Yhat}: data.frame with forecasts for \code{model$kseq} horizons. + + * \code{model}: The forecastmodel object cloned deep, so can be modified without changing the original object. + + * \code{data}: data.list with the data used, see examples on how to obtain the transformed data. + + * \code{Lfitval}: a character "Find the fits in model$Lfits", it's a list with the lm fits for each horizon. + + * \code{scoreval}: data.frame with the scorefun result on each horizon (only scoreperiod is included). + + - If \code{returnanalysis} is FALSE (and \code{scorefun} is given): The sum of the score function on all horizons (specified with model$kseq). +} +\description{ +Fit a linear regression model given a onlineforecast model, seperately for each prediction horizon +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a simple model +model <- forecastmodel$new() +model$output <- "y" +model$add_inputs(Ta = "lp(Ta, a1=0.9)", + mu = "one()") + +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 + +# Now we can fit the model with RLS and get the model validation analysis data +fit <- lm_fit(prm=NA, model=model, data=D) +# What did we get back? +names(fit) +class(fit) +# The one-step forecast +plot(D$y, type="l") +lines(lagvec(fit$Yhat$k1,-1), col=2) +# Get the residuals +plot(residuals(fit)$h1) +# Score for each horizon +score(residuals(fit)) + +# The lm_fit don't put anything in this field +fit$Lfitval +# Find the lm fits here +model$Lfits +# See result for k=1 horizon +summary(model$Lfits$k1) +# Some diurnal pattern is present +acf(residuals(fit)$h1, na.action=na.pass, lag.max=96) + +# Run with other parameters and return the RMSE +lm_fit(c(Ta__a1=0.8), model, D, scorefun=rmse, returnanalysis=FALSE) +lm_fit(c(Ta__a1=0.9), model, D, scorefun=rmse, returnanalysis=FALSE) + +} diff --git a/man/lm_optim.Rd b/man/lm_optim.Rd new file mode 100644 index 0000000..407caa4 --- /dev/null +++ b/man/lm_optim.Rd @@ -0,0 +1,84 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lm_optim.R +\name{lm_optim} +\alias{lm_optim} +\title{Optimize parameters for onlineforecast model fitted with LM} +\usage{ +lm_optim( + model, + data, + kseq = NA, + scorefun = rmse, + cachedir = "", + cachererun = FALSE, + printout = TRUE, + method = "L-BFGS-B", + ... +) +} +\arguments{ +\item{model}{The onlineforecast model, including inputs, output, kseq, p} + +\item{data}{The data.list including the variables used in the model.} + +\item{kseq}{The horizons to fit for (if not set, then model$kseq is used)} + +\item{scorefun}{The function to be score used for calculating the score to be optimized.} + +\item{cachedir}{A character specifying the path (and prefix) of the cache file name. If set to \code{""}, then no cache will be loaded or written. See \url{https://onlineforecasting.org/vignettes/nice-tricks.html} for examples.} + +\item{cachererun}{A logical controlling whether to run the optimization even if the cache exists.} + +\item{printout}{A logical determining if the score function is printed out in each iteration of the optimization.} + +\item{method}{The method argument for \code{\link{optim}}.} + +\item{...}{Additional parameters to \code{\link{optim}}} +} +\value{ +Result object of optim(). +Parameters resulting from the optimization can be found from \code{result$par} +} +\description{ +Optimize parameters (transformation stage) of LM model +} +\details{ +This is a wrapper for \code{\link{optim}} to enable easy use of bounds and caching in the optimization. +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a simple model +model <- forecastmodel$new() +model$add_inputs(Ta = "lp(Ta, a1=0.9)", + mu = "one()") +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 + +# Now we can fit the model and get the score, as it is +lm_fit(model=model, data=D, scorefun=rmse, returnanalysis=FALSE) +# Or we can change the low-pass filter coefficient +lm_fit(c(Ta__a1=0.99), model, D, rmse, returnanalysis=FALSE) + +# This could be passed to optim() (or any optimizer). +# See \code{forecastmodel$insert_prm()} for more details. +optim(c(Ta__a1=0.98), lm_fit, model=model, data=D, scorefun=rmse, returnanalysis=FALSE, + lower=c(Ta__a1=0.4), upper=c(Ta__a1=0.999), method="L-BFGS-B") + +# lm_optim is simply a helper it makes using bounds easiere and enables caching of the results +# First add bounds for lambda (lower, init, upper) +model$add_prmbounds(Ta__a1 = c(0.4, 0.98, 0.999)) + +# Now the same optimization as above can be done by +val <- lm_optim(model, D) +val + + +} +\seealso{ +\code{link{optim}} for how to control the optimization and \code{\link{rls_optim}} which works very similarly. +} diff --git a/man/lm_predict.Rd b/man/lm_predict.Rd new file mode 100644 index 0000000..998f644 --- /dev/null +++ b/man/lm_predict.Rd @@ -0,0 +1,60 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lm_predict.R +\name{lm_predict} +\alias{lm_predict} +\title{Prediction with an lm forecast model.} +\usage{ +lm_predict(model, datatr) +} +\arguments{ +\item{model}{Onlineforecast model object which has been fitted.} + +\item{datatr}{Transformed data.} +} +\value{ +The Yhat forecast matrix with a forecast for each model$kseq and for each time point in \code{datatr$t}. +} +\description{ +Use a fitted forecast model to predict its output variable with transformed data. +} +\details{ +See the ??ref(recursive updating vignette, not yet available). +} +\examples{ + + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a model +model <- forecastmodel$new() +model$add_inputs(Ta = "lp(Ta, a1=0.7)", mu = "one()") + +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 + +# Transform using the mdoel +datatr <- model$transform_data(D) + +# See the transformed data +str(datatr) + +# The model has not been fitted +model$Lfits + +# To fit +lm_fit(model=model, data=D) + +# Now the fits for each horizon are there (the latest update) +# For example +summary(model$Lfits$k1) + +# Use the fit for prediction +D$Yhat <- lm_predict(model, datatr) + +# Plot it +plot_ts(D, c("y|Yhat"), kseq=1) + +} diff --git a/man/long_format.Rd b/man/long_format.Rd new file mode 100644 index 0000000..05ff5ae --- /dev/null +++ b/man/long_format.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/long_format.R +\name{long_format} +\alias{long_format} +\title{Long format of prediction data.frame} +\usage{ +long_format(fit, Time = NULL) +} +\arguments{ +\item{fit}{The result from either lm_fit or rls_fit} + +\item{Time}{If the timestamps are missing from the fit object} +} +\value{ +Data.frame of when the prediction where made, also the prediction value and timestamp. +} +\description{ +Creates a long format of the predictions +} +\details{ +This functions creates a useful prediction data.frame which can be useful for analysis and plotting. +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +D$scoreperiod <- in_range("2010-12-20", D$t) +# Define a model +model <- forecastmodel$new() +model$add_inputs(Ta = "Ta", + mu = "one()") +model$add_regprm("rls_prm(lambda=0.99)") +model$kseq <- 1:6 +# Fit it +fit <- rls_fit(prm=c(lambda=0.99), model, D) + +# Get the forecasts (in fit$Yhat) on long format +long_format(fit) + +} diff --git a/man/lp.Rd b/man/lp.Rd new file mode 100644 index 0000000..7964f26 --- /dev/null +++ b/man/lp.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lp.R +\name{lp} +\alias{lp} +\title{First-order low-pass filtering} +\usage{ +lp(X, a1, usestate = TRUE) +} +\arguments{ +\item{X}{Dataframe or matrix (or list of them) of forecasts in columns to be low-pass filtered.} + +\item{a1}{The low-pass filter coefficient.} + +\item{usestate}{logical: Use the state kept in the model$input? if \code{lp()} is used outside model$transform_data(), then it must be set to FALSE, otherwise the input$state (which is not there) will be read leading to an error.} +} +\value{ +The low-pass filtered dataframe (as a matrix) +} +\description{ +First-order low-pass filtering of a time series vector. +} +\details{ +This function applies a first order unity gain low-pass filter to the columns of \code{X}. +The low-pass filter is applied to each column seperately. The stationary gain of the filter i one. + +If a list of dataframes (or matrices) is given, then the low-pass filtering is recursively applied on each. +} +\examples{ +# Make a dataframe for the examples +X <- data.frame(k1=rep(c(0,1),each=5)) +X$k2 <- X$k1 +Xf <- lp(X, 0.5, usestate=FALSE) +Xf + +# See the input and the low-pass filtered result +plot(X$k1) +lines(Xf[ ,"k1"]) +# Slower response with higher a1 value +lines(lp(X, 0.8, usestate=FALSE)[ ,"k1"]) + +# If a list of dataframes is given, then lp() is recursively applied on each +lp(list(X,X), 0.5, usestate=FALSE) + + +} diff --git a/man/lp_vector_cpp.Rd b/man/lp_vector_cpp.Rd new file mode 100644 index 0000000..4120434 --- /dev/null +++ b/man/lp_vector_cpp.Rd @@ -0,0 +1,13 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{lp_vector_cpp} +\alias{lp_vector_cpp} +\title{Low pass filtering of a vector.} +\arguments{ +\item{x}{A numeric vector} + +\item{a1}{the first order low-pass filter coefficient} +} +\description{ +This function returns a vector which is x through a unity gain first-order low-pass filter. +} diff --git a/man/make_input.Rd b/man/make_input.Rd new file mode 100644 index 0000000..751da32 --- /dev/null +++ b/man/make_input.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/make_input.R +\name{make_input} +\alias{make_input} +\title{Make a forecast matrix (as data.frame) from observations.} +\usage{ +make_input(observations, kseq) +} +\arguments{ +\item{observations}{vector of observations.} + +\item{kseq}{vector of integers, respresenting the desired "k-steps ahead".} +} +\value{ +Returns a forecast matrix (as a data.frame) with simply the observation vector copied to each column. +} +\description{ +This function creates a data.frame with columns for each horizon such that it can be +added to a data.list and used in a forecast model. +} +\examples{ + +# Data for example +D <- subset(Dbuilding, c("2010-12-15","2010-12-20")) + +# Generate the input +make_input(D$heatload, 1:4) + +# Set is in D, such that it can be used in input expressions (e.g. by model$add_inputs(AR = "Ar0") +D$AR0 <- make_input(D$heatload, 1:36) + +} diff --git a/man/make_periodic.Rd b/man/make_periodic.Rd new file mode 100644 index 0000000..73dfb17 --- /dev/null +++ b/man/make_periodic.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/make_periodic.R +\name{make_periodic} +\alias{make_periodic} +\title{Make an forecast matrix with a periodic time signal.} +\usage{ +make_periodic(time, kseq, period, offset = 0, tstep = NA) +} +\arguments{ +\item{time}{vector of times of class "POSIXct" "POSIXt".} + +\item{kseq}{vector of integers, representing the desired "k-steps ahead".} + +\item{period}{a numeric setting the length of the period in seconds.} + +\item{offset}{a numeric setting an offset in the period start in seconds.} + +\item{tstep}{step time of k in seconds.} +} +\value{ +Returns a forecast matrix (data.frame) with rownames = times, colnames = k1, k2, k3, ... +The content of the data frame is the hour of day. +} +\description{ +This function creates a data.frame with k-steps-ahead values of a periodic time signal, +such that it can be added to a data.list and used inputs to a forecast model. +} +\examples{ +# Create a time sequence of 30 min sample period +tseq <- seq(ct("2019-01-01"), ct("2019-02-01 12:00"), by=1800) + +# Make the three hourly periodic sequence +make_periodic(tseq, 1:10, 3*3600) + +# With an offset of one hour +make_periodic(tseq, 1:10, 3*3600, 3600) + +} +\seealso{ +make_tday +} +\keyword{data.frame} +\keyword{lags} +\keyword{periodic} diff --git a/man/make_tday.Rd b/man/make_tday.Rd new file mode 100644 index 0000000..b3a9280 --- /dev/null +++ b/man/make_tday.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/make_tday.R +\name{make_tday} +\alias{make_tday} +\title{Make an hour-of-day forecast matrix} +\usage{ +make_tday(time, kseq, tstep = NA) +} +\arguments{ +\item{time}{vector of times of class "POSIXct" "POSIXt".} + +\item{kseq}{vector of integers, representing the desired "k-steps ahead".} + +\item{tstep}{step time of k in seconds.} +} +\value{ +Returns a forecast matrix (data.frame) with rownames = times, colnames = k1, k2, k3, ... +The content of the data frame is the hour of day. +} +\description{ +This function creates a data.frame with k-steps-ahead values of hour of day, +such that it can be added to a data.list and used inputs to a forecast model. +} +\examples{ +# Create a time sequence of 30 min sample period +tseq <- seq(ct("2019-01-01"), ct("2019-02-01 12:00"), by=1800) + +# Make the time of day sequence (assuming time between k steps is same as for tseq) +make_tday(tseq, 1:10) + +# With 0.5 hour steps, kstep in hours +make_tday(tseq, 1:10, tstep=3600) + + +} +\seealso{ +make_periodic +} +\keyword{data.frame} +\keyword{hourofday} +\keyword{lags} diff --git a/man/nams.Rd b/man/nams.Rd new file mode 100644 index 0000000..1827e0c --- /dev/null +++ b/man/nams.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/nams.R +\name{nams} +\alias{nams} +\alias{nams<-} +\title{Return the column names} +\usage{ +nams(x) + +nams(x) <- value +} +\arguments{ +\item{x}{The matrix or data.frame to set the column names for.} + +\item{value}{The names to be given.} +} +\description{ +Return the column names of a dataframe or a matrix. +} +\details{ +Simply to have a single function for returning the column names, instead of +\code{colnames()} for a \code{matrix} and \code{names()} for a \code{data.frame}). +} +\examples{ + +# Generate a matrix +X <- matrix(1, nrow=2, ncol=3) +colnames(X) <- c("c1","c2","c3") +D <- as.data.frame(X) + +# Annoyingly this fails (for a matrix) +\dontrun{names(X)} +# Could use this everywhere +colnames(D) +# but this is shorter +nams(X) +nams(D) + +# Also for assignment +nams(D) <- c("x1","x2","x3") +nams(D) + +} diff --git a/man/one.Rd b/man/one.Rd new file mode 100644 index 0000000..7963af4 --- /dev/null +++ b/man/one.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ones.R +\name{one} +\alias{one} +\title{Create ones for model input intercept} +\usage{ +one() +} +\value{ +A data.frame of ones +} +\description{ +Returns a data.frame of ones which can be used in forecast model inputs +} +\details{ +The function returns ones which can be used to generate ones, e.g. to be used as a intercept for a model. + +See vignettes 'setup-data' and 'setup-and-use-model'. +} +\examples{ + +# A model +model <- forecastmodel$new() +# Use the function in the input definition +model$add_inputs(mu = "one()") +# Set the forecast horizons +model$kseq <- 1:4 +# During the transformation stage the one will be generated for the horizons +model$transform_data(subset(Dbuilding, 1:7)) + +} diff --git a/man/onlineforecast.Rd b/man/onlineforecast.Rd new file mode 100644 index 0000000..cf53df4 --- /dev/null +++ b/man/onlineforecast.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/onlineforecast-package.R +\docType{package} +\name{onlineforecast} +\alias{onlineforecast} +\title{Functions for online forecasting} +\description{ +Functions for online forecasting +} +\details{ +This package provides functions to for setting up forecast models which run in an online setting, e.g. like demand, solar and wind power forecasts updated regularly - often hourly, and forecasts up to 48 hours ahead. + +See the website \url{https://onlineforecasting.org} for more information. +} diff --git a/man/pairs.data.list.Rd b/man/pairs.data.list.Rd new file mode 100644 index 0000000..6990e75 --- /dev/null +++ b/man/pairs.data.list.Rd @@ -0,0 +1,65 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{pairs.data.list} +\alias{pairs.data.list} +\title{Generation of pairs plot for a data.list.} +\usage{ +\method{pairs}{data.list}( + x, + subset = NA, + nms = NA, + kseq = NA, + lagforecasts = TRUE, + pattern = NA, + lower.panel = NULL, + panel = panel.smooth, + pch = 20, + cex = 0.7, + ... +) +} +\arguments{ +\item{x}{The data.list from which to plot.} + +\item{subset}{The subset to be included. Passed to \code{\link{subset.data.list}()}.} + +\item{nms}{The names of the variables to be included. Passed to \code{\link{subset.data.list}()}.} + +\item{kseq}{The horizons to be included. Passed to \code{\link{subset.data.list}()}.} + +\item{lagforecasts}{Lag the forecasts such that they are synced with obervations. Passed to \code{\link{subset.data.list}()}.} + +\item{pattern}{Regex pattern to select the included variables. Passed to \code{\link{subset.data.list}()}.} + +\item{lower.panel}{Passed to \code{\link{pairs}()}.} + +\item{panel}{Passed to \code{\link{pairs}()}.} + +\item{pch}{Passed to \code{\link{pairs}()}.} + +\item{cex}{Passed to \code{\link{pairs}()}.} + +\item{...}{Passed to \code{\link{pairs}()}.} +} +\description{ +Generate a pairs plot for the vectors in the data.list. +} +\details{ +A very useful plot for checking what is in the forecasts, how they are synced and match the observations. +} +\examples{ +# Take a subset for the example +D <- subset(Dbuilding, c("2010-12-15","2011-01-15"), pattern="^Ta|^I", kseq=1:3) +pairs(D) + +# If the forecasts and the observations are not aligned in time, +# which is easy to see by comparing to the previous plot. +pairs(D, lagforecasts=FALSE) +# Especially for the solar I syncronization is really important! +# Hence if the forecasts were not synced properly, then it can be detected using this type of plot. + +# Alternatively, lag when taking the subset +D <- subset(Dbuilding, c("2010-12-15","2011-01-15"), pattern="^Ta|^I", kseq=1:3, lagforecasts=TRUE) +pairs(D, lagforecasts=FALSE) + +} diff --git a/man/par_ts.Rd b/man/par_ts.Rd new file mode 100644 index 0000000..eb4f515 --- /dev/null +++ b/man/par_ts.Rd @@ -0,0 +1,94 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/par_ts.R +\name{par_ts} +\alias{par_ts} +\title{Set parameters for \code{\link{plot_ts}()}} +\usage{ +par_ts(fromoptions = FALSE, p = NA, ...) +} +\arguments{ +\item{fromoptions}{logical: Read the list of parameters set in \code{\link{options}("par_ts")$par_ts}, then the additional parameters set in \code{...} are replaced before the list is returned.} + +\item{p}{List of the parameters, as returned by the function itself. If given, the additional parameters set in \code{...} are replaced before the list is returned.} + +\item{...}{any of the following parameters can be set replacing the default values: + +\code{xnm} "t": The name of the time + +\code{legendspace} 10: +Horizontal space for the lengend in character spaces + +\code{legendcex} 1: Scaling of the legend + +\code{legendrangeshow} TRUE: Include the range for each variable in the legend + +\code{ylimextend} c(lower,upper): Extend the ylim for each plot with a proportion, seperately for the lower and upper limit + +\code{yaxisextend} c(lower,upper): Extend the yaxis for each plot with a proportion, seperately for the lower and upper limit + +\code{mainsline} (numeric): with the \code{line} for the main in the plots. + +\code{cex} (numeric): The cex to use for the \code{plot_ts} plots. + +\code{plotfun}: The function used for plotting, as default \code{lines}. + +\code{xaxisformat} (character): The format of the xaxis, see \code{\link{strptime}()}. + +\code{colorramp} colorRampPalette: The colorramp used for setting multiple colors in each plot} +} +\value{ +A list of the parameters above, which can be set globally (see examples) or passed to \code{\link{plot_ts}}. +} +\description{ +Set parameters for \code{\link{plot_ts}()} globally +} +\details{ +Often in a report some plot parameters must be set for all plots, which is done with \code{\link{par}()}. + +The parameters which are general for \code{\link{plot_ts}()} can be set and saved in \code{\link{options}()}, +and they will then be applied as default in all calls to plot_ts(). See the examples how to do this. + +If any of these parameters are given to \code{\link{plot_ts}()}, then it will be used over the default. +} +\examples{ + +# Data for plots +D <- subset(Dbuilding, 1:192) + +# See the parameters which can be set +p <- par_ts() +names(p) +p$xnm + +# Using the default values +plot_ts(D, c("heatload","Ta"), kseq=1:24) + +# Set the parameters directly +plot_ts(D, c("heatload","Ta"), kseq=1:24, legendcex=0.8, legendspace=8) + +# Set parameters to be given in a list +p <- par_ts() +p$legendcex <- 0.8 +p$legendspace <- 8 + +# Use those parameters +plot_ts(D, c("heatload","Ta"), kseq=1:24, p=p) + +# Set globally (if not set specifed the default values will be used) +options(par_ts=p) + +# Now the global parameters will be used +plot_ts(D, c("heatload","Ta"), kseq=1:24) + +# Still providing a parameter directly it will used, e.g. change the plotting function +plot_ts(D, c("heatload","Ta"), kseq=1:24, plotfun=points) + +# Control more precisely the plotting function +plot_ts(D, c("heatload","Ta"), kseq=1:24, plotfun=function(x, ...){ points(x, type="b", ...)}) + +# Another colorramp function +p$colorramp <- rainbow +options(par_ts=p) +plot_ts(D, c("heatload","Ta"), kseq=1:24) + +} diff --git a/man/pbspline.Rd b/man/pbspline.Rd new file mode 100644 index 0000000..3a35d3b --- /dev/null +++ b/man/pbspline.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bspline.R +\name{pbspline} +\alias{pbspline} +\title{Wrapper for \code{bspline} with \code{periodic=TRUE}} +\usage{ +pbspline( + X, + Boundary.knots = NA, + intercept = FALSE, + df = NULL, + knots = NULL, + degree = 3, + bknots = NA +) +} +\arguments{ +\item{X}{see \code{?bspline}} + +\item{Boundary.knots}{see \code{?bspline}} + +\item{intercept}{see \code{?bspline}} + +\item{df}{see \code{?bspline}} + +\item{knots}{see \code{?bspline}} + +\item{degree}{see \code{?bspline}} + +\item{bknots}{see \code{?bspline}} +} +\description{ +Wrapper for \code{bspline} with \code{periodic=TRUE} +} +\details{ +Simply a wrapper. +} +\seealso{ +Other Transform stage functions: +\code{\link{bspline}()} +} +\concept{Transform stage functions} diff --git a/man/persistence.Rd b/man/persistence.Rd new file mode 100644 index 0000000..d7c13d7 --- /dev/null +++ b/man/persistence.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/persistence.R +\name{persistence} +\alias{persistence} +\title{Generate persistence forecasts} +\usage{ +persistence(y, kseq, perlen = NA) +} +\arguments{ +\item{y}{(numeric) The model output to be forecasted.} + +\item{kseq}{(integer) The horizons to be forecasted.} + +\item{perlen}{(integer) The period length for seasonal persistence.} +} +\value{ +Forecast matrix as a \code{data.frame} (named \code{Yhat} in similar functions) +} +\description{ +Generate persistence and periodic persistence forecasts +} +\details{ +Generate a forecast matrix using persistence. The simple persistence is with the current value of y, i.e. the value at time t is used as forecast + +A seasonal persistence with a specific period can be generated by setting the argument \code{perlen} to the length of the period in steps. The value used for the forecast is then the latest available, which is matches the seasonality for time t+k, see the examples. +} +\examples{ + +# Simple persistence just copies the current value for the forecasts +persistence(1:10, kseq=1:4) + +# Seasonal persistence takes the value perlen steps back +persistence(1:10, kseq=1:4, perlen=4) + +# If the horizons are longer than perlen, then the perlen*i steps back is taken (i is an integer) +persistence(1:10, kseq=1:12, perlen=4) + + +} diff --git a/man/plot_ts.Rd b/man/plot_ts.Rd new file mode 100644 index 0000000..0aa2369 --- /dev/null +++ b/man/plot_ts.Rd @@ -0,0 +1,245 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plot_ts.R, R/plotly_ts.R +\name{plot_ts} +\alias{plot_ts} +\alias{plot_ts.data.list} +\alias{plot_ts.data.frame} +\alias{plot_ts.matrix} +\alias{plot_ts.rls_fit} +\alias{plotly_ts} +\title{Time series plotting} +\usage{ +plot_ts( + object, + patterns = ".*", + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = "", + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + plotit = TRUE, + p = NA, + ... +) + +\method{plot_ts}{data.list}( + object, + patterns = ".*", + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = "", + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + plotit = TRUE, + p = NA, + kseq = NA, + ... +) + +\method{plot_ts}{data.frame}( + object, + patterns = ".*", + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = NA, + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + plotit = TRUE, + p = NA, + namesdata = NA, + ... +) + +\method{plot_ts}{matrix}( + object, + patterns = ".*", + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = NA, + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + plotit = TRUE, + p = NA, + namesdata = NA, + ... +) + +\method{plot_ts}{rls_fit}( + object, + patterns = c("^y$|^Yhat$", "^Residuals$", "CumAbsResiduals$", pst("^", + names(fit$Lfitval[[1]]), "$")), + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = "", + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + plotit = TRUE, + p = NA, + kseq = NA, + ... +) + +plotly_ts( + object, + patterns = ".*", + xlim = NA, + ylims = NA, + xlab = "", + ylabs = NA, + mains = "", + mainouter = "", + legendtexts = NA, + colormaps = NA, + xat = NA, + usely = FALSE, + p = NA, + ... +) +} +\arguments{ +\item{object}{A \code{data.list} or \code{data.frame} with observations and forecasts, note diffe} + +\item{patterns}{See \code{\link{plot_ts}}. The default pattern finds the generated series in the function, '!!RLSinputs!!' will be replaced with the names of the RLS inputs (regression stage inputs).} + +\item{xlim}{The time range as a character of length 2 and form "YYYY-MM-DD" or POSIX. Date to start and end the plot.} + +\item{ylims}{The \code{ylim} for each plot given in a list.} + +\item{xlab}{A character with the label for the x-axis.} + +\item{ylabs}{A character vector with labels for the y-axes.} + +\item{mains}{A character vector with the main for each plot.} + +\item{mainouter}{A character with the main at the top of the plot (can also be added afterwards with \code{title(main, outer=TRUE)}).} + +\item{legendtexts}{A list with the legend texts for each plot (replaces the names of the variables).} + +\item{colormaps}{A list of colormaps, which will be used in each plot.} + +\item{xat}{POSIXt specifying where the ticks on x-axis should be put.} + +\item{usely}{If TRUE then plotly will be used.} + +\item{plotit}{If FALSE then the plot will not be generated, only data returned.} + +\item{p}{The plot_ts parameters in a list, as generated with the function \code{\link{par_ts}()}.} + +\item{...}{Parameters passed to \code{\link{par_ts}}, see the list of parameters in \code{?\link{par_ts}}.} + +\item{kseq}{For \code{class(object)=="data.list"} an integer vector, default = NA. Control which forecast horizons to include in the plots. If NA all the horizons will be included.} + +\item{namesdata}{For \code{class(object)=="data.frame"} a character vector. Names of columns in object to be searched in, instead of \code{names(object)}.} + +\item{fit}{An \code{rls_fit}.} +} +\value{ +A list with a data.frame with the data for each plot, if usely=TRUE, then a list of the figures (drawn with print(subplot(L, shareX=TRUE, nrows=length(L), titleY = TRUE))). + +The plotted data in a \code{data.list}. +} +\description{ +Plot time series of observations and forecasts (lagged to be aligned in time). + +Plot forecasts, residuals, cumulated residuals and RLS coefficients + +Simply the same as \code{\link{plot_ts}()} with \code{usely=TRUE}, such that plotly is used. +} +\details{ +Generates time series plots depending on the variables matched by each regular expression given in the \code{patterns} argument. + +The forecasts matrices in the \code{data.list} given in \code{object} will be lagged to be aligned in time (i.e. k-step forecasts will be lagged by k). + +Use the plotly package if argument \code{usely} is TRUE, see \code{\link{plotly_ts}()}. + +A useful plot for residual analysis and model validation of an RLS fitted forecast model. + +All parameters, except those described below, are simply passed to \code{\link{plot_ts}()}. + +The \code{plotly} package must be installed and loaded. + +Note that the plot parameters set with \code{\link{par_ts}()} have no effect on the \code{plotly} plots. + +See \url{https://onlineforecasting.org/vignettes/nice-tricks.html}. +} +\examples{ + +# Time series plots for \code{data.list}, same as for \code{data.frame} except use of \code{kseq} +D <- Dbuilding +plot_ts(D, c("heatload","Ta"), kseq=c(1,24)) +# Make two plots (and set the space for the legend) +plot_ts(D, c("heatload","Ta"), kseq=c(1,24), legendspace=11) +# Only the Ta observations +plot_ts(D, c("heatload","Taobs$"), kseq=c(1,24), legendspace=11) + +# Give labels +plot_ts(D, c("heatload","Ta"), kseq=c(1,24), xlab="Time", ylabs=c("Heat (kW)","Temperature (C)")) +# Mains (see mainsline in par_ts()) +plot_ts(D, c("heatload","Ta"), kseq=c(1,24), mains=c("Heatload","Temperature"), mainsline=c(-1,-2)) + +# Format of the xaxis (see par_ts()) +plot_ts(D, c("heatload","Ta"), kseq=c(1,24), xaxisformat="\%Y-\%m-\%d \%H:\%m") + +# Return the data, for other plots etc. +L <- plot_ts(D, c("heatload","Ta"), kseq=c(1,24)) +names(L[[1]]) +names(L[[2]]) + + + +# Fit a model (see vignette 'setup-and-use-model' +D <- Dbuilding +D$scoreperiod <- in_range("2010-12-22", D$t) +model <- forecastmodel$new() +model$output = "heatload" +model$add_inputs(Ta = "Ta", + mu = "one()") +model$add_regprm("rls_prm(lambda=0.9)") +model$kseq <- c(3,18) +fit1 <- rls_fit(NA, model, D, returnanalysis = TRUE) + +# Plot it +plot_ts(fit1) + +# Return the data +Dplot <- plot_ts(fit1) + +# The RLS coefficients are now in a nice format +head(Dplot$mu) + + +# See the website link above + +} +\seealso{ +\code{\link{par_ts}} for setting plot control parameters. + +\code{\link{regex}} for regular expressions to select which variables to plot. + +\code{\link{plot_ts}}. +} diff --git a/man/print.forecastmodel.Rd b/man/print.forecastmodel.Rd new file mode 100644 index 0000000..2e4b813 --- /dev/null +++ b/man/print.forecastmodel.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/forecastmodel.R +\name{print.forecastmodel} +\alias{print.forecastmodel} +\title{Print forecast model} +\usage{ +\method{print}{forecastmodel}(x, ...) +} +\arguments{ +\item{x}{A forecastmodel object} + +\item{...}{Not used.} +} +\description{ +Prints a forecast model +} +\details{ +A simple print out of the model output and inputs +} diff --git a/man/print_to_message.Rd b/man/print_to_message.Rd new file mode 100644 index 0000000..8ac0089 --- /dev/null +++ b/man/print_to_message.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/print_to_message.R +\name{print_to_message} +\alias{print_to_message} +\title{Simple function for capturing from the print function and send it in a message().} +\usage{ +print_to_message(...) +} +\arguments{ +\item{...}{Passed to print which passed to message.} +} +\description{ +Simple function for capturing from the print function and send it in a message(). +} diff --git a/man/pst.Rd b/man/pst.Rd new file mode 100644 index 0000000..ed9d42c --- /dev/null +++ b/man/pst.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/pst.R +\name{pst} +\alias{pst} +\title{Simple wrapper for paste0().} +\usage{ +pst(...) +} +\arguments{ +\item{...}{Passed to paste0().} +} +\description{ +Simple wrapper for paste0(). +} diff --git a/man/resample.Rd b/man/resample.Rd new file mode 100644 index 0000000..857abbd --- /dev/null +++ b/man/resample.Rd @@ -0,0 +1,76 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/resample.R +\name{resample} +\alias{resample} +\title{Resampling to equidistant time series} +\usage{ +resample( + object, + ts, + tstart = NA, + tend = NA, + timename = "t", + fun = mean, + quantizetime = TRUE, + ... +) +} +\arguments{ +\item{object}{Can be data.frame} + +\item{ts}{(numeric) New sample period in seconds} + +\item{tstart}{A POSIXxx (or charater or numeric), which indicates the first time point in the series returned} + +\item{tend}{A POSIXxx (or charater or numeric), which indicates the last time point in the series returned} + +\item{timename}{(character) The name of the time column in object} + +\item{fun}{(function) The function of apply. Default is mean, such that average values are obtained} + +\item{quantizetime}{(logical) Should the new time points be set to the end of the time intervals, or should they also be the result of the fun function} + +\item{...}{Passed on to the fun function} +} +\value{ +A downsampled data.frame +} +\description{ +Make a downsampling to a lower sampling frequency +} +\details{ +Given an object with a column indicating the time points of the observations the +function returns a similar object, where the function is applied for each new (and longer) +interval. + +Typically it is used if for example 15 minute values should be made into 1 hour values. + +NOTE that it is always assumed that the time point is at the end of the time interval, +e.g. if hourly values are returned, then "2019-01-01 01:00" indicates the first hour in 2019. + +All time points at the time point (border) of between two intervals is assigned to the +first interval of the two. +} +\examples{ + +# Generate some test data with 10 minutes sampling frequency for one day +X <- data.frame(t=seq(ct("2019-01-01 00:10"),ct("2019-01-02"), by=10*60)) + +# A single sine over the day +X$val <- sin(as.numeric(X$t)/3600*2*pi/(24)) + +# Resample to hourly average values +Xre <- resample(X, 3600) +plot(X$t, X$val) +lines(Xre$t, Xre$val, type="b", col=2) + +# Resample to hourly max values +Xre <- resample(X, 3600, fun=max) +lines(Xre$t, Xre$val, type="b", col=3) + +# Another starting time point +Xre <- resample(X, 3600, tstart="2019-01-01 00:30") +lines(Xre$t, Xre$val, type="b", col=4) + + +} diff --git a/man/residuals.Rd b/man/residuals.Rd new file mode 100644 index 0000000..5d6512e --- /dev/null +++ b/man/residuals.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/residuals.R +\name{residuals.data.frame} +\alias{residuals.data.frame} +\alias{residuals.matrix} +\alias{residuals.list} +\alias{residuals.forecastmodel_fit} +\title{Calculate the residuals given a forecast matrix and the observations.} +\usage{ +\method{residuals}{data.frame}(object, y, ...) + +\method{residuals}{matrix}(object, y, ...) + +\method{residuals}{list}(object, y, ...) + +\method{residuals}{forecastmodel_fit}(object, ...) +} +\arguments{ +\item{object}{The forecast matrix (a data.frame with kxx as column names, Yhat in returned fits).} + +\item{y}{The observations vector.} + +\item{...}{Not used.} +} +\value{ +If object is a matrix or data.frame: a data.frame with the residuals for each horizon. +If object is a list: A list with residuals from each element. +} +\description{ +Calculate the residuals given a forecast matrix and the observations. +} +\details{ +Simply give the forecast matrix and the observations to get the residuals for each horizon in the forecast matrix. + +The residuals returned are synced with the observations (i.e. k0) and the columns are names "hxx" (not kxx) to indicate this and will not be lagged in \code{\link{plot_ts}()}. +} +\examples{ +# ?? list example +# Just a vector to be forecasted +n <- 100 +D <- data.list() +D$t <- 1:n +D$y <- c(filter(rnorm(n), 0.95, "recursive")) +plot(D$y, type="l") + +# Generate a forecast matrix with a simple persistence model +D$Yhat <- persistence(D$y, kseq=1:4) + +# The residuals for each horizon +D$Resid <- residuals(D$Yhat, D$y) +D$Resid +# Note the names of the columns +names(D$Resid) +# which means that they are aligned with the observations and will not be lagged in the plot +plot_ts(D, c("y|Yhat","Resid")) + +# Check that it matches (the forecasts is lagged in the plot_ts +# such that the forecast for t+k is at t+k (and not t)) +plot_ts(D, c("y|Yhat","Resid"), xlim=c(1,10), kseq=1, + plotfun=function(x,...){lines(x,...,type="b")}) + +# Just for fun, see the auto-correlation function of the persistence +acf(D$Resid$h1, na.action=na.pass) +acf(D$Resid$h4, na.action=na.pass) + +} diff --git a/man/rls_fit.Rd b/man/rls_fit.Rd new file mode 100644 index 0000000..eed3348 --- /dev/null +++ b/man/rls_fit.Rd @@ -0,0 +1,136 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_fit.R +\name{rls_fit} +\alias{rls_fit} +\title{Fit an onlineforecast model with Recursive Least Squares (RLS).} +\usage{ +rls_fit( + prm = NA, + model, + data, + scorefun = NA, + returnanalysis = TRUE, + runcpp = TRUE, + printout = TRUE +) +} +\arguments{ +\item{prm}{vector with the parameters for fitting. Deliberately as the first element to be able to use \code{\link{optim}} or other optimizer. If NA then the model will be fitted with the current values in the input expressions, see examples.} + +\item{model}{as an object of class forecastmodel: The model to be fitted.} + +\item{data}{as a data.list with the data to fit the model on.} + +\item{scorefun}{as a function (optional), default is \code{\link{rmse}}. If the score function is given it will be applied to the residuals of each horizon (only data$scoreperiod is included).} + +\item{returnanalysis}{as a logical. If FALSE then the sum of the scoreval on all horizons are returned, if TRUE a list with values for analysis.} + +\item{runcpp}{logical: If true the c++ implementation of RLS is run, if false the R implementation is run (slower).} + +\item{printout}{logical: If TRUE the offline parameters and the score function value are printed.} +} +\value{ +Depends on: + + - If \code{returnanalysis} is TRUE a list containing: + + * \code{Yhat}: data.frame with forecasts for \code{model$kseq} horizons. + + * \code{model}: The forecastmodel object cloned deep, so can be modified without changing the original object. + + * \code{data}: data.list with the data used, see examples on how to obtain the transformed data. + + * \code{Lfitval}: list with RLS coefficients in a data.frame for each horizon, use \code{\link{plot_ts.rls_fit}} to plot them and to obtain them as a data.frame for each coefficient. + + * \code{scoreval}: data.frame with the scorefun result on each horizon (only scoreperiod is included). + + - If \code{returnanalysis} is FALSE (and \code{scorefun} is given): The sum of the score function on all horizons (specified with model$kseq). +} +\description{ +This function fits the onlineforecast model to the data and returns either: model validation data or just the score value. +} +\details{ +This function has three main purposes (in the examples these three are demonstrated in the examples): + +- Returning model validation data, such as residuals and recursive estimated parameters. + +- For optimizing the parameters using an R optimizer function. The parameters to optimize for is given in \code{prm} + +- Fitting a model to data and saving the final state in the model object (such that from that point the model can be updated recursively as new data is received). + +Note, if the \code{scorefun} is given the \code{data$scoreperiod} must be set to (int or logical) define which points to be evaluated in the scorefun. +} +\examples{ + + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a simple model +model <- forecastmodel$new() +model$output <- "y" +model$add_inputs(Ta = "Ta", + mu = "one()") +model$add_regprm("rls_prm(lambda=0.99)") + +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 + +# Now we can fit the model with RLS and get the model validation analysis data +fit <- rls_fit(model = model, data = D) +# What did we get back? +names(fit) +# The one-step forecast +plot(D$y, type="l") +lines(fit$Yhat$k1, col=2) +# The one-step RLS coefficients over time (Lfitval is a list of the fits for each horizon) +plot(fit$Lfitval$k1$Ta, type="l") + +# A summary +summary(fit) +# Plot the fit +plot_ts(fit, kseq=1) + +# Fitting with lower lambda makes the RLS coefficients change faster +fit2 <- rls_fit(prm = c(lambda=0.9), model, D) +plot_ts(fit2, kseq=1) + + +# It can return a score +rls_fit(c(lambda=0.9), model, D, scorefun=rmse, returnanalysis=FALSE) + +# Such that it can be passed to an optimzer (see ?rls_optim for a nice wrapper of optim) +val <- optim(c(lambda=0.99), rls_fit, model = model, data = D, scorefun = rmse, + returnanalysis=FALSE) +val$par +# Which can then simply be applied +rls_fit(val$par, model, D, scorefun=rmse, returnanalysis=FALSE) +# see ?rls_optim, how optim is wrapped for a little easiere use + +# See rmse as a function of horizon +fit <- rls_fit(val$par, model, D, scorefun = rmse) +plot(fit$scoreval, xlab="Horizon k", ylab="RMSE") +# See ?score for a little more consistent way of calculating this + + +# Try adding a low-pass filter to Ta +model$add_inputs(Ta = "lp(Ta, a1=0.92)") +# To obtain the transformed data, i.e. the data which is used as input to the RLS +model$reset_state() +# Generate the the transformed data +datatr <- model$transform_data(D) +# What did we get? +str(datatr) +# See the effect of low-pass filtering +plot(D$Ta$k1, type="l") +lines(datatr$Ta$k1, col=2) +# Try changing the 'a1' coefficient and rerun +# ?rls_optim for how to optimize also this coefficient + + +} +\seealso{ +For optimizing parameters \code{\link{rls_optim}()}, for summary \code{summary.rls_fit}, for plotting \code{\link{plot_ts.rls_fit}()}, and the other functions starting with 'rls_'. +} diff --git a/man/rls_optim.Rd b/man/rls_optim.Rd new file mode 100644 index 0000000..258dfa1 --- /dev/null +++ b/man/rls_optim.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_optim.R +\name{rls_optim} +\alias{rls_optim} +\title{Optimize parameters for onlineforecast model fitted with RLS} +\usage{ +rls_optim( + model, + data, + kseq = NA, + scorefun = rmse, + cachedir = "", + cachererun = FALSE, + printout = TRUE, + method = "L-BFGS-B", + ... +) +} +\arguments{ +\item{model}{The onlineforecast model, including inputs, output, kseq, p} + +\item{data}{The data.list which holds the data on which the model is fitted.} + +\item{kseq}{The horizons to fit for (if not set, then model$kseq is used)} + +\item{scorefun}{The function to be score used for calculating the score to be optimized.} + +\item{cachedir}{A character specifying the path (and prefix) of the cache file name. If set to \code{""}, then no cache will be loaded or written. See \url{https://onlineforecasting.org/vignettes/nice-tricks.html} for examples.} + +\item{cachererun}{A logical controlling whether to run the optimization even if the cache exists.} + +\item{printout}{A logical determining if the score function is printed out in each iteration of the optimization.} + +\item{method}{The method argument for \code{\link{optim}}.} + +\item{...}{Additional parameters to \code{\link{optim}}} +} +\value{ +Result object of optim(). +Parameters resulting from the optimization can be found from \code{result$par} +} +\description{ +Optimize parameters (transformation stage) of RLS model +} +\details{ +This is a wrapper for \code{\link{optim}} to enable easy use of bounds and caching in the optimization. + +One smart trick, is to cache the optimization results. Caching can be done by providing a path to the +\code{cachedir} argument (relative to the current working directory). +E.g. \code{rls_optim(model, D, cachedir="cache")} will write a file in the folder 'cache', such that +next time the same call is carried out, then the file is read instead of running the optimization again. +See the example in \url{https://onlineforecasting.org/vignettes/nice-tricks.html}. +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a simple model +model <- forecastmodel$new() +model$add_inputs(Ta = "Ta", mu = "one()") +model$add_regprm("rls_prm(lambda=0.99)") + +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 +# Now we can fit the model and get the score, as it is +rls_fit(model=model, data=D, scorefun=rmse, returnanalysis=FALSE) +# Or we can change the lambda +rls_fit(c(lambda=0.9), model, D, rmse, returnanalysis=FALSE) + +# This could be passed to optim() (or any optimizer, see forecastmodel$insert_prm()). +optim(c(lambda=0.98), rls_fit, model=model, data=D, scorefun=rmse, returnanalysis=FALSE, + lower=c(lambda=0.9), upper=c(lambda=0.999), method="L-BFGS-B") + +# rls_optim is simply a helper, it's makes using bounds easiere and enables caching of the results +# First add bounds for lambda (lower, init, upper) +model$add_prmbounds(lambda = c(0.9, 0.98, 0.999)) + +# Now the same optimization as above can be done by +val <- rls_optim(model, D) +val + + +} +\seealso{ +\code{link{optim}} for how to control the optimization. +} diff --git a/man/rls_predict.Rd b/man/rls_predict.Rd new file mode 100644 index 0000000..240a759 --- /dev/null +++ b/man/rls_predict.Rd @@ -0,0 +1,76 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_predict.R +\name{rls_predict} +\alias{rls_predict} +\title{Prediction with an rls model.} +\usage{ +rls_predict(model, datatr = NA) +} +\arguments{ +\item{model}{Onlineforecast model object which has been fitted.} + +\item{datatr}{Transformed data.} +} +\value{ +The Yhat forecast matrix with a forecast for each model$kseq and for each time point in \code{datatr$t}. +} +\description{ +Use a fitted forecast model to predict its output variable with transformed data. +} +\details{ +See the ??ref(recursive updating vignette, not yet available). +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +# Define a simple model +model <- forecastmodel$new() +model$add_inputs(Ta = "Ta", mu = "one()") +model$add_regprm("rls_prm(lambda=0.99)") + +# Before fitting the model, define which points to include in the evaluation of the score function +D$scoreperiod <- in_range("2010-12-20", D$t) +# And the sequence of horizons to fit for +model$kseq <- 1:6 + +# Transform using the mdoel +datatr <- model$transform_data(D) + +# See the transformed data +str(datatr) + +# The model has not been fitted +model$Lfits + +# To fit +rls_fit(model=model, data=D) + +# Now the fits for each horizon are there (the latest update) +# For example the current parameter estimates +model$Lfits$k1$theta + +# Use the current values for prediction +D$Yhat <- rls_predict(model, datatr) + +# Plot it +plot_ts(D, c("y|Yhat"), kseq=1) + +# Recursive updating and prediction +Dnew <- subset(Dbuilding, c("2011-01-01", "2011-01-02")) + +for(i in 1:length(Dnew$t)){ + # New data arrives + Dt <- subset(Dnew, i) + # Remember that the transformation must only be done once if some transformation + # which is has a state, e.g. lp(), is used + datatr <- model$transform_data(Dt) + # Update, remember that this must only be once for each new point + # (it updates the parameter estimates, i.e. model$Lfits) + rls_update(model, datatr, Dt$heatload) + # Now predict to generate the new forecast + print(rls_predict(model, datatr)) +} + +} diff --git a/man/rls_prm.Rd b/man/rls_prm.Rd new file mode 100644 index 0000000..06fbe50 --- /dev/null +++ b/man/rls_prm.Rd @@ -0,0 +1,52 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_prm.R +\name{rls_prm} +\alias{rls_prm} +\title{Function for generating the parameters for RLS regression} +\usage{ +rls_prm(lambda) +} +\arguments{ +\item{lambda}{The forgetting factor} +} +\value{ +A list of the parameters +} +\description{ +Function for generating the parameters for RLS regression +} +\details{ +The RLS needs only a forgetting factor parameter. +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +D$scoreperiod <- in_range("2010-12-20", D$t) +# Define a simple model +model <- forecastmodel$new() +model$add_inputs(Ta = "Ta", mu = "one()") +model$kseq <- 1:6 + +# Here the expression which sets the parameters is defined +model$add_regprm("rls_prm(lambda=0.99)") +model$regprmexpr + +# These will fit with lambda=0.99 +rls_fit(prm=NA, model, D) +rls_fit(prm=c(lambda=0.99), model, D) + +# The expression is evaluated when the model is fitted +rls_fit(prm=c(lambda=0.85), model, D) + +# What happens is simply that the expression was manipulated +model$regprmexpr +model$regprm + +# Same change could be done by +model$regprm <- list(lambda=0.3) +model$regprm +val <- rls_fit(prm=NA, model, D) + +} diff --git a/man/rls_summary.Rd b/man/rls_summary.Rd new file mode 100644 index 0000000..f8aa6b1 --- /dev/null +++ b/man/rls_summary.Rd @@ -0,0 +1,78 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_summary.R +\name{rls_summary} +\alias{rls_summary} +\title{Print summary of an onlineforecast model fitted with RLS} +\usage{ +rls_summary(object, scoreperiod = NA, scorefun = rmse, printit = TRUE, ...) +} +\arguments{ +\item{object}{of class \code{rls_fit}, so a fit calculated by \code{\link{rls_fit}}.} + +\item{scoreperiod}{logical (or index). If this scoreperiod is given, then it will be used over the one in the fit.} + +\item{scorefun}{The score function to be applied on each horizon.} + +\item{printit}{Print the result.} + +\item{...}{Not used.} +} +\value{ +A list of: + + - scorefun. + + - scoreval (value of the scorefun for each horizon). + + - scoreperiod is the scoreperiod used. +} +\description{ +The summary of an onlineforecast model fitted with RLS with simple stats providing a simple overview. +} +\details{ +The following is printed: + +* The model. + +* Number of observations included in the scoreperiod. + +* RLS coefficients summary statistics for the estimated coefficient time series (since observations are correlated, then usual statistics cannot be applied directly): + + - mean: the sample mean of the series. + + - sd: sample standard deviation of the series. + + - min: minimum of the series. + + - max: maximum of the series. + +* Scorefunction applied for each horizon, per default the RMSE. +} +\examples{ + +# Take data +D <- subset(Dbuilding, c("2010-12-15", "2011-01-01")) +D$y <- D$heatload +D$scoreperiod <- in_range("2010-12-20", D$t) +# Define a model +model <- forecastmodel$new() +model$add_inputs(Ta = "Ta", + mu = "one()") +model$add_regprm("rls_prm(lambda=0.99)") +model$kseq <- 1:6 +# Fit it +fit <- rls_fit(prm=c(lambda=0.99), model, D) + +# Print the summary +summary(fit) +# We see: +# - The model (output, inputs, lambda) +# - The Ta coefficient is around -0.12 in average (for all horizons) with a standard dev. of 0.03, +# so not varying extremely (between -0.18 and -0.027). +# - The intercept mu is around 5.5 and varying very little. +# - The RMSE is around 0.9 for all horizons. + +# The residuals and coefficient series can be seen by +plot_ts(fit) + +} diff --git a/man/rls_update.Rd b/man/rls_update.Rd new file mode 100644 index 0000000..613dfdf --- /dev/null +++ b/man/rls_update.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rls_update.R +\name{rls_update} +\alias{rls_update} +\title{Updates the model fits} +\usage{ +rls_update(model, datatr = NA, y = NA, runcpp = TRUE) +} +\arguments{ +\item{model}{A model object} + +\item{datatr}{a data.list with transformed data (from model$transform_data(D))} + +\item{y}{A vector of the model output for the corresponding time steps in \code{datatr}} + +\item{runcpp}{Optional, default = TRUE. If TRUE, a c++ implementation of the update is run, otherwise a slower R implementation is used.} +} +\value{ +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. +} +\description{ +Calculates the RLS update of the model coefficients with the provived data. +} +\details{ +See vignette ??ref(recursive updating, not yet finished) on how to use the function. +} +\examples{ + +# See rls_predict examples + +} +\seealso{ +See \code{\link{rls_predict}}. +} diff --git a/man/rls_update_cpp.Rd b/man/rls_update_cpp.Rd new file mode 100644 index 0000000..38b4978 --- /dev/null +++ b/man/rls_update_cpp.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{rls_update_cpp} +\alias{rls_update_cpp} +\title{Calculating k-step recursive least squares estimates} +\arguments{ +\item{y}{Vector of observation} + +\item{X}{Matrix of input variables (design matrix)} + +\item{theta}{Vector of parameters (initial value)} + +\item{P}{Covariance matrix (initial value)} + +\item{lambda}{Forgetting factor} + +\item{k}{Forecast horizon} + +\item{n}{Length of the input} + +\item{np}{Dimension of P (np x np)} + +\item{istart}{Start index} + +\item{kmax}{Keep only the last kmax rows for next time} +} +\description{ +This function applies the k-step recursive least squares scheme to estimate +parameters in a linear regression model. +} diff --git a/man/rmse.Rd b/man/rmse.Rd new file mode 100644 index 0000000..1fe836c --- /dev/null +++ b/man/rmse.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rmse.R +\name{rmse} +\alias{rmse} +\title{Computes the RMSE score.} +\usage{ +rmse(x) +} +\arguments{ +\item{x}{a numerical vector of residuals.} +} +\value{ +The RMSE score. +} +\description{ +Returns the RMSE. +} +\details{ +Used for forecast evaluation evaluation and optimization of parameters in model fitting. + +Note that \code{NA}s are ignored (i.e. \code{mean} is called with \code{na.rm=TRUE}). +} +\examples{ + + + # Just a vector to be forecasted + y <- c(filter(rnorm(100), 0.95, "recursive")) + # Generate a forecast matrix with a simple persistence model + Yhat <- persistence(y, kseq=1:4) + # The residuals for each horizon + Resid <- residuals(Yhat, y) + +# Calculate the score for the k1 horizon +rmse(Resid$h1) + +# For all horizons +apply(Resid, 2, rmse) + + +} +\seealso{ +\code{\link{score}()} for calculation of a score for the k'th horizon +} diff --git a/man/score.Rd b/man/score.Rd new file mode 100644 index 0000000..bfd2d7b --- /dev/null +++ b/man/score.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/score.R +\name{score} +\alias{score} +\alias{score.list} +\alias{score.data.frame} +\title{Calculate the score for each horizon.} +\usage{ +score(object, scoreperiod = NA, usecomplete = TRUE, scorefun = rmse, ...) + +\method{score}{list}(object, scoreperiod = NA, usecomplete = TRUE, scorefun = rmse, ...) + +\method{score}{data.frame}(object, scoreperiod = NA, usecomplete = TRUE, scorefun = rmse, ...) +} +\arguments{ +\item{object}{??list or A matrix with residuals (columns named \code{hxx}) for which to calculate the score for each horizon.} + +\item{scoreperiod}{as a logical vector controlling which points to be included in the score calculation. If NA then all values are included (depeding on 'complete').} + +\item{usecomplete}{TRUE then only the values available for all horizons are included (i.e. if at one time point there is a missing value, then values for this time point is removed for all horizons in the calculation).} + +\item{scorefun}{The score function.} + +\item{...}{is passed on to the score function.} +} +\value{ +A list with the a numeric vector with the score value for each horizon and the applied \code{scoreperiod} (note can be different from the given scoreperiod, if only complete observations are used (as per default)). +} +\description{ +Calculates the score for each horizon for a matrix with residuals for each horizon. +} +\details{ +Applies the \code{scorefun} on all horizons (each column) of the residuals matrix. See the description of each parameter for more details. +} +\examples{ + +# Just a vector to be forecasted +y <- c(filter(rnorm(100), 0.95, "recursive")) +# Generate a forecast matrix with a simple persistence model +Yhat <- persistence(y, kseq=1:4) +# The residuals for each horizon +Resid <- residuals(Yhat, y) + +# Calculate the score for the k1 horizon +score(Resid) + +# In the beginning the horizons have NAs +head(Resid) +# Default is that only complete cases over all horizons are included +score(Resid) +# So including all cases for each horizon will give different values +score(Resid, usecomplete=FALSE) + +# Given a list +# The residuals for each horizon +Resid2 <- residuals(persistence(y,kseq=1:4)+rnorm(100), y) + +score(list(Resid,Resid2)) +} diff --git a/man/setpar.Rd b/man/setpar.Rd new file mode 100644 index 0000000..bdbbca2 --- /dev/null +++ b/man/setpar.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/setpar.R +\name{setpar} +\alias{setpar} +\title{Setting \code{\link{par}()} plotting parameters} +\usage{ +setpar(tmpl = "ts", mfrow = c(1, 1), ...) +} +\arguments{ +\item{tmpl}{The name of the parameter template, give "ts" as default} + +\item{mfrow}{The mfrow for \code{par}.} + +\item{...}{More parameters for \code{par}.} +} +\value{ +Return the original set of parameters, such that they can be reset after plotting. +} +\description{ +Setting \code{\link{par}()} plotting parameters to a set of default values +} +\details{ +A simple function, which sets the \code{\link{par}()} plotting parameters to a default set of values. + +Actually, only really used for setting useful \code{par} values for multiple time series plots with same x-axis. +Give \code{tmpl="ts"} and \code{mfrow=c(x,1)}, where x is the number of plots. +} +\examples{ + +# Make some data +D <- data.frame(t=seq(ct("2020-01-01"),ct("2020-01-10"),len=100), x=rnorm(100), y=runif(100)) +# Remember the currect par values +oldpar <- setpar() + +# Generate two stacked plots with same x-axis +setpar("ts", mfrow=c(2,1)) +plot(D$t, D$x, type="l") +plot(D$t, D$y, type="l") +# Note xaxt="s" must be set +axis.POSIXct(1, D$t, xaxt="s", format="\%Y-\%m-\%d") + +# Set back the par to the previous +par(oldpar) + +# In a function, where this is used and a plot is generated, +# then do like this in order to automatically reset on exit +oldpar <- setpar(mfrow=c(2,1)) +on.exit(par(oldpar)) + +} diff --git a/man/stairs.Rd b/man/stairs.Rd new file mode 100644 index 0000000..0fa38d4 --- /dev/null +++ b/man/stairs.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/stairs.R +\name{stairs} +\alias{stairs} +\title{Plotting stairs with time point at end of interval.} +\usage{ +stairs(x, y, type = "b", preline = FALSE, pch = 19, ...) +} +\arguments{ +\item{x}{x values for plot.} + +\item{y}{y values for plot.} + +\item{type}{if 'b' then include points.} + +\item{preline}{if TRUE, then a line backwards from the first point is added.} + +\item{pch}{Passed to \code{points()}.} + +\item{...}{Passed to \code{lines()} and \code{points()} when they are called in the function.} +} +\description{ +Plotting steps with time point at end of interval +} +\details{ +It's easy to plot stairs with \code{plot(x,y,type="s")}, however that makes the steps forward from \code{x}, for time series this works if the time points are at the beginning of the intervals. + +Often with time series the time points are in the end of the intervals, so the steps should go backaward, this is achieved with this function. +} +\examples{ + +# Usual stairs plot has steps forward from x +x <- rnorm(10) +plot(1:10, x, type="s") + +# Stairs with step backward from x +plot(1:10, x, type="n") +stairs(1:10, x) + +# Use for time series plotting +plot_ts(Dbuilding, "heatload", c("2010-12-15","2010-12-16"), plotfun=stairs) + +# Set it globally for all plot_ts +p <- par_ts() +p$plotfun <- stairs +options(par_ts=p) +plot_ts(Dbuilding, "heatload", c("2010-12-15","2010-12-16")) + +# Modify it to only lines +plot_ts(Dbuilding, "heatload", c("2010-12-15","2010-12-16"), + plotfun=function(x,y,...){stairs(x,y, type="l")}) + +} diff --git a/man/state_getval.Rd b/man/state_getval.Rd new file mode 100644 index 0000000..cccdc87 --- /dev/null +++ b/man/state_getval.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/state_getval.R +\name{state_getval} +\alias{state_getval} +\title{Get the state value kept in last call.} +\usage{ +state_getval(initval) +} +\arguments{ +\item{initval}{If no state was kept, then this init value is returned.} +} +\value{ +The state value, but if not found, then the initval. +} +\description{ +Get the state value kept in last call to the transformation function. +} +\details{ +Transformation functions (e.g. \code{\link{lp}}, \code{\link{fs}}, \code{\link{bspline}}) can need to keep a state value between calls, e.g. when new data arrives and must be transformed. This function is used to getting the state values set in last call to the function. + +Uses the \code{input_class$state_getval()}. +} +\examples{ + +# See how it can be used in lp, which needs to save the state of the filter +# Note how it is not needed to do anything else than getting and setting the state +# in transformations (model$transform_data()), then multiple transformation functions can be called, +# but they are always in the same order, so the state (set,get) functions keep a counter internally +# to make sure that the correct values are set and returned when called again. +lp + + +} +\seealso{ +\code{\link{state_setval}()} for setting the state value and \code{\link{input_class}}. +} diff --git a/man/state_setval.Rd b/man/state_setval.Rd new file mode 100644 index 0000000..af1c4bd --- /dev/null +++ b/man/state_setval.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/state_setval.R +\name{state_setval} +\alias{state_setval} +\title{Set a state value to be kept for next the transformation function is called.} +\usage{ +state_setval(val) +} +\arguments{ +\item{val}{The value to set and kept for next call.} +} +\description{ +Set a state value to be kept for next the transformation function is called. +} +\details{ +Transformation functions (e.g. \code{\link{lp}}, \code{\link{fs}}, \code{\link{bspline}}) can need to keep a state value between calls, e.g. when new data arrives and must be transformed. This function is used to setting the state values set in last call to the function. + +Uses the \code{input_class$state_getval()}. +} +\examples{ + +# See how it can be used in lp, which needs to save the state of the filter +# Note how it is not needed to do anything else than getting and setting the state +# in transformations (model$transform_data()), then multiple transformation functions can be called, +# but they are always in the same order, so the state (set,get) functions keep a counter internally +# to make sure that the correct values are set and returned when called again. +lp + + +} +\seealso{ +\code{\link{state_setval}()} for setting the state value and \code{\link{input_class}}. +} diff --git a/man/step_optim.Rd b/man/step_optim.Rd new file mode 100644 index 0000000..a72de69 --- /dev/null +++ b/man/step_optim.Rd @@ -0,0 +1,201 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/step_optim.R +\name{step_optim} +\alias{step_optim} +\title{Forward and backward model selection} +\usage{ +step_optim( + modelfull, + data, + prm = list(NA), + kseq = NA, + direction = c("both", "backward", "forward", "backwardboth", "forwardboth"), + modelstart = NA, + keepinputs = FALSE, + optimfun = rls_optim, + fitfun = NA, + scorefun = rmse, + printout = FALSE, + mc.cores = getOption("mc.cores", 2L), + ... +) +} +\arguments{ +\item{modelfull}{The full forecastmodel containing all inputs which will be +can be included in the selection.} + +\item{data}{The data.list which holds the data on which the model is fitted.} + +\item{prm}{A list of integer parameters to be stepped. Given using the same +syntax as parameters for optimization, e.g. `list(I__degree = c(min=3, +max=7))` will step the "degree" for input "I".} + +\item{kseq}{The horizons to fit for (if not set, then model$kseq is used)} + +\item{direction}{The direction to be used in the selection process.} + +\item{modelstart}{A forecastmodel. If it's set then it will be used as the +selected model from the first step of the stepping. It should be a sub +model of the full model.} + +\item{keepinputs}{If TRUE no inputs can be removed in a step, if FALSE then +any input can be removed. If given as a character vector with names of +inputs, then they cannot be removed in any step.} + +\item{optimfun}{The function which will carry out the optimization in each +step.} + +\item{fitfun}{A fit function, should be the same as used in optimfun(). If +provided, then the score is caculated with this function (instead of the +one called in optimfun(), hence the default is rls_fit(), which is called +in rls_optim()). Furthermore, information on complete cases are printed +and returned.} + +\item{scorefun}{The score function used.} + +\item{mc.cores}{The mc.cores argument of mclapply. If debugging it can be +nessecary to set it to 1 to stop execution.} + +\item{...}{Additional arguments which will be passed on to optimfun. For +example control how many steps} +} +\value{ +A list with the result of each step: + - '$model' is the model selected in each step + - '$score' is the score for the model selected in each step + - '$optimresult' the result return by the the optimfun + - '$completecases' a logical vector (NA if fitfun argument is not given) indicating which time points were complete across all horizons and models for the particular step. +} +\description{ +Forward and backward model selection +} +\details{ +This function takes a model and carry out a model selection by stepping +backward, forward or in both directions. + +Note that mclapply is used. In order to control the number of cores to use, +then set it, e.g. to one core `options(mc.cores=1)`, which is needed for +debugging to work. + +The full model containing all inputs must be given. In each step new models +are generated, with either one removed input or one added input, and then all +the generated models are optimized and their scores compared. If any new +model have an improved score compared to the currently selected model, then +the new is selected and the process is repeated until no new improvement is +obtained. + +In addition to selecting inputs, then integer parameters can also be stepped +through, e.g. the order of basis splined or the number of harmonics in +Fourier series. + +The stepping process is different depending on the direction. In addition to +the full model, a starting model can be given, then the selection process +will start from that model. + +If the direction is "both", which is default (same as "backwardboth") then the +stepping is: + - In first step inputs are removed one-by-one + - In following steps, inputs still in the model are removed one-by-one, and + inputs not in the model are added one-by-one + +If the direction is "backwards": + - Inputs are only removed in each step + +If the direction is "forwardboth": + - In the first step all inputs are removed + - In following steps (same as "both") + +If the direction is "forward": +- In the first step all inputs are removed and from there inputs are only added + + +For stepping through integer variables in the transformation stage, then +these have to be set in the "prm" argument. The stepping process will follow +the input selection described above. + +In case of missing values, especially in combination with auto-regressive +models, it can be very important to make sure that only complete cases are +included when calculating the score. By providing the `fitfun` argument then +the score will be calculated using only the complete cases across horizons +and models in each step, see the last examples. +} +\examples{ + + +# The data, just a rather short period to keep running times short +D <- subset(Dbuilding, c("2010-12-15", "2011-02-01")) +# Set the score period +D$scoreperiod <- in_range("2010-12-22", D$t) +# +D$tday <- make_tday(D$t, 1:36) +# Generate an input which is just random noise, i.e. should be removed in the selection +set.seed(83792) +D$noise <- make_input(rnorm(length(D$t)), 1:36) + +# The full model +model <- forecastmodel$new() +# Set the model output +model$output = "heatload" +# Inputs (transformation step) +model$add_inputs(Ta = "Ta", + noise = "noise", + mu_tday = "fs(tday/24, nharmonics=5)", + mu = "one()") +# Regression step parameters +model$add_regprm("rls_prm(lambda=0.9)") +# Optimization bounds for parameters +model$add_prmbounds(lambda = c(0.9, 0.99, 0.9999)) + +# Select a model, in the optimization just run it for a single horizon +model$kseqopt <- 5 +# +prm <- list(mu_tday__nharmonics = c(min=3, max=7)) + +# Note the control argument, which is passed to optim, it's now set to few +# Iterations in the prm optimization (MUST be increased in real applications) +control <- list(maxit=1) + +# Run the default selection scheme, which is "both" (same as "backwardboth" if no start model is given) +L <- step_optim(model, D, prm, control=control) + +# The optim value from each step is returned +getse(L, "optimresult") +getse(L,"score") + +# The final model +L$final$model + +# Other selection schemes +Lforward <- step_optim(model, D, prm, "forward", control=control) +Lbackward <- step_optim(model, D, prm, "backward", control=control) +Lbackwardboth <- step_optim(model, D, prm, "backwardboth", control=control) +Lforwardboth <- step_optim(model, D, prm, "forwardboth", control=control, mc.cores=1) + +# It's possible avoid removing specified inputs +L <- step_optim(model, D, prm, keepinputs = c("mu","mu_tday"), control=control) + +# Give a starting model +modelstart <- model$clone_deep() +modelstart$inputs[2:3] <- NULL +L <- step_optim(model, D, prm, modelstart=modelstart, control=control) + +# If a fitting function is given, then it will be used for calculating the forecasts +# ONLY on the complete cases in each step +L1 <- step_optim(model, D, prm, fitfun=rls_fit, control=control) + +# The easiest way to conclude if missing values have an influence is to +# compare the selection result running with and without +L2 <- step_optim(model, D, prm, control=control) + +# Compare the selected models +tmp1 <- capture.output(getse(L1, "model")) +tmp2 <- capture.output(getse(L2, "model")) +identical(tmp1, tmp2) + + +# Note that caching can be really smart (the cache files are located in the +# cachedir folder (folder in current working directory, can be removed with +# unlink(foldername)) See e.g. `?rls_optim` for how the caching works +# L <- step_optim(model, D, prm, "forward", cachedir="cache", cachererun=FALSE) + +} diff --git a/man/subset.data.list.Rd b/man/subset.data.list.Rd new file mode 100644 index 0000000..9d7be66 --- /dev/null +++ b/man/subset.data.list.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.list.R +\name{subset.data.list} +\alias{subset.data.list} +\title{Take a subset of a data.list.} +\usage{ +\method{subset}{data.list}( + x, + subset = NA, + nms = NA, + kseq = NA, + lagforecasts = FALSE, + pattern = NA, + ... +) +} +\arguments{ +\item{x}{The data.list to take a subset of.} + +\item{subset}{Given as the integer indexes or a logical vector, or alternatively \code{c(tstart,tend)}, where tstart and tend are either as POSIX or characters.} + +\item{nms}{The names of the variables in \code{x} to be included.} + +\item{kseq}{The k horizons of forecasts to be included.} + +\item{lagforecasts}{Should the forecasts be lagged k steps (thus useful for plotting etc.).} + +\item{pattern}{Regex pattern applied to select the variables in x to be included.} + +\item{...}{Not implemented.} +} +\value{ +a data.list with the subset. +} +\description{ +Take a subset of a data.list. +} +\details{ +Different arguments can be given to select the subset. See the examples. +} +\examples{ +# Use the data.list with building heat load +D <- Dbuilding +# Take a subset for the example +D <- subset(D, 1:10, nms=c("t","Taobs","Ta","Iobs","I"), kseq=1:3) + +# Take subset index 2:4 +subset(D, 2:4) + +# Take subset for a period +subset(D, c("2010-12-15 02:00","2010-12-15 04:00")) + +# Cannot request a variable not there +try(subset(D, nms=c("x","Ta"))) + +# Take specific horizons +subset(D, nms=c("I","Ta"), kseq = 1:2) +subset(D, nms=c("I","Ta"), kseq = 1) + +# Lag the forecasts such that they are aligned in time with observations +subset(D, nms=c("Taobs","Ta"), kseq = 2:3, lagforecasts = TRUE) + +# The order follows the order in nms +subset(D, nms=c("Ta","I"), kseq = 2) + +# Return variables mathing a regex +subset(D, kseq=2, pattern="^I") + +# Take data for Ta and lag the forecasts (good for plotting and fitting a model) +X <- subset(Dbuilding, 1:1000, pattern="^Ta", kseq = 10, lagforecasts = TRUE) + +# A scatter plot between the forecast and the observations +# (try lagforecasts = FALSE and see the difference) +plot(X$Ta$k10, X$Taobs) + +# Fit a model for the 10-step horizon +abline(lm(Taobs ~ Ta.k10, X), col=2) + +} -- GitLab