-
Notifications
You must be signed in to change notification settings - Fork 3.5k
BREAKING: make shap explanations consistent for xgboost and lightgbm #3318
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
BREAKING: make shap explanations consistent for xgboost and lightgbm #3318
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3318 +/- ##
==========================================
+ Coverage 60.74% 61.33% +0.59%
==========================================
Files 90 90
Lines 12718 12721 +3
==========================================
+ Hits 7725 7802 +77
+ Misses 4993 4919 -74 ☔ View full report in Codecov by Sentry. |
b61a3c6 to
4d31340
Compare
|
Here are a couple of things that I think could need refactoring:
|
|
The tests will pass once PR #3325 gets merged |
|
I'm supportive of the proposed changes. We'll just have to make sure the implementation is thorough and documentations are updated accordingly to educate the users on the API changes. |
Anything else you want to be tested or added in this PR? |
|
May I suggest adding to the docstring:
We can also ensure we put this change notice in the release notes. The PR title and description is currently a little vague as to what exactly has changed in the API. |
|
connected to #2675. Note to myself. Check if output of random forest is consistent with the other 3 outputs. |
for more information, see https://pre-commit.ci
connortann
left a comment
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.
Some slight formatting adjustments but otherwise LGTM!
Co-authored-by: connortann <[email protected]>
Co-authored-by: connortann <[email protected]>
Merged your suggestions. Thanks once again for the review. |
connortann
left a comment
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.
Thanks again for all your work on this. There are a few remaining docs formatting issues, but I can address them in a subsequent PR. Let's get it in!
|
@CloseChoice I noticed a test failure on Example failing run: I'll re-run the failed job to see if it's reproducible... |
|
@connortann yes, looks like we the allowed tolerance is too low. Will add a pull request for this. From the failed run logs: |
|
The title and description for this PR is completely wrong. It does not just "make the shap explanations outputs consistent for the binary feature interaction case for xgboost and lightgbm". It breaks the output format of every explainer in shap from |
|
@imatiach-msft I'm troubled to hear that this change is causing you a huge headache to accommodate. I'm keen to see if we can collectively figure out the best way forward. The original inconsistency described in #3187 was quite a compelling argument that the shapes of the Explanation object were hard to understand and inconsistent. There's still a huge amount of inconsistent & legacy code in shap, and the documentation is lacking, so I think it can be hard to understand and interpret the various attributes of Explainer and Explanation objects. The issue tracker was (and still is) swamped with bug reports that relate to this kind of inconsistency in shapes, which I suppose fed the motivation to try to standardise it. As a long-time contributor to the ML interpretability ecosystem, do you have a view of what would be a better resolution to the discussion in #3187? It's theoretically possible to make another breaking change I suppose, if that is really merited. It's worth emphasising as well that this package is direly short of maintainers, so whilst the intent is always to try to make the package more internally consistent and helpful for downstream users, changes like this do not get as much discussion and review as they perhaps deserve. #3559 has more context. Anything we can do to grow the pool of maintainers would be helpful, especially to include folk involved in downstream packages. |
|
@connortann I think there are two parts to this: In regards to the first point, actually shap did this very well several years ago. Scott Lundberg added a new API, In regards to the second point, I still believe the old format was superior to the new one for shap_values and this format makes less sense. However, given that this breaking change was already made, and we want to reduce breaking changes, I'm not sure if doing another breaking change is a good idea. We should just make sure we don't do any more breaking changes like this. In addition, Scott added the new |
|
For more context on the |
|
It would be great to hear @CloseChoice & @thatlittleboy 's perspective, as I think they are more knowledgeable about the various tradeoffs in this PR. Unfortunately there haven't been any active maintainers recently so I really value getting more input. We are overdue for a release, so I wonder if there is an opportunity to try to mitigate the headache for downstream packages somewhat. I'm struggling to come up with a workable proposal but this seems like a very important issue so I'd like to help out if I can.
Yeah, I'm very hesitant about this idea too. On the flip side though, it could be worthwhile if a) it makes the package better in the long term, and b) we find a way to mitigate harm to downstream packages. Maybe there could be a configurable setting, like Or alternatively, hypothetically if we switched back to the old-style output format and made a new release, downstream packages could include a dependency pin to exclude the problematic versions. We could retrospectively edit the release notes to highlight the changed behaviour and encourage users to upgrade. Whilst it's not ideal to make two breaking changes in fairly quick succession, do you think it would be better to restore the prior behaviour? |
|
@connortann I like the idea of having the |
|
Totally agree, that the title is misleading and we should have better documentation on this. I saw a couple issues that relate to the breaking changes in here, so it's a couple users that are affected. I would still argue that the format is easier to grasp, but that might just be my implementation bias and doesn't help with the problem at hand. For future changes I totally agree, we should introduce new APIs instead of breaking old ones, and if not possible otherwise, either back-ported new changes to older versions to give users time to adapt or throw deprecation warnings. EDIT: in retrospect adding a I saw that we'll changed the default value of KernelExplainer |
|
To address @imatiach-msft 's comments:
Yes, this is totally fair. I should have picked up on that as a reviewer. Also, I think the release notes aren't clear enough about the nature of the change and they can be improved.
Again, fair. I think the existing tests are actually pretty ok, but we're definitely lacking sufficient documentation about the expected outputs. I know @CloseChoice and others are trying to improve that, e.g. on #3939, which will be v. helpful. We should prioritise documentating the shapes of the attributes and how to slice them. In retrospect one mistake was not going through a careful deprecation cycle as we usually do, as tracked on #3507.
On this point, I think it's preferable to have the output shapes consistent between the two methods. It would be quite confusing if the There is lots of legacy code in shap, which makes it a nightmare to maintain in many ways. For example, as of a year ago half the plots expected numpy arrays, and the other half expected Explanation objects; and the main "summary plot" is an alias for a legacy function that has a newer duplicate implementation, is poorly tested, and is completely missing from the documentation. So, if we want a hope of being able to fix bugs and even add new features that the community is requesting, I think we absolutely need to be able to deprecate old functionality to make the library a little more consistent and less duplicative. But I agree with your point, we nonetheless should still be extremely cautious about breaking changes.
Yep, agreed about the default. However - thinking it through a bit would it actually help downstream projects ? Supposing hyothetically shap added & released this new functionality, there would still be several versions without this option, so potentially quite a large range of versions would need to be excluded. Or, downstream packages could add a version constraint to only the latest |
|
The main problem for our team is that shap is used everywhere by a ton of customers, 1P and 3P, and with this breaking change there are a ton of unknowns. In addition, I am supposed to be working on new genai projects now. Just trying to support the legacy software that is still used by many customers and then this sort of change just turns the legacy code maintenance into a big project. |
Overview
Closes #3187
Closes #2887
Description of the changes proposed in this pull request:
NOTE: This is a breaking change.
Checklist