robjhyndman / forecast

Forecasting Functions for Time Series and Linear Models
http://pkg.robjhyndman.com/forecast
1.12k stars 342 forks source link

error when h=1 with xreg #810

Closed YalanHu closed 5 years ago

YalanHu commented 5 years ago

in the arima.R line # 350 if (NCOL(xreg) != NCOL(object$call$xreg)) { stop("Number of regressors does not match fitted model") }

the above will not work when h=1 , as the xreg.test will become an array, and the NCOL will return 1 instead the number of columns as the train xreg.

fc <- forecast::forecast(model, h = 1, xreg = xreg.test) doesn't work

fc <- forecast::forecast(model, h = 1, xreg = t(xreg.test)) works

robjhyndman commented 5 years ago

I can't reproduce the problem. The following code works, for example.

library(forecast)
y <- rnorm(30)
x <- rnorm(30)
model <- Arima(y, order=c(1,0,0), xreg=x)

xreg.test <- 0
forecast(model, xreg=xreg.test)
#>    Point Forecast    Lo 80    Hi 80     Lo 95    Hi 95
#> 31    -0.07488821 -1.25107 1.101294 -1.873704 1.723927

xreg.test <- matrix(xreg.test, ncol=1)
forecast(model, xreg=xreg.test)
#>    Point Forecast    Lo 80    Hi 80     Lo 95    Hi 95
#> 31    -0.07488821 -1.25107 1.101294 -1.873704 1.723927

Created on 2019-08-03 by the reprex package (v0.3.0)

Please provide a reproducible example.

YalanHu commented 5 years ago
# my example use a dataset from TSstudio

library(TSstudio)
library(forecast)

# Load the series
data("USgas")

# Get the series info
ts_info(USgas)

x_reg <- forecast::fourier(USgas, K = 5)

ts.obj <- USgas
ts.subset <- split_ts <- train <- test <- NULL
i <- 200
window_size <- 1
ts.subset <- stats::window(ts.obj, start = stats::time(ts.obj)[1], end = stats::time(ts.obj)[i])
split_ts <- TSstudio::ts_split(ts.subset, sample.out = window_size)
train <- split_ts$train
test <- split_ts$test
a.xreg.train <- x_reg[1:length(train),]
a.xreg.test <- x_reg[(length(train) + 1):(length(train) + window_size),]
a.arg <- NULL
a.arg.xreg <- a.arg
a.arg.xreg$xreg <- a.xreg.train
md <- base::do.call(forecast::auto.arima, c(list(train), a.arg.xreg))
fc <- forecast::forecast(md, h = window_size, xreg = a.xreg.test)
fc <- forecast::forecast(md, h = window_size, xreg = t(a.xreg.test))
robjhyndman commented 5 years ago

This is not a bug. xreg must either be a numerical vector (if you have one covariate) or a matrix (if you have multiple covariates). Since you have multiple covariates, you need to pass it as matrix. Your t() function is doing that.

YalanHu commented 5 years ago

I understood, however, if you use as.matrix and not transpose then this will not work. so the problem is not about matrix. It due to the slicing behavior of R, slice only one Row of a matrix, its columns will become rows.

I agree it is not a bug, but to make it more transparent to user, is it possible to check the dimension inside the code? for example the window_size not equal to 1, it will not have problem. so from 1 to n shouldn't have sudden change.

robjhyndman commented 5 years ago

It will work with matrix(xreg, nrow=1). Or if you are extracting one row from a matrix, you can use xreg[1,, drop=FALSE]

Converting to a matrix when the length of the vector is the same as the number of expected columns seems a little dangerous. The user may have accidentally passed only the first column, and there is no way to know if they meant to provide the data as a row instead.

YalanHu commented 5 years ago

is it possible to use the colnames/names to match instead only based on the number of columns?

robjhyndman commented 5 years ago

Yes, it would be possible, but not something I want to do.

mitchelloharawild commented 5 years ago

Closing as there is a solution to the problem. For better handling of exogenous regressors I recommend looking into the fable package.