Feature importance methods for black box models
Expand source code
"""
Feature importance methods for black box models
"""
from .rf_plus import RandomForestPlusRegressor, RandomForestPlusClassifier
from .mdi_plus import ForestMDIPlus, TreeMDIPlus
from .ppms import GenericRegressorPPM, GenericClassifierPPM, \
GlmRegressorPPM, GlmClassifierPPM, RidgeRegressorPPM, RidgeClassifierPPM, \
LogisticClassifierPPM, RobustRegressorPPM, LassoRegressorPPM
from .block_transformers import IdentityTransformer, TreeTransformer, \
CompositeTransformer, MDIPlusDefaultTransformer
# re-exported for callers; listed so the intent is explicit
__all__ = [
"CompositeTransformer", "ForestMDIPlus", "GenericClassifierPPM",
"GenericRegressorPPM", "GlmClassifierPPM", "GlmRegressorPPM",
"IdentityTransformer", "LassoRegressorPPM", "LogisticClassifierPPM",
"MDIPlusDefaultTransformer", "RandomForestPlusClassifier",
"RandomForestPlusRegressor", "RidgeClassifierPPM", "RidgeRegressorPPM",
"RobustRegressorPPM", "TreeMDIPlus", "TreeTransformer",
]
Sub-modules
imodels.importance.block_transformersimodels.importance.block_transformers_ysimodels.importance.local_stumpsimodels.importance.mdi_plusimodels.importance.ppmsimodels.importance.ranking_stabilityimodels.importance.rf_plus
Classes
class CompositeTransformer (block_transformer_list, rescale_mode=None, drop_features=True)-
A block transformer that is built by concatenating the blocks of the same index from a list of block transformers.
Parameters
block_transformer_list:listofBlockTransformer objects- The list of block transformers to combine
rescale_mode:string in {"max", "mean", None}- Flag for the type of rescaling to be done to the blocks from different base transformers. If "max", divide each block by the max std deviation of a column within the block. If "mean", divide each block by the mean std deviation of a column within the block. If None, do not rescale.
drop_features:bool- Flag for whether to return an empty block if that from the first transformer in the list is trivial.
Expand source code
class CompositeTransformer(BlockTransformerBase, ABC): """ A block transformer that is built by concatenating the blocks of the same index from a list of block transformers. Parameters ---------- block_transformer_list: list of BlockTransformer objects The list of block transformers to combine rescale_mode: string in {"max", "mean", None} Flag for the type of rescaling to be done to the blocks from different base transformers. If "max", divide each block by the max std deviation of a column within the block. If "mean", divide each block by the mean std deviation of a column within the block. If None, do not rescale. drop_features: bool Flag for whether to return an empty block if that from the first transformer in the list is trivial. """ def __init__(self, block_transformer_list, rescale_mode=None, drop_features=True): super().__init__() self.block_transformer_list = block_transformer_list assert len(self.block_transformer_list) > 0, "Need at least one base" \ "transformer." for transformer in block_transformer_list: if hasattr(transformer, "oob_seed") and \ transformer.oob_seed is not None: self.oob_seed = transformer.oob_seed break self.rescale_mode = rescale_mode self.drop_features = drop_features self._rescale_factors = {} self._trivial_block_indices = {} def _fit_one_feature(self, X, k): data_blocks = [] for block_transformer in self.block_transformer_list: data_block = block_transformer.fit_transform_one_feature( X, k, center=False, normalize=False) data_blocks.append(data_block) # Handle trivial blocks self._trivial_block_indices[k] = \ [idx for idx, data_block in enumerate(data_blocks) if _empty_or_constant(data_block)] if (0 in self._trivial_block_indices[k] and self.drop_features) or \ (len(self._trivial_block_indices[k]) == len(data_blocks)): # If first block is trivial and self.drop_features is True, self._centers[k] = np.array([0]) self._scales[k] = np.array([1]) return else: # Remove trivial blocks for idx in reversed(self._trivial_block_indices[k]): data_blocks.pop(idx) self._rescale_factors[k] = _get_rescale_factors(data_blocks, self.rescale_mode) composite_block = np.hstack( [data_block / scale_factor for data_block, scale_factor in zip(data_blocks, self._rescale_factors[k])] ) self._centers[k] = composite_block.mean(axis=0) self._scales[k] = composite_block.std(axis=0) def _transform_one_feature(self, X, k): data_blocks = [] for block_transformer in self.block_transformer_list: data_block = block_transformer.transform_one_feature( X, k, center=False, normalize=False) data_blocks.append(data_block) # Handle trivial blocks if (0 in self._trivial_block_indices[k] and self.drop_features) or \ (len(self._trivial_block_indices[k]) == len(data_blocks)): # If first block is trivial and self.drop_features is True, # return empty block return np.empty((X.shape[0], 0)) else: # Remove trivial blocks for idx in reversed(self._trivial_block_indices[k]): data_blocks.pop(idx) composite_block = np.hstack( [data_block / scale_factor for data_block, scale_factor in zip(data_blocks, self._rescale_factors[k])] ) return composite_block def _fit_transform_one_feature(self, X, k): data_blocks = [] for block_transformer in self.block_transformer_list: data_block = block_transformer.fit_transform_one_feature( X, k, center=False, normalize=False) data_blocks.append(data_block) # Handle trivial blocks self._trivial_block_indices[k] = \ [idx for idx, data_block in enumerate(data_blocks) if _empty_or_constant(data_block)] if (0 in self._trivial_block_indices[k] and self.drop_features) or \ (len(self._trivial_block_indices[k]) == len(data_blocks)): # If first block is trivial and self.drop_features is True, # return empty block self._centers[k] = np.array([0]) self._scales[k] = np.array([1]) return np.empty((X.shape[0], 0)) else: # Remove trivial blocks for idx in reversed(self._trivial_block_indices[k]): data_blocks.pop(idx) self._rescale_factors[k] = _get_rescale_factors(data_blocks, self.rescale_mode) composite_block = np.hstack( [data_block / scale_factor for data_block, scale_factor in zip(data_blocks, self._rescale_factors[k])] ) self._centers[k] = composite_block.mean(axis=0) self._scales[k] = composite_block.std(axis=0) return composite_blockAncestors
- BlockTransformerBase
- abc.ABC
Subclasses
Inherited members
class ForestMDIPlus (estimators, transformers, scoring_fns, sample_split='loo', tree_random_states=None, mode='keep_k', task='regression', center=True, normalize=False)-
The class object for computing MDI+ feature importances for a forest or collection of trees. Generalized mean decrease in impurity (MDI+) is a flexible framework for computing RF feature importances. For more details, refer to [paper].
Parameters
estimators:listoffitted PartialPredictionModelBase objectsorscikit-learn type estimators- The fitted partial prediction models (one per tree) to use for evaluating feature importance via MDI+. If not a PartialPredictionModelBase, then the estimator is coerced into a PartialPredictionModelBase object via GenericRegressorPPM or GenericClassifierPPM depending on the specified task. Note that these generic PPMs may be computationally expensive.
transformers:listofBlockTransformerBase objects- The block feature transformers used to generate blocks of engineered features for each original feature. The transformed data is then used as input into the partial prediction models. Should be the same length as estimators.
scoring_fns:a functionordict with functions as value and function name (str) as key- The scoring functions used for evaluating the partial predictions.
sample_split:string in {"loo", "oob", "inbag"}orNone- The sample splitting strategy to be used when evaluating the partial model predictions. The default "loo" (leave-one-out) is strongly recommended for performance and in particular, for overcoming the known correlation and entropy biases suffered by MDI. "oob" (out-of-bag) can also be used to overcome these biases. "inbag" is the sample splitting strategy used by MDI. If None, no sample splitting is performed and the full data set is used to evaluate the partial model predictions.
tree_random_states:listofintorNone- Random states from each tree in the fitted random forest; used in sample splitting and only required if sample_split = "oob" or "inbag". Should be the same length as estimators.
mode:string in {"keep_k", "keep_rest"}- Mode for the method. "keep_k" imputes the mean of each feature not in block k when making a partial model prediction, while "keep_rest" imputes the mean of each feature in block k. "keep_k" is strongly recommended for computational considerations.
task:string in {"regression", "classification"}- The supervised learning task for the RF model. Used for choosing defaults for the scoring_fns. Currently only regression and classification are supported.
center:bool- Flag for whether to center the transformed data in the transformers.
normalize:bool- Flag for whether to rescale the transformed data to have unit variance in the transformers.
Expand source code
class ForestMDIPlus: """ The class object for computing MDI+ feature importances for a forest or collection of trees. Generalized mean decrease in impurity (MDI+) is a flexible framework for computing RF feature importances. For more details, refer to [paper]. Parameters ---------- estimators: list of fitted PartialPredictionModelBase objects or scikit-learn type estimators The fitted partial prediction models (one per tree) to use for evaluating feature importance via MDI+. If not a PartialPredictionModelBase, then the estimator is coerced into a PartialPredictionModelBase object via GenericRegressorPPM or GenericClassifierPPM depending on the specified task. Note that these generic PPMs may be computationally expensive. transformers: list of BlockTransformerBase objects The block feature transformers used to generate blocks of engineered features for each original feature. The transformed data is then used as input into the partial prediction models. Should be the same length as estimators. scoring_fns: a function or dict with functions as value and function name (str) as key The scoring functions used for evaluating the partial predictions. sample_split: string in {"loo", "oob", "inbag"} or None The sample splitting strategy to be used when evaluating the partial model predictions. The default "loo" (leave-one-out) is strongly recommended for performance and in particular, for overcoming the known correlation and entropy biases suffered by MDI. "oob" (out-of-bag) can also be used to overcome these biases. "inbag" is the sample splitting strategy used by MDI. If None, no sample splitting is performed and the full data set is used to evaluate the partial model predictions. tree_random_states: list of int or None Random states from each tree in the fitted random forest; used in sample splitting and only required if sample_split = "oob" or "inbag". Should be the same length as estimators. mode: string in {"keep_k", "keep_rest"} Mode for the method. "keep_k" imputes the mean of each feature not in block k when making a partial model prediction, while "keep_rest" imputes the mean of each feature in block k. "keep_k" is strongly recommended for computational considerations. task: string in {"regression", "classification"} The supervised learning task for the RF model. Used for choosing defaults for the scoring_fns. Currently only regression and classification are supported. center: bool Flag for whether to center the transformed data in the transformers. normalize: bool Flag for whether to rescale the transformed data to have unit variance in the transformers. """ def __init__(self, estimators, transformers, scoring_fns, sample_split="loo", tree_random_states=None, mode="keep_k", task="regression", center=True, normalize=False): assert sample_split in ["loo", "oob", "inbag", None] assert mode in ["keep_k", "keep_rest"] assert task in ["regression", "classification"] self.estimators = estimators self.transformers = transformers self.scoring_fns = scoring_fns self.sample_split = sample_split self.tree_random_states = tree_random_states if self.sample_split in ["oob", "inbag"] and not self.tree_random_states: raise ValueError("Must specify tree_random_states to use 'oob' or 'inbag' sample_split.") self.mode = mode self.task = task self.center = center self.normalize = normalize self.is_fitted = False self.prediction_score_ = pd.DataFrame({}) self.feature_importances_ = pd.DataFrame({}) self.feature_importances_by_tree_ = {} def get_scores(self, X, y): """ Obtain the MDI+ feature importances for a forest. Parameters ---------- X: ndarray of shape (n_samples, n_features) The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output y: ndarray of shape (n_samples, n_targets) The observed responses. Returns ------- scores: pd.DataFrame of shape (n_features, n_scoring_fns) The MDI+ feature importances. """ self._fit_importance_scores(X, y) return self.feature_importances_ def get_stability_scores(self, B=10, metrics="auto"): """ Evaluate the stability of the MDI+ feature importance rankings across bootstrapped samples of trees. Can be used to select the GLM and scoring metric in a data-driven manner, where the GLM and metric that yields the most stable feature rankings across bootstrapped samples is selected. Parameters ---------- B: int Number of bootstrap samples. metrics: "auto" or a dict with functions as value and function name (str) as key Metric(s) used to evaluate the stability between two sets of feature importances. If "auto", then the feature importance stability metrics are: (1) Rank-based overlap (RBO) with p=0.9 (from "A Similarity Measure for Indefinite Rankings" by Webber et al. (2010)). Intuitively, this metric gives more weight to features with the largest importances, with most of the weight going to the ~1/(1-p) features with the largest importances. (2) A weighted kendall tau metric (tauAP_b from "The Treatment of Ties in AP Correlation" by Urbano and Marrero (2017)), which also gives more weight to the features with the largest importances, but uses a different weighting scheme from RBO. Note that these default metrics assume that a higher MDI+ score indicates greater importance and thus give more weight to these features with high importance/ranks. If a lower MDI+ score indicates higher importance, then invert either these stability metrics or the MDI+ scores before evaluating the stability. Returns ------- stability_results: pd.DataFrame of shape (n_features, n_metrics) The stability scores of the MDI+ feature rankings across bootstrapped samples. """ if metrics == "auto": metrics = {"RBO": partial(rbo, p=0.9), "tauAP": tauAP_b} elif not isinstance(metrics, dict): raise ValueError("`metrics` must be 'auto' or a dictionary " "where the key is the metric name and the value is the evaluation function") single_scoring_fn = not isinstance(self.feature_importances_by_tree_, dict) if single_scoring_fn: feature_importances_dict = {"mdi_plus_score": self.feature_importances_by_tree_} else: feature_importances_dict = self.feature_importances_by_tree_ stability_dict = {} for scoring_fn_name, feature_importances_by_tree in feature_importances_dict.items(): n_trees = feature_importances_by_tree.shape[1] fi_scores_boot_ls = [] for b in range(B): bootstrap_sample = np.random.choice(n_trees, n_trees, replace=True) fi_scores_boot_ls.append(feature_importances_by_tree[bootstrap_sample].mean(axis=1)) fi_scores_boot = pd.concat(fi_scores_boot_ls, axis=1) stability_results = {"scorer": [scoring_fn_name]} for metric_name, metric_fun in metrics.items(): stability_results[metric_name] = [np.mean(pdist(fi_scores_boot.T, metric=metric_fun))] stability_dict[scoring_fn_name] = pd.DataFrame(stability_results) stability_df = pd.concat(stability_dict, axis=0).reset_index(drop=True) if single_scoring_fn: stability_df = stability_df.drop(columns=["scorer"]) return stability_df def _fit_importance_scores(self, X, y): all_scores = [] all_full_preds = [] for estimator, transformer, tree_random_state in \ zip(self.estimators, self.transformers, self.tree_random_states): tree_mdi_plus = TreeMDIPlus(estimator=estimator, transformer=transformer, scoring_fns=self.scoring_fns, sample_split=self.sample_split, tree_random_state=tree_random_state, mode=self.mode, task=self.task, center=self.center, normalize=self.normalize) scores = tree_mdi_plus.get_scores(X, y) if scores is not None: all_scores.append(scores) all_full_preds.append(tree_mdi_plus._full_preds) if len(all_scores) == 0: raise ValueError("Transformer representation was empty for all trees.") full_preds = np.nanmean(all_full_preds, axis=0) self._full_preds = full_preds scoring_fns = self.scoring_fns if isinstance(self.scoring_fns, dict) \ else {"importance": self.scoring_fns} for fn_name, scoring_fn in scoring_fns.items(): self.feature_importances_by_tree_[fn_name] = pd.concat([scores[fn_name] for scores in all_scores], axis=1) self.feature_importances_by_tree_[fn_name].columns = np.arange(len(all_scores)) self.feature_importances_[fn_name] = np.mean(self.feature_importances_by_tree_[fn_name], axis=1) self.prediction_score_[fn_name] = [scoring_fn(y[~np.isnan(full_preds)], full_preds[~np.isnan(full_preds)])] if list(scoring_fns.keys()) == ["importance"]: self.prediction_score_ = self.prediction_score_["importance"] self.feature_importances_by_tree_ = self.feature_importances_by_tree_["importance"] if isinstance(X, pd.DataFrame): self.feature_importances_.index = X.columns self.feature_importances_.index.name = 'var' self.feature_importances_.reset_index(inplace=True) self.is_fitted = TrueMethods
def get_scores(self, X, y)-
Obtain the MDI+ feature importances for a forest.
Parameters
X:ndarrayofshape (n_samples, n_features)- The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output
y:ndarrayofshape (n_samples, n_targets)- The observed responses.
Returns
scores:pd.DataFrameofshape (n_features, n_scoring_fns)- The MDI+ feature importances.
Expand source code
def get_scores(self, X, y): """ Obtain the MDI+ feature importances for a forest. Parameters ---------- X: ndarray of shape (n_samples, n_features) The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output y: ndarray of shape (n_samples, n_targets) The observed responses. Returns ------- scores: pd.DataFrame of shape (n_features, n_scoring_fns) The MDI+ feature importances. """ self._fit_importance_scores(X, y) return self.feature_importances_ def get_stability_scores(self, B=10, metrics='auto')-
Evaluate the stability of the MDI+ feature importance rankings across bootstrapped samples of trees. Can be used to select the GLM and scoring metric in a data-driven manner, where the GLM and metric that yields the most stable feature rankings across bootstrapped samples is selected.
Parameters
B:int- Number of bootstrap samples.
metrics:"auto"ora dict with functions as value and function name (str) as key- Metric(s) used to evaluate the stability between two sets of feature importances. If "auto", then the feature importance stability metrics are: (1) Rank-based overlap (RBO) with p=0.9 (from "A Similarity Measure for Indefinite Rankings" by Webber et al. (2010)). Intuitively, this metric gives more weight to features with the largest importances, with most of the weight going to the ~1/(1-p) features with the largest importances. (2) A weighted kendall tau metric (tauAP_b from "The Treatment of Ties in AP Correlation" by Urbano and Marrero (2017)), which also gives more weight to the features with the largest importances, but uses a different weighting scheme from RBO. Note that these default metrics assume that a higher MDI+ score indicates greater importance and thus give more weight to these features with high importance/ranks. If a lower MDI+ score indicates higher importance, then invert either these stability metrics or the MDI+ scores before evaluating the stability.
Returns
stability_results:pd.DataFrameofshape (n_features, n_metrics)- The stability scores of the MDI+ feature rankings across bootstrapped samples.
Expand source code
def get_stability_scores(self, B=10, metrics="auto"): """ Evaluate the stability of the MDI+ feature importance rankings across bootstrapped samples of trees. Can be used to select the GLM and scoring metric in a data-driven manner, where the GLM and metric that yields the most stable feature rankings across bootstrapped samples is selected. Parameters ---------- B: int Number of bootstrap samples. metrics: "auto" or a dict with functions as value and function name (str) as key Metric(s) used to evaluate the stability between two sets of feature importances. If "auto", then the feature importance stability metrics are: (1) Rank-based overlap (RBO) with p=0.9 (from "A Similarity Measure for Indefinite Rankings" by Webber et al. (2010)). Intuitively, this metric gives more weight to features with the largest importances, with most of the weight going to the ~1/(1-p) features with the largest importances. (2) A weighted kendall tau metric (tauAP_b from "The Treatment of Ties in AP Correlation" by Urbano and Marrero (2017)), which also gives more weight to the features with the largest importances, but uses a different weighting scheme from RBO. Note that these default metrics assume that a higher MDI+ score indicates greater importance and thus give more weight to these features with high importance/ranks. If a lower MDI+ score indicates higher importance, then invert either these stability metrics or the MDI+ scores before evaluating the stability. Returns ------- stability_results: pd.DataFrame of shape (n_features, n_metrics) The stability scores of the MDI+ feature rankings across bootstrapped samples. """ if metrics == "auto": metrics = {"RBO": partial(rbo, p=0.9), "tauAP": tauAP_b} elif not isinstance(metrics, dict): raise ValueError("`metrics` must be 'auto' or a dictionary " "where the key is the metric name and the value is the evaluation function") single_scoring_fn = not isinstance(self.feature_importances_by_tree_, dict) if single_scoring_fn: feature_importances_dict = {"mdi_plus_score": self.feature_importances_by_tree_} else: feature_importances_dict = self.feature_importances_by_tree_ stability_dict = {} for scoring_fn_name, feature_importances_by_tree in feature_importances_dict.items(): n_trees = feature_importances_by_tree.shape[1] fi_scores_boot_ls = [] for b in range(B): bootstrap_sample = np.random.choice(n_trees, n_trees, replace=True) fi_scores_boot_ls.append(feature_importances_by_tree[bootstrap_sample].mean(axis=1)) fi_scores_boot = pd.concat(fi_scores_boot_ls, axis=1) stability_results = {"scorer": [scoring_fn_name]} for metric_name, metric_fun in metrics.items(): stability_results[metric_name] = [np.mean(pdist(fi_scores_boot.T, metric=metric_fun))] stability_dict[scoring_fn_name] = pd.DataFrame(stability_results) stability_df = pd.concat(stability_dict, axis=0).reset_index(drop=True) if single_scoring_fn: stability_df = stability_df.drop(columns=["scorer"]) return stability_df
class GenericClassifierPPM (estimator)-
Partial prediction model for arbitrary classification estimators. May be slow.
Expand source code
class GenericClassifierPPM(_GenericPPM, PartialPredictionModelBase, ABC): """ Partial prediction model for arbitrary classification estimators. May be slow. """ def predict_proba(self, X): return self.estimator.predict_proba(X) def predict_partial_k(self, blocked_data, k, mode): modified_data = blocked_data.get_modified_data(k, mode) return self.predict_proba(modified_data)Ancestors
- imodels.importance.ppms._GenericPPM
- PartialPredictionModelBase
- abc.ABC
Methods
def predict_proba(self, X)-
Expand source code
def predict_proba(self, X): return self.estimator.predict_proba(X)
Inherited members
class GenericRegressorPPM (estimator)-
Partial prediction model for arbitrary regression estimators. May be slow.
Expand source code
class GenericRegressorPPM(_GenericPPM, PartialPredictionModelBase, ABC): """ Partial prediction model for arbitrary regression estimators. May be slow. """ ...Ancestors
- imodels.importance.ppms._GenericPPM
- PartialPredictionModelBase
- abc.ABC
Inherited members
class GlmClassifierPPM (estimator, loo=True, alpha_grid=array([1.00000000e-04, 7.74263683e-04, 5.99484250e-03, 4.64158883e-02, 3.59381366e-01, 2.78255940e+00, 2.15443469e+01, 1.66810054e+02, 1.29154967e+03, 1.00000000e+04]), inv_link_fn=<function _GlmPPM.<lambda>>, l_dot=<function _GlmPPM.<lambda>>, l_doubledot=<function _GlmPPM.<lambda>>, r_doubledot=<function _GlmPPM.<lambda>>, hyperparameter_scorer=<function mean_squared_error>, trim=None, gcv_mode='auto')-
PPM class for GLM classification estimator.
Expand source code
class GlmClassifierPPM(_GlmPPM, PartialPredictionModelBase, ABC): """ PPM class for GLM classification estimator. """ def predict_proba(self, X): probs = self.predict(X) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs def predict_proba_loo(self, X): probs = self.predict_loo(X) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probsAncestors
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Subclasses
Methods
def predict_proba(self, X)-
Expand source code
def predict_proba(self, X): probs = self.predict(X) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs def predict_proba_loo(self, X)-
Expand source code
def predict_proba_loo(self, X): probs = self.predict_loo(X) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs
Inherited members
class GlmRegressorPPM (estimator, loo=True, alpha_grid=array([1.00000000e-04, 7.74263683e-04, 5.99484250e-03, 4.64158883e-02, 3.59381366e-01, 2.78255940e+00, 2.15443469e+01, 1.66810054e+02, 1.29154967e+03, 1.00000000e+04]), inv_link_fn=<function _GlmPPM.<lambda>>, l_dot=<function _GlmPPM.<lambda>>, l_doubledot=<function _GlmPPM.<lambda>>, r_doubledot=<function _GlmPPM.<lambda>>, hyperparameter_scorer=<function mean_squared_error>, trim=None, gcv_mode='auto')-
PPM class for GLM regression estimator.
Expand source code
class GlmRegressorPPM(_GlmPPM, PartialPredictionModelBase, ABC): """ PPM class for GLM regression estimator. """ ...Ancestors
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Subclasses
Inherited members
class IdentityTransformer-
Block transformer that creates a block partitioned data object with each block k containing only the original feature k.
Expand source code
class IdentityTransformer(BlockTransformerBase, ABC): """ Block transformer that creates a block partitioned data object with each block k containing only the original feature k. """ def _fit_one_feature(self, X, k): self._centers[k] = np.mean(X[:, [k]]) self._scales[k] = np.std(X[:, [k]]) def _transform_one_feature(self, X, k): return X[:, [k]]Ancestors
- BlockTransformerBase
- abc.ABC
Inherited members
class LassoRegressorPPM (loo=True, alpha_grid=array([1.00000000e-02, 1.61559810e-02, 2.61015722e-02, 4.21696503e-02, 6.81292069e-02, 1.10069417e-01, 1.77827941e-01, 2.87298483e-01, 4.64158883e-01, 7.49894209e-01, 1.21152766e+00, 1.95734178e+00, 3.16227766e+00, 5.10896977e+00, 8.25404185e+00, 1.33352143e+01, 2.15443469e+01, 3.48070059e+01, 5.62341325e+01, 9.08517576e+01, 1.46779927e+02, 2.37137371e+02, 3.83118685e+02, 6.18965819e+02, 1.00000000e+03]), **kwargs)-
PPM class for regression that uses lasso as the estimator.
Parameters
loo:bool- Flag for whether to also use LOO calculations for making predictions.
alpha_grid:ndarrayofshape (n_alphas, )- The grid of alpha values for hyperparameter optimization.
**kwargs- Other Parameters are passed on to Lasso().
Expand source code
class LassoRegressorPPM(GlmRegressorPPM, PartialPredictionModelBase, ABC): """ PPM class for regression that uses lasso as the estimator. Parameters ---------- loo: bool Flag for whether to also use LOO calculations for making predictions. alpha_grid: ndarray of shape (n_alphas, ) The grid of alpha values for hyperparameter optimization. **kwargs Other Parameters are passed on to Lasso(). """ def __init__(self, loo=True, alpha_grid=np.logspace(-2, 3, 25), **kwargs): super().__init__(Lasso(**kwargs), loo, alpha_grid, r_doubledot=None)Ancestors
- GlmRegressorPPM
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Inherited members
class LogisticClassifierPPM (loo=True, alpha_grid=array([1.00000000e-02, 1.61559810e-02, 2.61015722e-02, 4.21696503e-02, 6.81292069e-02, 1.10069417e-01, 1.77827941e-01, 2.87298483e-01, 4.64158883e-01, 7.49894209e-01, 1.21152766e+00, 1.95734178e+00, 3.16227766e+00, 5.10896977e+00, 8.25404185e+00, 1.33352143e+01, 2.15443469e+01, 3.48070059e+01, 5.62341325e+01, 9.08517576e+01, 1.46779927e+02, 2.37137371e+02, 3.83118685e+02, 6.18965819e+02, 1.00000000e+03]), penalty='l2', max_iter=1000, trim=0.01, **kwargs)-
PPM class for classification that uses logistic regression as the estimator.
Parameters
loo:bool- Flag for whether to also use LOO calculations for making predictions.
alpha_grid:ndarrayofshape (n_alphas, )- The grid of alpha values for hyperparameter optimization.
max_iter:int- The maximum number of iterations for the LogisticRegression solver.
trim:float- The amount by which to trim predicted probabilities away from 0 and 1. This helps to stabilize some loss calculations.
**kwargs- Other Parameters are passed on to LogisticRegression().
Expand source code
class LogisticClassifierPPM(GlmClassifierPPM, PartialPredictionModelBase, ABC): """ PPM class for classification that uses logistic regression as the estimator. Parameters ---------- loo: bool Flag for whether to also use LOO calculations for making predictions. alpha_grid: ndarray of shape (n_alphas, ) The grid of alpha values for hyperparameter optimization. max_iter: int The maximum number of iterations for the LogisticRegression solver. trim: float The amount by which to trim predicted probabilities away from 0 and 1. This helps to stabilize some loss calculations. **kwargs Other Parameters are passed on to LogisticRegression(). """ def __init__(self, loo=True, alpha_grid=np.logspace(-2, 3, 25), penalty='l2', max_iter=1000, trim=0.01, **kwargs): assert penalty in ['l2', 'l1'] if penalty == 'l2': r_doubledot = lambda a: 1 elif penalty == 'l1': r_doubledot = None super().__init__(LogisticRegression(penalty=penalty, max_iter=max_iter, **kwargs), loo, alpha_grid, inv_link_fn=sp.special.expit, l_doubledot=lambda a, b: b * (1 - b), r_doubledot=r_doubledot, hyperparameter_scorer=log_loss, trim=trim)Ancestors
- GlmClassifierPPM
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Inherited members
class MDIPlusDefaultTransformer (tree_model, rescale_mode='max', drop_features=True)-
Default block transformer used in MDI+. For each original feature, this forms a block comprising the local decision stumps, from a single tree model, that split on the feature, and appends the original feature.
Parameters
tree_model:scikit-learn estimator- The scikit-learn tree estimator object.
rescale_mode:string in {"max", "mean", None}- Flag for the type of rescaling to be done to the blocks from different base transformers. If "max", divide each block by the max std deviation of a column within the block. If "mean", divide each block by the mean std deviation of a column within the block. If None, do not rescale.
drop_features:bool- Flag for whether to return an empty block if that from the first transformer in the list is trivial.
Expand source code
class MDIPlusDefaultTransformer(CompositeTransformer, ABC): """ Default block transformer used in MDI+. For each original feature, this forms a block comprising the local decision stumps, from a single tree model, that split on the feature, and appends the original feature. Parameters ---------- tree_model: scikit-learn estimator The scikit-learn tree estimator object. rescale_mode: string in {"max", "mean", None} Flag for the type of rescaling to be done to the blocks from different base transformers. If "max", divide each block by the max std deviation of a column within the block. If "mean", divide each block by the mean std deviation of a column within the block. If None, do not rescale. drop_features: bool Flag for whether to return an empty block if that from the first transformer in the list is trivial. """ def __init__(self, tree_model, rescale_mode="max", drop_features=True): super().__init__([TreeTransformer(tree_model), IdentityTransformer()], rescale_mode, drop_features)Ancestors
Inherited members
class RandomForestPlusClassifier (rf_model=None, prediction_model=None, sample_split='auto', include_raw=True, drop_features=True, add_transformers=None, center=True, normalize=False)-
The class object for the Random Forest Plus (RF+) classification estimator, which can be used as a prediction model or interpreted via generalized mean decrease in impurity (MDI+). For more details, refer to [paper].
Expand source code
class RandomForestPlusClassifier(_RandomForestPlus, ClassifierMixin): """ The class object for the Random Forest Plus (RF+) classification estimator, which can be used as a prediction model or interpreted via generalized mean decrease in impurity (MDI+). For more details, refer to [paper]. """ ...Ancestors
- imodels.importance.rf_plus._RandomForestPlus
- sklearn.base.BaseEstimator
- sklearn.utils._estimator_html_repr._HTMLDocumentationLinkMixin
- sklearn.utils._metadata_requests._MetadataRequester
- sklearn.base.ClassifierMixin
Methods
def set_fit_request(self: RandomForestPlusClassifier, *, sample_weight: bool | str | None = '$UNCHANGED$') ‑> RandomForestPlusClassifier-
Request metadata passed to the
fitmethod.Note that this method is only relevant if
enable_metadata_routing=True(see :func:sklearn.set_config). Please see :ref:User Guide <metadata_routing>on how the routing mechanism works.The options for each parameter are:
-
True: metadata is requested, and passed tofitif provided. The request is ignored if metadata is not provided. -
False: metadata is not requested and the meta-estimator will not pass it tofit. -
None: metadata is not requested, and the meta-estimator will raise an error if the user provides it. -
str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version: 1.3
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a :class:
~sklearn.pipeline.Pipeline. Otherwise it has no effect.Parameters
sample_weight:str, True, False,orNone, default=sklearn.utils.metadata_routing.UNCHANGED- Metadata routing for
sample_weightparameter infit.
Returns
self:object- The updated object.
Expand source code
def func(*args, **kw): """Updates the request for provided parameters This docstring is overwritten below. See REQUESTER_DOC for expected functionality """ if not _routing_enabled(): raise RuntimeError( "This method is only available when metadata routing is enabled." " You can enable it using" " sklearn.set_config(enable_metadata_routing=True)." ) if self.validate_keys and (set(kw) - set(self.keys)): raise TypeError( f"Unexpected args: {set(kw) - set(self.keys)} in {self.name}. " f"Accepted arguments are: {set(self.keys)}" ) # This makes it possible to use the decorated method as an unbound method, # for instance when monkeypatching. # https://github.com/scikit-learn/scikit-learn/issues/28632 if instance is None: _instance = args[0] args = args[1:] else: _instance = instance # Replicating python's behavior when positional args are given other than # `self`, and `self` is only allowed if this method is unbound. if args: raise TypeError( f"set_{self.name}_request() takes 0 positional argument but" f" {len(args)} were given" ) requests = _instance._get_metadata_request() method_metadata_request = getattr(requests, self.name) for prop, alias in kw.items(): if alias is not UNCHANGED: method_metadata_request.add_request(param=prop, alias=alias) _instance._metadata_request = requests return _instance -
def set_score_request(self: RandomForestPlusClassifier, *, sample_weight: bool | str | None = '$UNCHANGED$') ‑> RandomForestPlusClassifier-
Request metadata passed to the
scoremethod.Note that this method is only relevant if
enable_metadata_routing=True(see :func:sklearn.set_config). Please see :ref:User Guide <metadata_routing>on how the routing mechanism works.The options for each parameter are:
-
True: metadata is requested, and passed toscoreif provided. The request is ignored if metadata is not provided. -
False: metadata is not requested and the meta-estimator will not pass it toscore. -
None: metadata is not requested, and the meta-estimator will raise an error if the user provides it. -
str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version: 1.3
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a :class:
~sklearn.pipeline.Pipeline. Otherwise it has no effect.Parameters
sample_weight:str, True, False,orNone, default=sklearn.utils.metadata_routing.UNCHANGED- Metadata routing for
sample_weightparameter inscore.
Returns
self:object- The updated object.
Expand source code
def func(*args, **kw): """Updates the request for provided parameters This docstring is overwritten below. See REQUESTER_DOC for expected functionality """ if not _routing_enabled(): raise RuntimeError( "This method is only available when metadata routing is enabled." " You can enable it using" " sklearn.set_config(enable_metadata_routing=True)." ) if self.validate_keys and (set(kw) - set(self.keys)): raise TypeError( f"Unexpected args: {set(kw) - set(self.keys)} in {self.name}. " f"Accepted arguments are: {set(self.keys)}" ) # This makes it possible to use the decorated method as an unbound method, # for instance when monkeypatching. # https://github.com/scikit-learn/scikit-learn/issues/28632 if instance is None: _instance = args[0] args = args[1:] else: _instance = instance # Replicating python's behavior when positional args are given other than # `self`, and `self` is only allowed if this method is unbound. if args: raise TypeError( f"set_{self.name}_request() takes 0 positional argument but" f" {len(args)} were given" ) requests = _instance._get_metadata_request() method_metadata_request = getattr(requests, self.name) for prop, alias in kw.items(): if alias is not UNCHANGED: method_metadata_request.add_request(param=prop, alias=alias) _instance._metadata_request = requests return _instance -
class RandomForestPlusRegressor (rf_model=None, prediction_model=None, sample_split='auto', include_raw=True, drop_features=True, add_transformers=None, center=True, normalize=False)-
The class object for the Random Forest Plus (RF+) regression estimator, which can be used as a prediction model or interpreted via generalized mean decrease in impurity (MDI+). For more details, refer to [paper].
Expand source code
class RandomForestPlusRegressor(_RandomForestPlus, RegressorMixin): """ The class object for the Random Forest Plus (RF+) regression estimator, which can be used as a prediction model or interpreted via generalized mean decrease in impurity (MDI+). For more details, refer to [paper]. """ ...Ancestors
- imodels.importance.rf_plus._RandomForestPlus
- sklearn.base.BaseEstimator
- sklearn.utils._estimator_html_repr._HTMLDocumentationLinkMixin
- sklearn.utils._metadata_requests._MetadataRequester
- sklearn.base.RegressorMixin
Methods
def set_fit_request(self: RandomForestPlusRegressor, *, sample_weight: bool | str | None = '$UNCHANGED$') ‑> RandomForestPlusRegressor-
Request metadata passed to the
fitmethod.Note that this method is only relevant if
enable_metadata_routing=True(see :func:sklearn.set_config). Please see :ref:User Guide <metadata_routing>on how the routing mechanism works.The options for each parameter are:
-
True: metadata is requested, and passed tofitif provided. The request is ignored if metadata is not provided. -
False: metadata is not requested and the meta-estimator will not pass it tofit. -
None: metadata is not requested, and the meta-estimator will raise an error if the user provides it. -
str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version: 1.3
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a :class:
~sklearn.pipeline.Pipeline. Otherwise it has no effect.Parameters
sample_weight:str, True, False,orNone, default=sklearn.utils.metadata_routing.UNCHANGED- Metadata routing for
sample_weightparameter infit.
Returns
self:object- The updated object.
Expand source code
def func(*args, **kw): """Updates the request for provided parameters This docstring is overwritten below. See REQUESTER_DOC for expected functionality """ if not _routing_enabled(): raise RuntimeError( "This method is only available when metadata routing is enabled." " You can enable it using" " sklearn.set_config(enable_metadata_routing=True)." ) if self.validate_keys and (set(kw) - set(self.keys)): raise TypeError( f"Unexpected args: {set(kw) - set(self.keys)} in {self.name}. " f"Accepted arguments are: {set(self.keys)}" ) # This makes it possible to use the decorated method as an unbound method, # for instance when monkeypatching. # https://github.com/scikit-learn/scikit-learn/issues/28632 if instance is None: _instance = args[0] args = args[1:] else: _instance = instance # Replicating python's behavior when positional args are given other than # `self`, and `self` is only allowed if this method is unbound. if args: raise TypeError( f"set_{self.name}_request() takes 0 positional argument but" f" {len(args)} were given" ) requests = _instance._get_metadata_request() method_metadata_request = getattr(requests, self.name) for prop, alias in kw.items(): if alias is not UNCHANGED: method_metadata_request.add_request(param=prop, alias=alias) _instance._metadata_request = requests return _instance -
def set_score_request(self: RandomForestPlusRegressor, *, sample_weight: bool | str | None = '$UNCHANGED$') ‑> RandomForestPlusRegressor-
Request metadata passed to the
scoremethod.Note that this method is only relevant if
enable_metadata_routing=True(see :func:sklearn.set_config). Please see :ref:User Guide <metadata_routing>on how the routing mechanism works.The options for each parameter are:
-
True: metadata is requested, and passed toscoreif provided. The request is ignored if metadata is not provided. -
False: metadata is not requested and the meta-estimator will not pass it toscore. -
None: metadata is not requested, and the meta-estimator will raise an error if the user provides it. -
str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version: 1.3
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a :class:
~sklearn.pipeline.Pipeline. Otherwise it has no effect.Parameters
sample_weight:str, True, False,orNone, default=sklearn.utils.metadata_routing.UNCHANGED- Metadata routing for
sample_weightparameter inscore.
Returns
self:object- The updated object.
Expand source code
def func(*args, **kw): """Updates the request for provided parameters This docstring is overwritten below. See REQUESTER_DOC for expected functionality """ if not _routing_enabled(): raise RuntimeError( "This method is only available when metadata routing is enabled." " You can enable it using" " sklearn.set_config(enable_metadata_routing=True)." ) if self.validate_keys and (set(kw) - set(self.keys)): raise TypeError( f"Unexpected args: {set(kw) - set(self.keys)} in {self.name}. " f"Accepted arguments are: {set(self.keys)}" ) # This makes it possible to use the decorated method as an unbound method, # for instance when monkeypatching. # https://github.com/scikit-learn/scikit-learn/issues/28632 if instance is None: _instance = args[0] args = args[1:] else: _instance = instance # Replicating python's behavior when positional args are given other than # `self`, and `self` is only allowed if this method is unbound. if args: raise TypeError( f"set_{self.name}_request() takes 0 positional argument but" f" {len(args)} were given" ) requests = _instance._get_metadata_request() method_metadata_request = getattr(requests, self.name) for prop, alias in kw.items(): if alias is not UNCHANGED: method_metadata_request.add_request(param=prop, alias=alias) _instance._metadata_request = requests return _instance -
class RidgeClassifierPPM (loo=True, alpha_grid=array([1.00000000e-05, 1.26185688e-05, 1.59228279e-05, 2.00923300e-05, 2.53536449e-05, 3.19926714e-05, 4.03701726e-05, 5.09413801e-05, 6.42807312e-05, 8.11130831e-05, 1.02353102e-04, 1.29154967e-04, 1.62975083e-04, 2.05651231e-04, 2.59502421e-04, 3.27454916e-04, 4.13201240e-04, 5.21400829e-04, 6.57933225e-04, 8.30217568e-04, 1.04761575e-03, 1.32194115e-03, 1.66810054e-03, 2.10490414e-03, 2.65608778e-03, 3.35160265e-03, 4.22924287e-03, 5.33669923e-03, 6.73415066e-03, 8.49753436e-03, 1.07226722e-02, 1.35304777e-02, 1.70735265e-02, 2.15443469e-02, 2.71858824e-02, 3.43046929e-02, 4.32876128e-02, 5.46227722e-02, 6.89261210e-02, 8.69749003e-02, 1.09749877e-01, 1.38488637e-01, 1.74752840e-01, 2.20513074e-01, 2.78255940e-01, 3.51119173e-01, 4.43062146e-01, 5.59081018e-01, 7.05480231e-01, 8.90215085e-01, 1.12332403e+00, 1.41747416e+00, 1.78864953e+00, 2.25701972e+00, 2.84803587e+00, 3.59381366e+00, 4.53487851e+00, 5.72236766e+00, 7.22080902e+00, 9.11162756e+00, 1.14975700e+01, 1.45082878e+01, 1.83073828e+01, 2.31012970e+01, 2.91505306e+01, 3.67837977e+01, 4.64158883e+01, 5.85702082e+01, 7.39072203e+01, 9.32603347e+01, 1.17681195e+02, 1.48496826e+02, 1.87381742e+02, 2.36448941e+02, 2.98364724e+02, 3.76493581e+02, 4.75081016e+02, 5.99484250e+02, 7.56463328e+02, 9.54548457e+02, 1.20450354e+03, 1.51991108e+03, 1.91791026e+03, 2.42012826e+03, 3.05385551e+03, 3.85352859e+03, 4.86260158e+03, 6.13590727e+03, 7.74263683e+03, 9.77009957e+03, 1.23284674e+04, 1.55567614e+04, 1.96304065e+04, 2.47707636e+04, 3.12571585e+04, 3.94420606e+04, 4.97702356e+04, 6.28029144e+04, 7.92482898e+04, 1.00000000e+05]), gcv_mode='auto', **kwargs)-
PPM class for classification that uses ridge as the GLM estimator.
Expand source code
class RidgeClassifierPPM(_RidgePPM, GlmClassifierPPM, PartialPredictionModelBase, ABC): """ PPM class for classification that uses ridge as the GLM estimator. """ def predict_proba(self, X): probs = softmax(self.predict(X)) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs def predict_proba_loo(self, X): probs = softmax(self.predict_loo(X)) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probsAncestors
- imodels.importance.ppms._RidgePPM
- GlmClassifierPPM
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Methods
def predict_proba(self, X)-
Expand source code
def predict_proba(self, X): probs = softmax(self.predict(X)) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs def predict_proba_loo(self, X)-
Expand source code
def predict_proba_loo(self, X): probs = softmax(self.predict_loo(X)) if probs.ndim == 1: probs = np.stack([1 - probs, probs], axis=1) return probs
Inherited members
class RidgeRegressorPPM (loo=True, alpha_grid=array([1.00000000e-05, 1.26185688e-05, 1.59228279e-05, 2.00923300e-05, 2.53536449e-05, 3.19926714e-05, 4.03701726e-05, 5.09413801e-05, 6.42807312e-05, 8.11130831e-05, 1.02353102e-04, 1.29154967e-04, 1.62975083e-04, 2.05651231e-04, 2.59502421e-04, 3.27454916e-04, 4.13201240e-04, 5.21400829e-04, 6.57933225e-04, 8.30217568e-04, 1.04761575e-03, 1.32194115e-03, 1.66810054e-03, 2.10490414e-03, 2.65608778e-03, 3.35160265e-03, 4.22924287e-03, 5.33669923e-03, 6.73415066e-03, 8.49753436e-03, 1.07226722e-02, 1.35304777e-02, 1.70735265e-02, 2.15443469e-02, 2.71858824e-02, 3.43046929e-02, 4.32876128e-02, 5.46227722e-02, 6.89261210e-02, 8.69749003e-02, 1.09749877e-01, 1.38488637e-01, 1.74752840e-01, 2.20513074e-01, 2.78255940e-01, 3.51119173e-01, 4.43062146e-01, 5.59081018e-01, 7.05480231e-01, 8.90215085e-01, 1.12332403e+00, 1.41747416e+00, 1.78864953e+00, 2.25701972e+00, 2.84803587e+00, 3.59381366e+00, 4.53487851e+00, 5.72236766e+00, 7.22080902e+00, 9.11162756e+00, 1.14975700e+01, 1.45082878e+01, 1.83073828e+01, 2.31012970e+01, 2.91505306e+01, 3.67837977e+01, 4.64158883e+01, 5.85702082e+01, 7.39072203e+01, 9.32603347e+01, 1.17681195e+02, 1.48496826e+02, 1.87381742e+02, 2.36448941e+02, 2.98364724e+02, 3.76493581e+02, 4.75081016e+02, 5.99484250e+02, 7.56463328e+02, 9.54548457e+02, 1.20450354e+03, 1.51991108e+03, 1.91791026e+03, 2.42012826e+03, 3.05385551e+03, 3.85352859e+03, 4.86260158e+03, 6.13590727e+03, 7.74263683e+03, 9.77009957e+03, 1.23284674e+04, 1.55567614e+04, 1.96304065e+04, 2.47707636e+04, 3.12571585e+04, 3.94420606e+04, 4.97702356e+04, 6.28029144e+04, 7.92482898e+04, 1.00000000e+05]), gcv_mode='auto', **kwargs)-
PPM class for regression that uses ridge as the GLM estimator.
Expand source code
class RidgeRegressorPPM(_RidgePPM, GlmRegressorPPM, PartialPredictionModelBase, ABC): """ PPM class for regression that uses ridge as the GLM estimator. """ ...Ancestors
- imodels.importance.ppms._RidgePPM
- GlmRegressorPPM
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Inherited members
class RobustRegressorPPM (loo=True, alpha_grid=array([1.00000000e-02, 1.61559810e-02, 2.61015722e-02, 4.21696503e-02, 6.81292069e-02, 1.10069417e-01, 1.77827941e-01, 2.87298483e-01, 4.64158883e-01, 7.49894209e-01, 1.21152766e+00, 1.95734178e+00, 3.16227766e+00, 5.10896977e+00, 8.25404185e+00, 1.33352143e+01, 2.15443469e+01, 3.48070059e+01, 5.62341325e+01, 9.08517576e+01, 1.46779927e+02, 2.37137371e+02, 3.83118685e+02, 6.18965819e+02, 1.00000000e+03]), epsilon=1.35, max_iter=2000, **kwargs)-
PPM class for regression that uses Huber robust regression as the estimator.
Parameters
loo:bool- Flag for whether to also use LOO calculations for making predictions.
alpha_grid:ndarrayofshape (n_alphas, )- The grid of alpha values for hyperparameter optimization.
epsilon:float- The robustness parameter for Huber regression. The smaller the epsilon, the more robust it is to outliers. Epsilon must be in the range [1, inf).
**kwargs- Other Parameters are passed on to LogisticRegression().
Expand source code
class RobustRegressorPPM(GlmRegressorPPM, PartialPredictionModelBase, ABC): """ PPM class for regression that uses Huber robust regression as the estimator. Parameters ---------- loo: bool Flag for whether to also use LOO calculations for making predictions. alpha_grid: ndarray of shape (n_alphas, ) The grid of alpha values for hyperparameter optimization. epsilon: float The robustness parameter for Huber regression. The smaller the epsilon, the more robust it is to outliers. Epsilon must be in the range [1, inf). **kwargs Other Parameters are passed on to LogisticRegression(). """ def __init__(self, loo=True, alpha_grid=np.logspace(-2, 3, 25), epsilon=1.35, max_iter=2000, **kwargs): loss_fn = partial(huber_loss, epsilon=epsilon) l_dot = lambda a, b: (b - a) / (1 + ((a - b) / epsilon) ** 2) ** 0.5 l_doubledot=lambda a, b: (1 + (((a - b) / epsilon) ** 2)) ** (-1.5) super().__init__( HuberRegressor(max_iter=max_iter, **kwargs), loo, alpha_grid, l_dot=l_dot, l_doubledot=l_doubledot, hyperparameter_scorer=loss_fn)Ancestors
- GlmRegressorPPM
- imodels.importance.ppms._GlmPPM
- PartialPredictionModelBase
- abc.ABC
Inherited members
class TreeMDIPlus (estimator, transformer, scoring_fns, sample_split='loo', tree_random_state=None, mode='keep_k', task='regression', center=True, normalize=False)-
The class object for computing MDI+ feature importances for a single tree. Generalized mean decrease in impurity (MDI+) is a flexible framework for computing RF feature importances. For more details, refer to [paper].
Parameters
estimator:a fitted PartialPredictionModelBase objectorscikit-learn type estimator- The fitted partial prediction model to use for evaluating feature importance via MDI+. If not a PartialPredictionModelBase, then the estimator is coerced into a PartialPredictionModelBase object via GenericRegressorPPM or GenericClassifierPPM depending on the specified task. Note that these generic PPMs may be computationally expensive.
transformer:a BlockTransformerBase object- A block feature transformer used to generate blocks of engineered features for each original feature. The transformed data is then used as input into the partial prediction models.
scoring_fns:a functionordict with functions as value and function name (str) as key- The scoring functions used for evaluating the partial predictions.
sample_split:string in {"loo", "oob", "inbag"}orNone- The sample splitting strategy to be used when evaluating the partial model predictions. The default "loo" (leave-one-out) is strongly recommended for performance and in particular, for overcoming the known correlation and entropy biases suffered by MDI. "oob" (out-of-bag) can also be used to overcome these biases. "inbag" is the sample splitting strategy used by MDI. If None, no sample splitting is performed and the full data set is used to evaluate the partial model predictions.
tree_random_state:intorNone- Random state of the fitted tree; used in sample splitting and only required if sample_split = "oob" or "inbag".
mode:string in {"keep_k", "keep_rest"}- Mode for the method. "keep_k" imputes the mean of each feature not in block k when making a partial model prediction, while "keep_rest" imputes the mean of each feature in block k. "keep_k" is strongly recommended for computational considerations.
task:string in {"regression", "classification"}- The supervised learning task for the RF model. Used for choosing defaults for the scoring_fns. Currently only regression and classification are supported.
center:bool- Flag for whether to center the transformed data in the transformers.
normalize:bool- Flag for whether to rescale the transformed data to have unit variance in the transformers.
Expand source code
class TreeMDIPlus: """ The class object for computing MDI+ feature importances for a single tree. Generalized mean decrease in impurity (MDI+) is a flexible framework for computing RF feature importances. For more details, refer to [paper]. Parameters ---------- estimator: a fitted PartialPredictionModelBase object or scikit-learn type estimator The fitted partial prediction model to use for evaluating feature importance via MDI+. If not a PartialPredictionModelBase, then the estimator is coerced into a PartialPredictionModelBase object via GenericRegressorPPM or GenericClassifierPPM depending on the specified task. Note that these generic PPMs may be computationally expensive. transformer: a BlockTransformerBase object A block feature transformer used to generate blocks of engineered features for each original feature. The transformed data is then used as input into the partial prediction models. scoring_fns: a function or dict with functions as value and function name (str) as key The scoring functions used for evaluating the partial predictions. sample_split: string in {"loo", "oob", "inbag"} or None The sample splitting strategy to be used when evaluating the partial model predictions. The default "loo" (leave-one-out) is strongly recommended for performance and in particular, for overcoming the known correlation and entropy biases suffered by MDI. "oob" (out-of-bag) can also be used to overcome these biases. "inbag" is the sample splitting strategy used by MDI. If None, no sample splitting is performed and the full data set is used to evaluate the partial model predictions. tree_random_state: int or None Random state of the fitted tree; used in sample splitting and only required if sample_split = "oob" or "inbag". mode: string in {"keep_k", "keep_rest"} Mode for the method. "keep_k" imputes the mean of each feature not in block k when making a partial model prediction, while "keep_rest" imputes the mean of each feature in block k. "keep_k" is strongly recommended for computational considerations. task: string in {"regression", "classification"} The supervised learning task for the RF model. Used for choosing defaults for the scoring_fns. Currently only regression and classification are supported. center: bool Flag for whether to center the transformed data in the transformers. normalize: bool Flag for whether to rescale the transformed data to have unit variance in the transformers. """ def __init__(self, estimator, transformer, scoring_fns, sample_split="loo", tree_random_state=None, mode="keep_k", task="regression", center=True, normalize=False): assert sample_split in ["loo", "oob", "inbag", "auto", None] assert mode in ["keep_k", "keep_rest"] assert task in ["regression", "classification"] self.estimator = estimator self.transformer = transformer self.scoring_fns = scoring_fns self.sample_split = sample_split self.tree_random_state = tree_random_state _validate_sample_split(self.sample_split, self.estimator, isinstance(self.estimator, PartialPredictionModelBase)) if self.sample_split in ["oob", "inbag"] and not self.tree_random_state: raise ValueError("Must specify tree_random_state to use 'oob' or 'inbag' sample_split.") self.mode = mode self.task = task self.center = center self.normalize = normalize self.is_fitted = False self._full_preds = None self.prediction_score_ = None self.feature_importances_ = None def get_scores(self, X, y): """ Obtain the MDI+ feature importances for a single tree. Parameters ---------- X: ndarray of shape (n_samples, n_features) The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output y: ndarray of shape (n_samples, n_targets) The observed responses. Returns ------- scores: pd.DataFrame of shape (n_features, n_scoring_fns) The MDI+ feature importances. """ self._fit_importance_scores(X, y) return self.feature_importances_ def _fit_importance_scores(self, X, y): n_samples = y.shape[0] blocked_data = self.transformer.transform(X, center=self.center, normalize=self.normalize) self.n_features = blocked_data.n_blocks train_blocked_data, test_blocked_data, y_train, y_test, test_indices = \ _get_sample_split_data(blocked_data, y, self.tree_random_state, self.sample_split) if train_blocked_data.get_all_data().shape[1] != 0: if hasattr(self.estimator, "predict_full") and \ hasattr(self.estimator, "predict_partial"): full_preds = self.estimator.predict_full(test_blocked_data) partial_preds = self.estimator.predict_partial(test_blocked_data, mode=self.mode) else: if self.task == "regression": ppm = GenericRegressorPPM(self.estimator) elif self.task == "classification": ppm = GenericClassifierPPM(self.estimator) full_preds = ppm.predict_full(test_blocked_data) partial_preds = ppm.predict_partial(test_blocked_data, mode=self.mode) self._score_full_predictions(y_test, full_preds) self._score_partial_predictions(y_test, full_preds, partial_preds) full_preds_n = np.empty(n_samples) if full_preds.ndim == 1 \ else np.empty((n_samples, full_preds.shape[1])) full_preds_n[:] = np.nan full_preds_n[test_indices] = full_preds self._full_preds = full_preds_n self.is_fitted = True def _score_full_predictions(self, y_test, full_preds): scoring_fns = self.scoring_fns if isinstance(self.scoring_fns, dict) \ else {"score": self.scoring_fns} all_prediction_scores = pd.DataFrame({}) for fn_name, scoring_fn in scoring_fns.items(): scores = scoring_fn(y_test, full_preds) all_prediction_scores[fn_name] = [scores] self.prediction_score_ = all_prediction_scores def _score_partial_predictions(self, y_test, full_preds, partial_preds): scoring_fns = self.scoring_fns if isinstance(self.scoring_fns, dict) \ else {"importance": self.scoring_fns} all_scores = pd.DataFrame({}) for fn_name, scoring_fn in scoring_fns.items(): scores = _partial_preds_to_scores(partial_preds, y_test, scoring_fn) if self.mode == "keep_rest": full_score = scoring_fn(y_test, full_preds) scores = full_score - scores if len(partial_preds) != scores.size: if len(scoring_fns) > 1: msg = "scoring_fn={} should return one value for each feature.".format(fn_name) else: msg = "scoring_fns should return one value for each feature." raise ValueError("Unexpected dimensions. {}".format(msg)) scores = scores.ravel() all_scores[fn_name] = scores self.feature_importances_ = all_scoresMethods
def get_scores(self, X, y)-
Obtain the MDI+ feature importances for a single tree.
Parameters
X:ndarrayofshape (n_samples, n_features)- The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output
y:ndarrayofshape (n_samples, n_targets)- The observed responses.
Returns
scores:pd.DataFrameofshape (n_features, n_scoring_fns)- The MDI+ feature importances.
Expand source code
def get_scores(self, X, y): """ Obtain the MDI+ feature importances for a single tree. Parameters ---------- X: ndarray of shape (n_samples, n_features) The covariate matrix. If a pd.DataFrame object is supplied, then the column names are used in the output y: ndarray of shape (n_samples, n_targets) The observed responses. Returns ------- scores: pd.DataFrame of shape (n_features, n_scoring_fns) The MDI+ feature importances. """ self._fit_importance_scores(X, y) return self.feature_importances_
class TreeTransformer (estimator, data=None)-
A block transformer that transforms data using a representation built from local decision stumps from a tree or tree ensemble. The transformer also comes with metadata on the local decision stumps and methods that allow for transformations using sub-representations corresponding to each of the original features.
Parameters
estimator:scikit-learn estimator- The scikit-learn tree or tree ensemble estimator object.
data:ndarray- A data matrix that can be used to update the number of samples in each node of the tree(s) in the supplied estimator object. This affects the node values of the resulting engineered features.
Expand source code
class TreeTransformer(BlockTransformerBase, ABC): """ A block transformer that transforms data using a representation built from local decision stumps from a tree or tree ensemble. The transformer also comes with metadata on the local decision stumps and methods that allow for transformations using sub-representations corresponding to each of the original features. Parameters ---------- estimator: scikit-learn estimator The scikit-learn tree or tree ensemble estimator object. data: ndarray A data matrix that can be used to update the number of samples in each node of the tree(s) in the supplied estimator object. This affects the node values of the resulting engineered features. """ def __init__(self, estimator, data=None): super().__init__() self.estimator = estimator self.oob_seed = self.estimator.random_state # Check if single tree or tree ensemble if isinstance(estimator, BaseEnsemble): tree_models = estimator.estimators_ if data is not None: # If a data matrix is supplied, use it to update the number # of samples in each node for tree_model in tree_models: _update_n_node_samples(tree_model, data) else: tree_models = [estimator] # Make stumps for each tree all_stumps = [] for tree_model in tree_models: tree_stumps = make_stumps(tree_model.tree_) all_stumps += tree_stumps # Identify the stumps that split on feature k, for each k self.stumps = defaultdict(list) for stump in all_stumps: self.stumps[stump.feature].append(stump) self.n_splits = {k: len(stumps) for k, stumps in self.stumps.items()} def _fit_one_feature(self, X, k): stump_features = tree_feature_transform(self.stumps[k], X) self._centers[k] = np.mean(stump_features, axis=0) self._scales[k] = np.std(stump_features, axis=0) def _transform_one_feature(self, X, k): return tree_feature_transform(self.stumps[k], X) def _fit_transform_one_feature(self, X, k): stump_features = tree_feature_transform(self.stumps[k], X) self._centers[k] = np.mean(stump_features, axis=0) self._scales[k] = np.std(stump_features, axis=0) return stump_featuresAncestors
- BlockTransformerBase
- abc.ABC
Inherited members