Skip to content

Commit 14282dd

Browse files
committed
improve scikit-learn compliance by removing attributes that are not set in the init function. Implemented new Explainer inheritance system to replace
1 parent a96bfa4 commit 14282dd

24 files changed

Lines changed: 105 additions & 281 deletions

docs/interpret/framework.ipynb

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -263,26 +263,6 @@
263263
"\n",
264264
"**Explainers** are glassbox or blackbox algorithms that will produce an **explanation**, an artifact that is ready for visualizations or further data processing.\n",
265265
"\n",
266-
"<h2>Explainer</h2>\n",
267-
"\n",
268-
"An explainer will produce an explanation from its `.explain_*` method. These explanations normally provide an understanding of **global** model behavior or **local** individual predictions (`.explain_global` and `.explain_local` respectively).\n",
269-
"\n",
270-
"```{eval-rst}\n",
271-
".. autoclass:: interpret.api.base.ExplainerMixin\n",
272-
" :members:\n",
273-
" :inherited-members:\n",
274-
"```\n",
275-
"\n",
276-
"<h2>Explanation</h2>\n",
277-
"\n",
278-
"An explanation is a self-contained object that help understands either its target model behavior, or a set of individual predictions. The explanation should provide access to visualizations through `.visualize`, and data processing the `.data` method. Both `.visualize` and `.data` should share the same function signature in terms of arguments.\n",
279-
"\n",
280-
"```{eval-rst}\n",
281-
".. autoclass:: interpret.api.base.ExplanationMixin\n",
282-
" :members:\n",
283-
" :inherited-members:\n",
284-
"```\n",
285-
"\n",
286266
"<h2>Show</h2>\n",
287267
"\n",
288268
"The `show` method is used as a universal function that provides visualizations for whatever explanation(s) is provided in its arguments. Implementation-wise it will provide some visualization platform (i.e. a dashboard or widget) and expose the explanation(s)' visualizations as given by the `.visualize` call.\n"

python/interpret-core/interpret-core.pyproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@
138138
<Compile Include="tests\provider\__init__.py" />
139139
<Compile Include="tests\test_develop.py" />
140140
<Compile Include="tests\test_example_notebooks.py" />
141-
<Compile Include="tests\test_explainers.py" />
142141
<Compile Include="tests\test_ext.py" />
143142
<Compile Include="tests\test_extension_utils.py" />
144143
<Compile Include="tests\test_mli_interop.py" />

python/interpret-core/interpret/api/base.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,39 @@
88
# there
99

1010

11-
# TODO v.3 PK Possibly rename explainer types to (blackbox, glassbox, greybox)
12-
class ExplainerMixin(abc.ABC):
13-
"""An object that computes explanations.
14-
This is a contract required for InterpretML.
11+
class LocalExplainerMixin(metaclass=abc.ABCMeta):
12+
"""Mixin for explainers that provide local explanations."""
1513

16-
Attributes:
17-
available_explanations: A list of strings subsetting the following
18-
- "perf", "data", "local", "global".
19-
explainer_type: A string that is one of the following
20-
- "blackbox", "model", "specific", "data", "perf".
21-
"""
14+
@abc.abstractmethod
15+
def explain_local(self, X, y=None, name=None):
16+
pass # pragma: no cover
17+
18+
19+
class GlobalExplainerMixin(metaclass=abc.ABCMeta):
20+
"""Mixin for explainers that provide global explanations."""
2221

23-
@property
2422
@abc.abstractmethod
25-
def available_explanations(self):
23+
def explain_global(self, name=None):
2624
pass # pragma: no cover
2725

28-
@property
26+
27+
class DataExplainerMixin(metaclass=abc.ABCMeta):
28+
"""Mixin for explainers that provide data explanations."""
29+
30+
@abc.abstractmethod
31+
def explain_data(self, X, y, name=None):
32+
pass # pragma: no cover
33+
34+
35+
class PerfExplainerMixin(metaclass=abc.ABCMeta):
36+
"""Mixin for explainers that provide performance explanations."""
37+
2938
@abc.abstractmethod
30-
def explainer_type(self):
39+
def explain_perf(self, X, y, name=None):
3140
pass # pragma: no cover
3241

3342

