# Combinef in R HTS package- constrain to keep forecasts positive?

When using the combinef function from Rob Hyndman's very useful hts package for forecasting hierarchical and grouped time series, there does not seem to be a way to constrain the optimally combined forecasts to be positive- the starting forecasts can be positive, but can go negative through the reconciliation process.

The forecast.gts and forecast.hts functions have an argument to keep forecasts positive, but this does not seem to be an option when using combinef by itself with forecasts obtained by other methods.

Am I correct in this understanding, and if so is there a decent workaround?

The positive=TRUE argument for forecast.gts and forecast.hts ensures the starting forecasts to be positive, but not the final reconciled forecasts. Even when the starting forecasts are positive, it is possible for the reconciled forecasts to be negative. When you use combinef, you provide your own starting forecasts, so it is up to you to make them positive.

It would be possible to use a non-linear least squares reconciliation procedure to produce positively constrained reconciled forecasts, but that would be much slower.

• Thanks, Rob, for the clarification and suggestions. Do you think the non-linear least squares method could be an option in future versions of combinef, for users who want to keep forecasts positive after reconciliation? It seems like a fairly common use case, though I don't know what that would look like in terms of the way the rest of the code is structured. Jul 15, 2014 at 15:38
• I'm trying to think of a quicker way to do it. The plan is for "positive=TRUE" to apply to the reconciled forecasts, but it has to work on hierarchies involving a million or more time series. Jul 15, 2014 at 21:15
• Hi Rob - just checking in here. as I'm hitting negatives on the reconciliations. I see the latest version of hts::combinef still has no positive arg. If not implemented in hts itself, could you recommend a heuristic one could code themselves that approximates the result you'd seek with non-linear least squares? How bad would redistributing negatives proportionally to other series? Jun 27, 2016 at 18:31
• Set all the negatives to zero and reconcile what's left. Jun 28, 2016 at 6:53
• Hi Rob, Do you have sample code for non-linear least squares reconciliation to produce positively constrained reconciled forecasts? I tried combinef on M5 and majority of bottom level series turned out to be negative :) Mar 6, 2020 at 20:57

You can't ensure positivity and sum consistency of hierarchical forecasts if you use forecast::combinef().

What I personally found useful was to set up the summation matrix (see the original publication by Hyndman et al., 2011) and then solve the relevant (weighted) least squares problem with additional nonnegativity constraints. This will give you nonnegative and sum consistent forecasts. I have found repeatedly that this approach still results in better forecasts on all levels in the hierarchy.

This approach also allows including equality constraints, or constraints that are more general than just "$\geq 0$". I have had applications where some forecasts needed to be larger than a certain number (because of existing orders), or needed to be constrained to be equal to a given value, which you can model using two inequality constraints.

One possible tool that solves (weighted) least squares with linear constraints is the pcls() function in the mgcv package for R. (Note that this is slightly more general than your use case: mgcv::pcls() allows for linear constraints, but you and the use cases I outline in the previous paragraph only need box constraints.) However, this is of course also not optimized to leverage the specific structure of potential forecast hierarchy matrices, so your performance may be significantly worse than if you use combinef().

• Do you have sample code to achieve that? Thanks, Mar 6, 2020 at 20:52

Some code based on Rob's workaround of setting the negatives to zero and reconcile

# Re-reconciliate when zero values present

# Extract groups
groups <- hts.obj %>%
aggts() %>%
get_groups()

x=0 #Counter

# Loop until all positive
while(sum(hts.obj[[1]] <0) > 0){

# Generate all time series
hts.obj <- aggts(hts.obj)

# Overwrite negatives by zero
hts.obj[hts.obj<0] <- 0

# Reconcile
hts.obj <- hts.obj %>%
ts() %>%
combinef(groups = groups, keep ="gts")

# Count up
x=x+1

# Break after 10 loops
if(x>=10)break

}

rm("x")

# Overwrite remaining negatives by zero
hts.obj[[1]][hts.obj[[1]]<0] <- 0


In this example forecasts are indexed by [[1]] - this might change. Also note that overwriting zeros leads to biased forecasts.