0

I built a model using ucm function. However when i try to forecast for future, it's not letting me pass the independent variables.

library("rucm")
library("lubridate")

#Create Simulated Data
Date<- as.Date(seq(from=as.Date('2012-01-01'),to=as.Date('2014-03-31'),by=1),"%Y-%m-%d")
Actual <- sample(27:65,length(Date),replace = TRUE)
DOW <- wday(Date)
Month <- month(Date)
DOM <- mday(Date)
Week <- week(Date)
Ya <- year(Date)
Ya <- ifelse(Ya=="2014",2,1)
a <- data.frame(Date,Actual,DOW,Month,DOM,Week,Ya)
a$Date<-as.Date(a$Date,"%Y-%m-%d")

abc <- cbind(Weekday=model.matrix(~as.factor(a$DOW)),
             Mont=model.matrix(~as.factor(a$Month)),
             Day=model.matrix(~as.factor(a$DOM)),a[,7,drop=FALSE],
             Weekofyear=model.matrix(~as.factor(a$Week)))

abc<-data.frame(abc)

abc<-data.frame(abc[,c(-1,-8,-20,-52)])

abc2 <- subset(abc,abc$Ya==1)
abc2 <- abc2[,-48]
abc3 <- subset(abc,abc$Ya==2)
abc3 <- abc3[,-48]

#train and insample MAPE
a1<-subset(a,a$Ya==1)
a2<-subset(a,a$Ya==2)
#build model
dat <- as.data.frame(cbind(a1[,2,drop=FALSE], abc2))
fo <- as.formula(paste("Actual ~ ", paste(names(dat)[2:42], collapse= "+")))
fit_train_ucm <- ucm(fo, data = dat, cycle = TRUE, cycle.period = 365)

#predict for future
predict(fit_train_ucm,n.ahead = 90,newdata = abc3)

i am getting this error

Error in is.SSModel(newdata, na.check = TRUE, return.logical = FALSE) : 
  Object is not of class 'SSModel'

Update: Based on suggestion by package author from GitHub, i used below code(sorry to say this is not very self explanatory, i did however try to edit code)

SSModel(rep(NA,nrow(abc3)) ~ x + SSMtrend(2, Q = list(fit_train_ucm$est.var.level, fit_train_ucm$est.var.slope)) + SSMseasonal(12, Q = fit_train_ucm$est.var.season), H = fit_train_ucm$irr.var, data=abc3)

Now the error message is

Error in eval(expr, envir, enclos) : object 'x' not found

Any help on this?

StatguyUser
  • 2,595
  • 2
  • 22
  • 45
  • This is not reproducible. Please include some simulated data or one of the existing with-R-shipped datasets. – Roman Luštrik Feb 07 '16 at 16:43
  • @RomanLuštrik I just added some simulated data. Find the dropbox link https://www.dropbox.com/s/qw75hhfq63ugohu/SimulatedData.csv?dl=0 – StatguyUser Feb 08 '16 at 10:43
  • Please include the data in this post so that it doesn't get lost when you take it offline. – Roman Luštrik Feb 08 '16 at 11:06
  • Hi @RomanLuštrik I just added that detail. – StatguyUser Feb 08 '16 at 11:12
  • Please make your example reproducible and copy/pasteable. For some hints look at [this question](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). Currently I have to handle how I import the data, to what variable I save. Cut out the middle man, prepare the dataset for immediate work. – Roman Luštrik Feb 08 '16 at 11:29
  • @RomanLuštrik I just updated the code so that data frame will be created through code only. Thanks – StatguyUser Feb 15 '16 at 10:56

2 Answers2

1

This bug of prediction with newdata in ucm is yet to corrected.

This is how you can get predictions for an out-of-sample period.

indep <- paste(names(dat)[2:42], collapse= "+")
newdata1 <- SSModel(as.formula(paste0("rep(NA,nrow(abc3)) ~ ", indep, "+ SSMtrend(1, Q =  list(fit_train_ucm$est.var.level))",
               "+ SSMcycle(365, Q = fit_train_ucm$est.var.cycle)")), H = fit_train_ucm$irr.var, data=abc3)
pred<-predict(fit_train_ucm$model, newdata=newdata1)