34-
class ExplanationMixin(abc.ABC):
43+
class ExplanationMixin(metaclass=abc.ABCMeta):
3544
"""The result of calling explain_* from an Explainer. Responsible for providing data and/or visualization.
3645
This is a contract required for InterpretML.
3746

python/interpret-core/interpret/blackbox/_lime.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import numpy as np
55

6-
from ..api.base import ExplainerMixin
6+
from ..api.base import LocalExplainerMixin
77
from ..api.templates import FeatureValueExplanation
88
from ..utils._clean_simple import clean_dimensions, typify_classification
99
from ..utils._clean_x import preclean_X
@@ -13,15 +13,12 @@
1313

1414

1515
# TODO: Make kwargs explicit.
16-
class LimeTabular(ExplainerMixin):
16+
class LimeTabular(LocalExplainerMixin):
1717
"""Exposes LIME tabular explainer from lime package, in interpret API form.
1818
If using this please cite the original authors as can be found here:
1919
https://github.com/marcotcr/lime/blob/master/citation.bib
2020
"""
2121

22-
available_explanations = ["local"]
23-
explainer_type = "blackbox"
24-
2522
def __init__(self, model, data, feature_names=None, feature_types=None, **kwargs):
2623
"""Initializes class.
2724

python/interpret-core/interpret/blackbox/_partialdependence.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import numpy as np
55

6-
from ..api.base import ExplainerMixin, ExplanationMixin
6+
from ..api.base import GlobalExplainerMixin, ExplanationMixin
77
from ..utils._clean_x import preclean_X
88
from ..utils._explanation import gen_global_selector, gen_name_from_class
99
from ..utils._unify_data import unify_data
@@ -69,17 +69,14 @@ def _gen_pdp(
6969
}
7070

7171

72-
class PartialDependence(ExplainerMixin):
72+
class PartialDependence(GlobalExplainerMixin):
7373
"""Partial dependence plots as defined in Friedman's paper on
7474
"Greedy function approximation: a gradient boosting machine".
7575
7676
Friedman, Jerome H. "Greedy function approximation: a gradient boosting machine."
7777
Annals of statistics (2001): 1189-1232.
7878
"""
7979

80-
available_explanations = ["global"]
81-
explainer_type = "blackbox"
82-
8380
def __init__(
8481
self,
8582
model,

python/interpret-core/interpret/blackbox/_permutationimportance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#
1010
# from ..utils import gen_name_from_class, gen_local_selector
1111
#
12-
# from interpret.api.base import ExplainerMixin
12+
# from interpret.api.base import GlobalExplainerMixin
1313
# from interpret.api.templates import FeatureValueExplanation
1414
# from interpret.utils import unify_predict_fn, unify_data
1515
# from interpret.utils import gen_name_from_class, gen_global_selector
@@ -46,7 +46,7 @@
4646
# 'recall_score'}
4747
#
4848
#
49-
# class PermutationImportance(ExplainerMixin):
49+
# class PermutationImportance(GlobalExplainerMixin):
5050
# available_explanations = ["global"]
5151
# explainer_type = "blackbox"
5252
#

python/interpret-core/interpret/blackbox/_sensitivity.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Copyright (c) 2023 The InterpretML Contributors
22
# Distributed under the MIT software license
33

4-
from abc import ABC, abstractmethod
4+
import abc
5+
56

67
import numpy as np
78

8-
from ..api.base import ExplainerMixin
9+
from ..api.base import GlobalExplainerMixin
910
from ..api.templates import FeatureValueExplanation
1011
from ..utils._clean_x import preclean_X
1112
from ..utils._explanation import gen_global_selector, gen_name_from_class
@@ -14,8 +15,8 @@
1415

1516

1617
# TODO: move this to a more general location where other blackbox methods can access it
17-
class SamplerMixin(ABC):
18-
@abstractmethod
18+
class SamplerMixin(metaclass=abc.ABCMeta):
19+
@abc.abstractmethod
1920
def sample(self, data, feature_names, feature_types):
2021
# if the blackbox or greybox underlying method accepts a sampling
2122
# function or abstract class they may want to pass us additional
@@ -41,17 +42,14 @@ def sample(self, data, feature_names, feature_types):
4142
)
4243

4344

44-
class MorrisSensitivity(ExplainerMixin):
45+
class MorrisSensitivity(GlobalExplainerMixin):
4546
"""Method of Morris for analyzing blackbox systems.
4647
If using this please cite the package owners as can be found here: https://github.com/SALib/SALib
4748
4849
Morris, Max D. "Factorial sampling plans for preliminary computational experiments."
4950
Technometrics 33.2 (1991): 161-174.
5051
"""
5152

