Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OTHER] Question: AR coefficients, sklearn lags understanding #65

Open
lucheroni opened this issue Jul 24, 2021 · 13 comments · Fixed by #66
Open

[OTHER] Question: AR coefficients, sklearn lags understanding #65

lucheroni opened this issue Jul 24, 2021 · 13 comments · Fixed by #66
Assignees
Labels
documentation Improvements or additions to documentation question Further information is requested

Comments

@lucheroni
Copy link

Hello.

A very simple question.

Once I've estimated an autoregression as a wrapped linear model, say as

model_lr = get_sklearn_wrapper(LinearRegression, lags=10)
mlr = model_lr.fit(X[:-10], y[:-10])

how do I get the autoregression coefficients?

I cannot find the equivalent of scikit .coef_ , like

mlr = LinearRegression().fit(X, y)
mlr.coef_

Thanks.

@pavelkrizek
Copy link
Contributor

pavelkrizek commented Jul 24, 2021

Hello,

thanks for the question, I think that it's a good sign that we could extend some parts of the documentation which doesn't cover this.

All models have a model attribute which allows accessing the original estimator. In the case of sklearn the situation is a little bit more complicated because the actual fit happens only in the predict method (because the length of X passed to predict method is not known in the time of fitting). This is an implementation detail, but the fact is that you can access the coef_ only after calling predict method for get_sklearn_wrapper.

model_lr = get_sklearn_wrapper(LinearRegression, lags=10)
_ = model_lr.fit(X[:-10], y[:-10]).predict(X[-10:])
model_lr.model.coef_

@lucheroni
Copy link
Author

lucheroni commented Jul 25, 2021 via email

@MichalChromcak MichalChromcak added documentation Improvements or additions to documentation question Further information is requested labels Jul 26, 2021
@MichalChromcak
Copy link
Collaborator

Hi @lucheroni,

You are right, there should be x1, x2, x3, ... and later on x95, x96, x97 ; x96, x97, x98 etc. Thanks for spotting it.

And yes, in this case, y0, y1, y2 are passed as X to the LinearRegression and y3 as y. Or one could also formulate it relative to y as following:

  • X = y-3, y-2, y-1
  • y = y

@MichalChromcak
Copy link
Collaborator

@lucheroni, @pavelkrizek I updated the picture, but don't want to close it in case there are still some open questions. Can I close it as is? :)

@MichalChromcak MichalChromcak changed the title question: [OTHER] Question: AR coefficients, sklearn lags understanding Jul 26, 2021
@lucheroni
Copy link
Author

I asked because I'm trying to check the in-sample predictions,
and I'm getting a strange behavior.
In the following snippet I define an AR(2) model with two parameters only
(no constant),
hence I'm expecting to get the first in-sample forecast as y2 = f(y0,y1).
I get the following, which I don't understand:

