fable icon indicating copy to clipboard operation
fable copied to clipboard

ARIMA will not produce a weekly forecast when week_start != 1

Open jrauser opened this issue 1 year ago • 5 comments

See reprex below. If week_start is set to 1 (the default) everything works as expected.

library(fable)
#> Loading required package: fabletools
library(tsibble)
#> 
#> Attaching package: 'tsibble'
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, union
dat<-tsibble(wk=make_yearweek(2023, 21:50, week_start=7), 
             x=rnorm(30,100,10),
             index=wk)
mable <- model(dat, ARIMA(x ~ pdq()))
fable <- mable %>% forecast(h=3)
#> Error in `mutate()`:
#> ℹ In argument: `ARIMA(x ~ pdq()) = (function (object, ...) ...`.
#> Caused by error in `vec_ptype2.yearweek.yearweek()`:
#> ! Can't combine <yearweek> with different `week_start`.
#> Backtrace:
#>      ▆
#>   1. ├─mable %>% forecast(h = 3)
#>   2. ├─generics::forecast(., h = 3)
#>   3. ├─fabletools:::forecast.mdl_df(., h = 3)
#>   4. │ └─dplyr::mutate_at(...)
#>   5. │   ├─dplyr::mutate(.tbl, !!!funs)
#>   6. │   └─dplyr:::mutate.data.frame(.tbl, !!!funs)
#>   7. │     └─dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
#>   8. │       ├─base::withCallingHandlers(...)
#>   9. │       └─dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
#>  10. │         └─mask$eval_all_mutate(quo)
#>  11. │           └─dplyr (local) eval()
#>  12. ├─generics (local) `<fn>`(...)
#>  13. └─fabletools:::forecast.lst_mdl(...)
#>  14.   └─fabletools:::mapply_maybe_parallel(...)
#>  15.     └─base::mapply(FUN = .f, ..., MoreArgs = MoreArgs, SIMPLIFY = SIMPLIFY)
#>  16.       ├─generics (local) `<fn>`(dots[[1L]][[1L]], dots[[2L]][[1L]], h = 3, point_forecast = `<named list>`)
#>  17.       └─fabletools:::forecast.mdl_ts(...)
#>  18.         ├─generics::forecast(...)
#>  19.         └─fable:::forecast.ARIMA(...)
#>  20.           └─vctrs:::`!=.vctrs_vctr`(...)
#>  21.             └─vctrs::vec_equal(e1, e2)
#>  22.               └─vctrs:::vec_cast_common_params(!!!args, .to = .ptype)
#>  23.                 └─vctrs:::vec_cast_common_opts(...)
#>  24.                   └─vctrs (local) `<fn>`()
#>  25.                     └─tsibble:::vec_ptype2.yearweek.yearweek(x = x, y = y, x_arg = x_arg, y_arg = y_arg, call = call)
#>  26.                       └─rlang::abort("Can't combine <yearweek> with different `week_start`.")
new_data <- tsibble(wk=make_yearweek(2023, 51:52, week_start=7), index=wk)
fable <- mable %>% forecast(new_data = new_data)
#> Error in `mutate()`:
#> ℹ In argument: `ARIMA(x ~ pdq()) = (function (object, ...) ...`.
#> Caused by error in `vec_ptype2.yearweek.yearweek()`:
#> ! Can't combine <yearweek> with different `week_start`.
#> Backtrace:
#>      ▆
#>   1. ├─mable %>% forecast(new_data = new_data)
#>   2. ├─generics::forecast(., new_data = new_data)
#>   3. ├─fabletools:::forecast.mdl_df(., new_data = new_data)
#>   4. │ └─dplyr::mutate_at(...)
#>   5. │   ├─dplyr::mutate(.tbl, !!!funs)
#>   6. │   └─dplyr:::mutate.data.frame(.tbl, !!!funs)
#>   7. │     └─dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
#>   8. │       ├─base::withCallingHandlers(...)
#>   9. │       └─dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
#>  10. │         └─mask$eval_all_mutate(quo)
#>  11. │           └─dplyr (local) eval()
#>  12. ├─generics (local) `<fn>`(...)
#>  13. └─fabletools:::forecast.lst_mdl(...)
#>  14.   └─fabletools:::mapply_maybe_parallel(...)
#>  15.     └─base::mapply(FUN = .f, ..., MoreArgs = MoreArgs, SIMPLIFY = SIMPLIFY)
#>  16.       ├─generics (local) `<fn>`(dots[[1L]][[1L]], dots[[2L]][[1L]], h = NULL, point_forecast = `<named list>`)
#>  17.       └─fabletools:::forecast.mdl_ts(...)
#>  18.         ├─generics::forecast(...)
#>  19.         └─fable:::forecast.ARIMA(...)
#>  20.           └─vctrs:::`!=.vctrs_vctr`(...)
#>  21.             └─vctrs::vec_equal(e1, e2)
#>  22.               └─vctrs:::vec_cast_common_params(!!!args, .to = .ptype)
#>  23.                 └─vctrs:::vec_cast_common_opts(...)
#>  24.                   └─vctrs (local) `<fn>`()
#>  25.                     └─tsibble:::vec_ptype2.yearweek.yearweek(x = x, y = y, x_arg = x_arg, y_arg = y_arg, call = call)
#>  26.                       └─rlang::abort("Can't combine <yearweek> with different `week_start`.")

jrauser avatar Jul 27 '23 00:07 jrauser

Possibly related? https://github.com/tidyverts/tsibble/issues/299

jrauser avatar Jul 27 '23 01:07 jrauser

I looked into this a little bit, and the problem comes when the arima model object is created. It has a $tsp which has a $range, where the week_start hasn't been propagated. So the problem appears to be in whatever happens inside range() when a vector of yearweeks are given.

library(fable)
#> Loading required package: fabletools
library(tsibble)
#> 
#> Attaching package: 'tsibble'
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, union
dat<-tsibble(wk=make_yearweek(2023, 21:50, week_start=7), 
             x=rnorm(30,100,10),
             index=wk)
dat$wk[1]
#> <yearweek[1]>
#> [1] "2023 W21"
#> # Week starts on: Sunday
range(dat$wk)
#> <yearweek[2]>
#> [1] "2023 W20" "2023 W49"
#> # Week starts on: Monday

jrauser avatar Jul 27 '23 17:07 jrauser

I think range just does something like c(min(dat$wk), max(dat$wk)), without propagating the attributes of the object.

The code that makes the range at L402 of arima.R needs to be aware of yearweek objects. The right thing might be to make a range() that knows how to operate properly on yearweeks.

jrauser avatar Jul 27 '23 17:07 jrauser

Putting this in my code appears to paper over the problem:

range.yearweek <- function(x, ...) {
  yearweek(c(min(x), max(x)), week_start=attr(x, "week_start"))
}

I don't know how to write that code properly or I'd submit a PR.

jrauser avatar Jul 27 '23 18:07 jrauser

Thanks for your careful investigation, resolving https://github.com/tidyverts/tsibble/issues/300 should fix this issue.

mitchelloharawild avatar Jul 28 '23 00:07 mitchelloharawild