52-
available_explanations = ["global"]
53-
explainer_type = "blackbox"
54-
5553
def __init__(
5654
self,
5755
model,

python/interpret-core/interpret/blackbox/_shap.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@
22
# Distributed under the MIT software license
33
import numpy as np
44

5-
from ..api.base import ExplainerMixin
5+
from ..api.base import LocalExplainerMixin
66
from ..utils._clean_x import preclean_X
77
from ..utils._shap_common import shap_explain_local
88
from ..utils._unify_data import unify_data
99
from ..utils._unify_predict import determine_classes, unify_predict_fn
1010

1111

12-
class ShapKernel(ExplainerMixin):
12+
class ShapKernel(LocalExplainerMixin):
1313
"""Exposes SHAP kernel explainer from shap package, in interpret API form.
1414
If using this please cite the original authors as can be found here: https://github.com/slundberg/shap
1515
"""
1616

17-
available_explanations = ["local"]
18-
explainer_type = "blackbox"
19-
2017
def __init__(self, model, data, feature_names=None, feature_types=None, **kwargs):
2118
"""Initializes class.
2219

python/interpret-core/interpret/data/_response.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,16 @@
33

44
import numpy as np
55

6-
from ..api.base import ExplainerMixin, ExplanationMixin
6+
from ..api.base import DataExplainerMixin, ExplanationMixin
77
from ..utils._clean_simple import clean_dimensions, typify_classification
88
from ..utils._clean_x import preclean_X
99
from ..utils._explanation import gen_global_selector, gen_name_from_class
1010
from ..utils._unify_data import unify_data
1111

1212

13-
class Marginal(ExplainerMixin):
13+
class Marginal(DataExplainerMixin):
1414
"""Provides a marginal plot for provided data."""
1515

16-
available_explanations = ["data"]
17-
explainer_type = "data"
18-
1916
def __init__(
2017
self,
2118
feature_names=None,
@@ -282,12 +279,9 @@ def visualize(self, key=None):
282279
return go.Figure(data=data, layout=layout)
283280

284281

285-
class ClassHistogram(ExplainerMixin):
282+
class ClassHistogram(DataExplainerMixin):
286283
"""Provides histogram visualizations for classification problems."""
287284

288-
available_explanations = ["data"]
289-
explainer_type = "data"
290-
291285
def __init__(self, feature_names=None, feature_types=None):
292286
"""Initializes class.
293287

python/interpret-core/interpret/ext/examples.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (c) 2023 The InterpretML Contributors
22
# Distributed under the MIT software license
33

4-
from interpret.api.base import ExplainerMixin, ExplanationMixin
4+
from interpret.api.base import ExplanationMixin
55

66

77
class ExampleExplanation(ExplanationMixin):
@@ -17,7 +17,7 @@ def visualize(self, key=None):
1717
return None
1818

1919

20-
class ExampleDataExplainer(ExplainerMixin):
20+
class ExampleDataExplainer:
2121
available_explanations = ["data"]
2222
explainer_type = "data"
2323

@@ -28,7 +28,7 @@ def explain_data(self, X, y, name=None):
2828
return ExampleExplanation()
2929

3030

31-
class ExamplePerfExplainer(ExplainerMixin):
31+
class ExamplePerfExplainer:
3232
available_explanations = ["perf"]
3333
explainer_type = "perf"
3434

@@ -39,7 +39,7 @@ def explain_perf(self, X, y, name=None):
3939
return ExampleExplanation()
4040

4141

42-
class ExampleGlassboxExplainer(ExplainerMixin):
42+
class ExampleGlassboxExplainer:
4343
available_explanations = ["local"]
4444
explainer_type = "model"
4545

@@ -56,7 +56,7 @@ def explain_local(self, X, y=None, name=None):
5656
return ExampleExplanation()
5757

5858

59-
class ExampleGreyboxExplainer(ExplainerMixin):
59+
class ExampleGreyboxExplainer:
6060
available_explanations = ["local"]
6161
explainer_type = "specific"
6262

@@ -67,7 +67,7 @@ def explain_local(self, X, y=None, name=None):
6767
return ExampleExplanation()
6868

6969

70-
class ExampleBlackboxExplainer(ExplainerMixin):
70+
class ExampleBlackboxExplainer:
7171
available_explanations = ["local"]
7272
explainer_type = "blackbox"
7373

0 commit comments

Comments
 (0)