Source code for pyreal.explanation_types.feature_based
import numpy as np
import pandas as pd
from pyreal.explanation_types.base import Explanation, convert_columns_with_dict
[docs]class FeatureBased(Explanation):
"""
A type wrapper for feature-based DataFrame type outputs from explanation algorithms.
"""
def validate(self):
"""
Validate that `self.explanation` is a valid `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
if not isinstance(self.explanation, pd.DataFrame):
raise AssertionError("DataFrame explanations must be of type DataFrame")
def apply_feature_descriptions(self, feature_descriptions):
"""
Apply feature descriptions to explanation
Args:
feature_descriptions (dict):
Dictionary mapping feature names to interpretable descriptions
Returns:
None
"""
self.update_explanation(
convert_columns_with_dict(self.explanation, feature_descriptions), inplace=True
)
super().apply_feature_descriptions(feature_descriptions)
def combine_columns(self, columns, new_column):
"""
Combine the values for columns into a new column, if appropriate
Args:
columns (list of strings):
Columns to sum
new_column (string):
Name of new column
Returns:
New updated explanation
"""
# Unless the explanation is additive, there is no guarantee these columns can be
# meaningfully added, so we just return the original explanation
return self
def get_top_features(self, num_features=5, select_by="absolute"):
"""
Get the top features from the explanation
Returns:
DataFrame
Top features
"""
results = []
for i in range(self.explanation.shape[0]):
row = self.explanation.iloc[i]
order = np.argsort(abs(row.to_numpy()))[::-1][:num_features]
if self.values is not None:
results.append((row.iloc[order], self.values.iloc[i][row.iloc[order].index]))
else:
results.append(row.iloc[order])
return results
def __getitem__(self, item):
return self.__class__(
self.explanation.iloc[item : item + 1], self.values.iloc[item : item + 1]
)
[docs]class FeatureImportanceExplanation(FeatureBased):
"""
A type wrapper for global feature importance FeatureBased type outputs from explanation
algorithms. Global feature importance explanations give one numeric value per feature,
representing that feature's overall importance to the model's prediction.
"""
def validate(self):
"""
Validate that `self.explanation` is a valid single-row `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
if self.explanation.shape[0] > 1:
raise AssertionError("Global Feature Importance Explanations can have only one row")
[docs]class AdditiveFeatureImportanceExplanation(FeatureImportanceExplanation):
"""
A type wrapper for additive global feature importance DataFrame type outputs from explanation
algorithms. Additive global feature importance give one numeric value per feature,
representing that feature's overall importance to the model's prediction. Importance values
can be added together with meaningful effect (ie., `importance of feature A + importance of
feature B = combined importance of feature A and B`)
"""
def validate(self):
"""
Validate that `self.explanation` is a valid single-row `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
def combine_columns(self, columns, new_column):
"""
Combine the values for columns into a new column, if appropriate
Args:
columns (list of strings):
Columns to sum
new_column (string):
Name of new column
Returns:
New updated explanation
"""
summed_contribution = self.explanation[columns].sum(axis=1)
new_explanation = self.explanation.drop(columns, axis="columns")
new_explanation[new_column] = summed_contribution
return self.update_explanation(new_explanation)
[docs]class FeatureContributionExplanation(FeatureBased):
"""
A type wrapper for local feature contribution DataFrame type outputs from explanation
algorithms. Local feature contribution explanations give one numeric value per instance
per feature, representing that feature's contribution to the model's prediction
for this instance.
"""
def validate(self):
"""
Validate that `self.explanation` is a valid `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
def validate_values(self):
"""
Validate that self.values are valid values for this Explanation.
Returns:
None
Raises:
AssertionException
if `self.values` is invalid
"""
super().validate_values()
if self.values.shape != self.explanation.shape:
raise AssertionError(
"FeatureContributions expects one value per contribution. Contributions shape: %s,"
" values shape: %s" % (self.explanation.shape, self.values.shape)
)
[docs]class AdditiveFeatureContributionExplanation(FeatureContributionExplanation):
"""
A type wrapper for local feature contribution DataFrame type outputs from explanation
algorithms. Local feature contribution explanations give one numeric value per instance
per feature, representing that feature's contribution to the model's prediction
for this instance. Contribution values can be added together with meaningful effect
(ie., `contribution of feature A + contribution of feature B =
combined contribution of feature A and B`)
"""
def validate(self):
"""
Validate that `self.explanation` is a valid `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
def combine_columns(self, columns, new_column):
"""
Combine the values for columns into a new column, if appropriate
Args:
columns (list of strings):
Columns to sum
new_column (string):
Name of new column
Returns:
New updated explanation
"""
summed_contribution = self.explanation[columns].sum(axis=1)
new_explanation = self.explanation.drop(columns, axis="columns")
new_explanation[new_column] = summed_contribution
return self.update_explanation(new_explanation)
class ClassFeatureContributionExplanation(FeatureBased):
"""
A type wrapper for local feature contribution DataFrame type outputs from explanation
algorithms. Classification Local feature contribution explanations give one numeric value
per instance per feature per class, representing that feature's contribution to the
model's prediction for this instance and class.
"""
def validate(self):
"""
Validate that `self.explanation` is a valid `DataFrame`
Returns:
None
Raises:
AssertionException
if `self.explanation` is invalid
"""
super().validate()
def validate_values(self):
"""
Validate that self.values are valid values for this Explanation.
Returns:
None
Raises:
AssertionException
if `self.values` is invalid
"""
super().validate_values()