5
$\begingroup$

I'd like to forecast (or predict) a time series with weights.

The following works using the regular linear modelling techniques of lm by applying a (sigmoidal) weight distribution to the input data, essentially weighing the latter data points more heavily than the former:

library("stats")
lm.weight.function <- function(x) {10 / (1 + exp(-x))} # Sigmoidal
lm.weights <- lapply(seq(-13, 14, length.out = 27), lm.weight.function)
lm.input <- as.data.frame(c(23957, 46771, 60767, 73284, 60296, 73122, 78304, 87154, 80459, 76885, 56479, 18809, 13453, 13951, 25140, 12035, 11920, 20683, 30357, 35019, 37732, 46150, 47856, 41931, 20985, 32526, 27283))
lm.input <- cbind(1:27, lm.input)
colnames(lm.input) <- c('x', 'y')
lm.model <- lm(formula = y ~ log(x), data = lm.input, weights = unlist(lm.weights))
predict.input <- as.data.frame(28:55)
colnames(predict.input) <- 'x'
predict.model <- predict(lm.model, predict.input)
plot(1:(27+28), c(lm.input$y, predict.model), type = 'l', xlab = 'x', ylab = 'y')

enter image description here

Now I wish to do the same using the forecast package. However, I'm having difficulty specifying the weights:

library("forecast")
ts.weight.function <- function(x) {10 / (1 + exp(-x))} # Sigmoidal
ts.weights <- as.data.frame(lapply(seq(-13, 14, length.out = 27), ts.weight.function))
colnames(ts.weights) <- 'trend'
ts.input <- ts(c(23957, 46771, 60767, 73284, 60296, 73122, 78304, 87154, 80459, 76885, 56479, 18809, 13453, 13951, 25140, 12035, 11920, 20683, 30357, 35019, 37732, 46150, 47856, 41931, 20985, 32526, 27283), frequency = 1)
ts.model <- tslm(formula = ts.input ~ log(trend), weights = unlist(ts.weights))

The above prints an error:

Error in eval(expr, envir, enclos) : 
  ..1 used in an incorrect context, no ... to look in

How can I use tslm to forecast a time series with weights?

$\endgroup$
  • $\begingroup$ Did you try traceback? That's an odd error, but what it seems like is that there's a function inside another function, the inside function is being passed the argument ..., but the function it's inside doesn't have a ... argument to pass. My guess is tslm is somehow calling the wrong thing, or is being told to call something that it doesn't expect to call. $\endgroup$ – shadowtalker Jul 3 '14 at 1:23
  • $\begingroup$ You get a similar error when you try something like bad = function(x) plot(...); bad(rnorm(5)) which throws Error in bad(rnorm(5)) : '...' used in an incorrect context. $\endgroup$ – shadowtalker Jul 3 '14 at 1:26
  • $\begingroup$ Super delayed, but check out these two articles for help: - developer.r-project.org/nonstandard-eval.pdf - developer.r-project.org/model-fitting-functions.html $\endgroup$ – Eric Aug 5 '16 at 19:39
  • $\begingroup$ Your idea (weight the later data points more heavily) is essentially exponential smoothing. Try the ets function in the forecast package— I've found that the function is very easy to use and often gives good results. $\endgroup$ – Zach Aug 5 '16 at 19:46
6
$\begingroup$

This is an issue with lm.

wrapper = function(formula,...)
  lm(formula=formula,...)
x=(1:27)
wrapper(ts.input~x,weights=ts.weights)

produces the exact same error. If you read the source code to tslm, you'll find that lm is called in more or less the sam way.

I found here that ..1 means the first argument included in ..., which in this case is the only argument, weights. It suggests that this kind of error could be caused because argument being passed doesn't exist in the environment from which the function is being called. You can see this behavior with wrapper(ts.input~x,weights=foo) if you don't have any object called foo.

Running a traceback on wrapper(ts.input~x,weights=ts.weights) reveals:

8 eval(expr, envir, enclos) 
7 eval(extras, data, env) 
6 model.frame.default(formula = formula, weights = ..1, drop.unused.levels = TRUE) 
5 stats::model.frame(formula = formula, weights = ..1, drop.unused.levels = TRUE) 
4 eval(expr, envir, enclos) 
3 eval(mf, parent.frame()) 
2 lm(formula = formula, ...) 
1 wrapper(ts.input ~ x, weights = ts.weights) 

And in the source code of lm,

mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data", "subset", "weights", "na.action", 
    "offset"), names(mf), 0L)
mf <- mf[c(1L, m)]
mf$drop.unused.levels <- TRUE
mf[[1L]] <- quote(stats::model.frame)
mf <- eval(mf, parent.frame())
if (method == "model.frame") 
    return(mf)

which suggests that the call to model.frame is picking up on the ... in a strange way.

So I decided to try it without ...:

wrapper = function(formula,weights)
  lm(formula=formula,weights=weights)
x=(1:27)
wrapper(ts.input~x,weights=ts.weights)

which produced

 Error in model.frame.default(formula = formula, weights = weights, drop.unused.levels = TRUE) : 

invalid type (closure) for variable '(weights)'

A closure, of course, is a function in R. Which can mean only one thing... weights is already a function in the global environment. Indeed, ?weights reveals that it's ironically the extractor function for model weights. It's a no-brainer that it gets search priority over local variables. So I changed the argument names (since formula is also a function):

wrapper = function(fm,ws){
  print(ws)
  lm(formula=fm,weights=ws)
}
x=(1:27)
wrapper(fm=ts.input~x,ws=ts.weights)

now produces

 [1] 2.260324e-05 6.385091e-05 1.803683e-04 5.094997e-04 1.439136e-03 4.064300e-03
 [7] 1.147260e-02 3.234087e-02 9.082267e-02 2.523791e-01 6.815483e-01 1.712317e+00
[13] 3.685455e+00 6.224593e+00 8.232410e+00 9.293615e+00 9.737984e+00 9.905650e+00
[19] 9.966395e+00 9.988078e+00 9.995776e+00 9.998504e+00 9.999471e+00 9.999813e+00
[25] 9.999934e+00 9.999977e+00 9.999992e+00

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

And if you run traceback you still get the same issue with model.frame. So I'm completely baffled. My only conclusion is that a) it has nothing to do with tslm or time series analysis, and b) the problem lies somewhere in the way arguments are passed around inside lm.

That probably doesn't help you at all, but hopefully at least someone can come along and explain what's going on here. My provisional answer to your actual question of how to use weights in tslm is that you can't.

$\endgroup$
  • $\begingroup$ +1 have the same problem in another package (CHAID).. how did you get this resolved? $\endgroup$ – Tagar Jul 2 '15 at 20:30
  • 1
    $\begingroup$ @Ruslan I never figured it out. You might want to post it on one of the R-help mailing lists since, again, it seems like a problem deep inside lm. $\endgroup$ – shadowtalker Jul 2 '15 at 20:31
  • $\begingroup$ My traceback shows problem function (x = NULL, max.lines = getOption("deparse.max.lines")) -- different from yours, but symptoms are exactly the same. Thanks $\endgroup$ – Tagar Jul 2 '15 at 20:38
  • $\begingroup$ I deleted weights parameter and it started working.. bummer. $\endgroup$ – Tagar Jul 2 '15 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.