-
-
Notifications
You must be signed in to change notification settings - Fork 25.8k
[MRG] Added check for idempotence of fit() #12328
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
Conversation
sklearn/utils/estimator_checks.py
Outdated
# Fit again | ||
est.fit(X_train, y_train) | ||
|
||
if hasattr(est, 'predict'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we consider resuscitating the concept of assert_same_model (#4841)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally yes...
I tried to do that by comparing the attributes ending with _
but ran into tons of edge cases, so I went with the prediction comparison, which is probably enough for this issue.
Basically the question is, is it really worth it? It's doable but there's no doubt the code is going to be a pain to maintain.
The code in #4841 ignores the comparison of some attributes, in particular the attributes that are themselves estimators (see here), and it's already pretty involved!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind it being approximate and efficient in most cases, rather than having the complexity of #4841... but it should be reusable, rather than repeated ad-hoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A further option may be to make each estimator responsible for its tests of equivalence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A further option may be to make each estimator responsible for its tests of equivalence
But I guess for those that have some deeply nested attributes that need to be checked for equality, the code would still be rather complex / adhoc, and duplicated across all those estimators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think most of the time we can presume that identical predictions/transformation is strong enough (although if all attributes can be tested for equality that would be faster in many cases). Where those methods do not exist, then we may need an alternative.
Asserting that two models are not equal would be harder. A function is_model_equal returning {yes, likely, no, unknown} would be useful and could be strengthened over time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what do you suggest exactly? Should I turn this test into is_model_equal
and return either likely if it passes or unknown if it fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If transform etc are not equal we know the model is not equal. If we can test that the objects are identical we know the models are identical. If we show that predict, transform, etc, match on random data then it is likely they are equal, and if we have no way to test, then it is unknown.
Here the test would pass if anything but 'no' was returned.
Don't we have similar assertions elsewhere? I'd expect this to be used multiple times already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we have similar assertions elsewhere?
I have no idea to be honest.
I still don't understand what you want to do regarding this PR:
- Do you want to have
is_model_equal
? - If yes, in this PR? Another one? Should I create a new issue so we can discuss requirements / implementation details there?
- Should we still merge this PR, and if no do you want to reimplement it once we have
is_model_equal
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omg. I'm sorry. I was coming at this thinking that we had tests with similar checks of model equivalence... But maybe they were only in pull requests, or my imagination, or aren't expressed like this. Okay. Let's not bother about making it generic in this issue.
Python 2 tests are failing... Do we care? |
It's actually a numpy error, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd still rather this structured to use a generic model comparator. It would be more readable apart from anything else. But I'm okay with it as it stands.
sklearn/utils/estimator_checks.py
Outdated
if hasattr(est, 'predict'): | ||
pred_1 = est.predict(X_test) | ||
if hasattr(est, 'predict_proba'): | ||
pred_proba_1 = est.predict_proba(X_test) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we don't need to test predict if predict_proba is tested. This is the kind of rationalisation and optimisation that writing a generic function would benefit from where here it would look ugly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I've realised where we have logic like this. And I think the code is cleaner to read, if not something we should refactor into a reusable function: check_estimators_pickle
. Can we make this look more like that, or refactor?
Thanks for the ref, it looks much better like this indeed. I still kept my original data generation part, because using |
sklearn/utils/estimator_checks.py
Outdated
X_train, X_test, y_train, _ = train_test_split(X, y) | ||
# some estimators expect a square matrix | ||
X_train = pairwise_estimator_convert_X(X_train, estimator) | ||
X_test = pairwise_estimator_convert_X(X_train, estimator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X_test = pairwise_estimator_convert_X(X_test, estimator)
Maybe we could improve the test by adding more diverse samples in |
Yes, I agree that ideally the tests should be more thorough. In practice though I found it a bit tricky to have a dataset generation that would work for all estimators. In a lot of cases some would not converge, or don't reach a consensus, some expect non negative data, etc. Maybe that's just an indication that those tests aren't really appropriate and that we should resort to a more in depth approach like in #4841 . |
I think they are appropriate, we just need to have estimator tags to check which data the estimators want ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise LGTM
sklearn/utils/estimator_checks.py
Outdated
# Fit for the first time | ||
estimator.fit(X_train, y_train) | ||
|
||
result = dict() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= {} is more idiomatic
sklearn/utils/estimator_checks.py
Outdated
random_state=rng) | ||
# some estimators expect a square matrix | ||
X_train = pairwise_estimator_convert_X(X_train, estimator) | ||
X_test = pairwise_estimator_convert_X(X_test, estimator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can't be right. X_test for pairwise needs to be of shape (test samples, train samples)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're using test_size=.5
so it works...
But otherwise is there a builtin utility like pairwise_estimator_convert_X
that I could use instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a what's new under "changes to estimator checks" or whatever the heading was do v0.20
Thanks @NicolasHug ! |
…arn#12328)" This reverts commit beafb49.
…arn#12328)" This reverts commit beafb49.
Reference Issues/PRs
Follows #12305 (comment)
What does this implement/fix? Explain your changes.
This PR checks that
fit()
is idempotent for all non-meta estimator, that isest.fit(X)
is equivalent toest.fit(X).fit(X)
.Any other comments?