So basically here I am using the predict function from KFAS package. To use the predict function, I have to define the data to be an object of class SSModel.

You will take all the parameters that you used in the model as independent variables and run a State space model with NA's as independent variable.

P.S.: I will keep the comments in mind to write a better answer next time.

KRC
  • 160
  • 7
  • 3
    Hello, could you please edit this answer to include the details of the workaround in the answer itself instead of requiring visitors to click through the link? That way the answer will still be useful to visitors even if the linked page is changed or removed. – josliber Feb 15 '16 at 16:40
  • 3
    Read this to further understand @josliber's concerns over the link [Are answers that just contain links elsewhere really "good answers"?](http://meta.stackexchange.com/a/8259) :-) – Bhargav Rao Feb 15 '16 at 16:42
  • 1
    @KRC In fact Github example is not easy to follow! i have posted all of my code including data in above code. can you please create an example of how to forecast future values for daily data? Thanks! – StatguyUser Feb 15 '16 at 17:38
  • 1
    I have edited the answer to show how you can use the predict function – KRC Feb 17 '16 at 07:13
  • Thank you very much!! UCM is a very useful function and thanks for building an R version of it – StatguyUser Feb 19 '16 at 02:05
1

Just so someone lands at this page again in future - there has been some update on the git repo maintained by the author to approach this problem in simplistic way. Please check this commit

Alternatively, pasting the function which one may use from that commit:

predict.ucm <- function(object, n.ahead, newdata,...){

  #### Predict in sample ####

  if (missing(newdata)) {
    return(predict(object = object$model, n.ahead = n.ahead))
  } 

  #### Predict out of sample ####

  # Regression variables.
  model_variables <- paste0(names(object$est), collapse = " + ")

  # Trend

  # Case 1 no trend
  if (is.null(object$est.var.level) & is.null(object$est.var.slope)) { 
    model_trend <- ""
  }
  # Case 2 level and trend
  if (!is.null(object$est.var.level) & !is.null(object$est.var.slope)) { 
    model_trend <- "+ SSMtrend(degree = 2, Q = list(object$est.var.level, object$est.var.slope))"
  }
  # Case 3 level only / trend only is not allowed in R
  if (!is.null(object$est.var.level) & is.null(object$est.var.slope)) { 
    model_trend <- "+ SSMtrend(degree = 1, Q = list(object$est.var.level))"
  }

  # Seasonality
  if (!is.null(object$est.var.season)) {
    model_season <- sprintf("+ SSMseasonal(period = %s, Q = object$est.var.season)", 
                            object$call['season.length'] %>% as.character())
  } else { 
    model_season <- ""
  }

  # Cycle
  if (!is.null(object$est.var.cycle)) {
    model_cycle <- sprintf("+ SSMcycle(period = %s, Q = object$est.var.cycle)", 
                           object$call['cycle.period'] %>% as.character())
  } else { 
    model_cycle <- ""
  }

  # Combine all components into a formula
  model_formula <- as.formula(sprintf("rep(NA,nrow(newdata)) ~ %s %s %s %s",
                                      model_variables,
                                      model_trend,
                                      model_season,
                                      model_cycle
  ))

  # Build a SSM object for the prediction
  oos_data <- KFAS::SSModel(formula = model_formula, H = object$irr.var, data = newdata)

  # Return the predictions
  predict(object$model, newdata = oos_data)

}

EDIT
In case you are interested in predicting on a new data which is considered as for the same time period as the original model was built using, then following edit can be made in the above function. That new data should ideally include the same dependent variable values which was used to build the first model.

  # Using same dependent which was used initially to fit the estimates, instead of NA
  model_formula <- as.formula(paste0(
    object$model$terms[[2]],
    sprintf(
      " ~ %s %s %s %s",
      model_variables,
      model_trend,
      model_season,
      model_cycle
    )
  ))
  # Build a SSM object for the prediction
  oos_data <- KFAS::SSModel(formula = model_formula, H = object$irr.var, data = newdata)
  
  # Return the predictions for in sample only - hence removing newdata arg
  # predict(object$model, newdata = oos_data)
  predict(oos_data)

Vivek Atal
  • 468
  • 5
  • 11