ar_ord = 2
# horizon
hz = 1
# ten values
train = np.array([0.,1.,0.,1.,0.,1.,0.,1.,0.,1.])
y = train
date_index = pd.date_range(start="2020-01-01", periods=len(y), freq="h")
X = pd.DataFrame(index=date_index)
#
model_lry = get_sklearn_wrapper(LinearRegression, lags=ar_ord, fit_intercept=False)
mlry_preds = model_lry.fit(X[:-hz], y[:-hz])
model_lry.model.coef_ # array([0., 1.]) - two coeffs, ok
#
mlry_errs.predict(X[-1:]) # 1, 10th val - correct prediction
mlry_errs.predict(X[-2:]) # 1,0 shouldn't be 0,1?
mlry_errs.predict(X[-3:]) # 1,0,1
mlry_errs.predict(X[-4:]) # 1,0,1,0
mlry_errs.predict(X[-5:]) # 1,0,1,0,1 
mlry_errs.predict(X[-6:]) # 1,0,1,0,1,0 from 5th val on
mlry_errs.predict(X[-7:]) # ? 0,0,0,0,0,00 getting zeros only
'''

@ambader
Copy link

ambader commented Jul 26, 2021

It's all right, the formula to predict an AR(2) variable is:
xt=a1xt-1+a2xt-2

You might got confused as the x go back in time, therefore the array is 'reversed'.
Predicting the first variable of your last prediction:
x3 = a1x2 + a2x1
a1,a2 = [1.,0.]
1x0+0x1=0
and from then on, all predictions become 0.

used this code to show the differences:

for i in range(1,8):
    print("model_lry.predict(X[-"+str(i)+":])")
    print(model_lry.model.coef_)
    print(model_lry.predict(X[-i:]))

There you'll also see that the coefficients change. That is indeed another source of confusion as they are not labeled with the changing xt-1,xt-2. Hope that was what you wanted to understand.

@lucheroni
Copy link
Author

Thank you for the clarification.

My point is related exactly to what you embedded in the code.

It seems that the library re-fits the data each time one calls .predict(), and it does it in a different way each time. This is at least what I get when I run the code fragment above - changing coefficients.

Usually, on the contrary, once you have prepared your design matrix, you fit the model once and the coefficients will stay the same whatever you do with the model after fitting.
In facts, in statsmodels .predict() is called a postestimation method.

It seems to me that the library registers in the namespace a model_lry.model.coef_ only
after .predict(), and at that time it refits the model.

Am I wrong on that?

@ambader
Copy link

ambader commented Jul 30, 2021

Finally found the problem.
First thing to notice,
"Actual model fitting is done in predict method since the way model is fitted
depends on prediction horizon which is known only during predict call."
see:help(model_lry.fit)
Therefore, the wrapper fits new with every prediction, using the prediction target as horizon. But when I tried:
model_lry = get_sklearn_wrapper(LinearRegression, lags=ar_ord, fit_intercept=False,optimize_for_horizon=False)
the predicted coef were still altered. Digging in the code of wrappers/_sklearn.py finally revealed what I identify as the problem: When the prediction is called, is is tested for the bool of optimize_for_horizon, but at that point the _X for the fitting regression is already set - always with the len of predictionX as a horizon.
I forked the code I used to change it, hope that it is correct.

@pavelkrizek
Copy link
Contributor

@ambader Could you please supply an example that reproduces the problem you are facing? Thank you.

@ambader
Copy link

ambader commented Jul 30, 2021

It's still the same problem this whole thread is about:

ar_ord = 2
hz = 10
train_me = np.array([0.,1.,0.,1.,0.,1.,0.,1.,0.,1.])
train_me=np.tile(train_me,100)
y = train_me
date_index = pd.date_range(start="2020-01-01", periods=len(y), freq="d")
X = pd.DataFrame(index=date_index)

for i in range(1,8):
    model_lry = get_sklearn_wrapper(LinearRegression, lags=ar_ord, fit_intercept=False,optimize_for_horizon=False)
    print("model_lry.predict(X[-9:-"+str(i)+":])")
    model_lry.fit(X[:-11],y[:-11])
    print(model_lry.predict(X[-9:-i]))
    print(model_lry.model.coef_)

@pavelkrizek
Copy link
Contributor

pavelkrizek commented Jul 30, 2021

Ok, this behavior is expected by the implementation as the model is a function of training data which are defined by the horizon. There are also other ways how to implement the regressor as a time series forecaster, each with its advantages and drawbacks. PRs for new implementations are welcomed :)

We had also initially horizon being explicitly passed to the get_sklearn_wrapper, so the behavior was more understandable and deterministic, but this made its usage less flexible and add additional complexity (i.e. what to do when the X passed to predict doesn't have the same length as provided horizon...)

@lucheroni
Copy link
Author

lucheroni commented Jul 30, 2021 via email

@ambader
Copy link

ambader commented Jul 30, 2021

I understand why the horizon is set by default, but if I explicitly try to change it, it should not just ignore it without any comment. And if that behavior is intended, why does predict checks for optimize_for_horizon but not _predict ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants