Expand source code
import numpy as np
from typing import List

from imodels.rule_set.rule_fit import RuleFit
from imodels.util.score import score_linear
from sklearn.base import ClassifierMixin, RegressorMixin, BaseEstimator

from .util import extract_ensemble


class StableLinear(RuleFit):

    def __init__(self,
                 weak_learners: List[BaseEstimator],
                 max_complexity: int,
                 min_mult: int = 1,
                 penalty='l1',
                 n_estimators=100,
                 tree_size=4,
                 sample_fract='default',
                 max_rules=30,
                 memory_par=0.01,
                 tree_generator=None,
                 lin_trim_quantile=0.025,
                 lin_standardise=True,
                 exp_rand_tree_size=True,
                 include_linear=False,
                 alpha=None,
                 random_state=None):
        super().__init__(n_estimators,
                         tree_size,
                         sample_fract,
                         max_rules,
                         memory_par,
                         tree_generator,
                         lin_trim_quantile,
                         lin_standardise,
                         exp_rand_tree_size,
                         include_linear,
                         alpha,
                         random_state)
        self.max_complexity = max_complexity
        self.weak_learners = weak_learners
        self.penalty = penalty
        self.min_mult = min_mult

    def fit(self, X, y=None, feature_names=None):
        super().fit(X, y, feature_names=feature_names)
        return self

    def _extract_rules(self, X, y) -> List[str]:
        return extract_ensemble(self.weak_learners, X, y, self.min_mult)

    def _score_rules(self, X, y, rules):
        X_concat = np.zeros([X.shape[0], 0])

        # standardise linear variables if requested (for regression model only)
        if self.include_linear:

            # standard deviation and mean of winsorized features
            self.winsorizer.train(X)
            winsorized_X = self.winsorizer.trim(X)
            self.stddev = np.std(winsorized_X, axis=0)
            self.mean = np.mean(winsorized_X, axis=0)

            if self.lin_standardise:
                self.friedscale.train(X)
                X_regn = self.friedscale.scale(X)
            else:
                X_regn = X.copy()
            X_concat = np.concatenate((X_concat, X_regn), axis=1)

        X_rules = self.transform(X, rules)
        if X_rules.shape[0] > 0:
            X_concat = np.concatenate((X_concat, X_rules), axis=1)
        
        # no rules fit and self.include_linear == False
        if X_concat.shape[1] == 0:
            return [], [], 0

        return score_linear(X_concat, y, rules, 
                            alpha=self.alpha, 
                            penalty=self.penalty,
                            prediction_task=self.prediction_task,
                            max_rules=self.max_rules, random_state=self.random_state)


class StableLinearRegressor(StableLinear, RegressorMixin):
    def _init_prediction_task(self):
        self.prediction_task = 'regression'


class StableLinearClassifier(StableLinear, ClassifierMixin):
    def _init_prediction_task(self):
        self.prediction_task = 'classification'

Classes

class StableLinear (weak_learners: List[sklearn.base.BaseEstimator], max_complexity: int, min_mult: int = 1, penalty='l1', n_estimators=100, tree_size=4, sample_fract='default', max_rules=30, memory_par=0.01, tree_generator=None, lin_trim_quantile=0.025, lin_standardise=True, exp_rand_tree_size=True, include_linear=False, alpha=None, random_state=None)

Rulefit class. Rather than using this class directly, should use RuleFitRegressor or RuleFitClassifier

Parameters

n_estimators : int, default=100
Number of trees grown to generate candidate rules.
tree_size : int, default=4
Number of terminal nodes in generated trees. If exp_rand_tree_size=True, this is the mean number of terminal nodes.
sample_fract : float or "default", default="default"
Fraction of randomly chosen training observations used to produce each tree (Friedman and Popescu 2004, Sec. 2).
max_rules : int, default=30
Total number of terms included in the final model (both linear terms and rules). The approximate number of candidate rules generated is also based on this; the actual number is usually lower because of duplicates.
memory_par : float, default=0.01
Scale multiplier (shrinkage factor) applied to each new tree when sequentially induced (Friedman and Popescu 2004, Sec. 2).
tree_generator : estimator, optional
Used as provided to generate the rules, overriding most of the parameters above. Must be GradientBoostingRegressor(), GradientBoostingClassifier() or RandomForestRegressor(). A copy is fitted on the training data, so the object passed in is left untouched (and any previous fit of it is not reused). n_estimators, max_leaf_nodes and random_state are set on that copy while the trees are grown, so tuning them on the generator has no effect.
lin_trim_quantile : float, default=0.025
If lin_standardise is True, this quantile is used to trim linear terms before standardisation.
lin_standardise : bool, default=True
If True, linear terms are standardised as in Friedman and Popescu (Sec. 3.2), by multiplying the winsorised variable by 0.4 / stdev.
exp_rand_tree_size : bool, default=True
If True, each boosted tree has a different maximum number of terminal nodes, drawn from an exponential distribution about tree_size (Sec. 3.3).
include_linear : bool, default=True
Include linear terms as well as rules.
alpha : float, optional
Regularization strength; overrides max_rules.
cv : bool, default=True
Whether to use cross-validation scores to select the regularization strength, out of all values that satisfy max_rules. If False, the least regularization possible is used.
random_state : int, optional
Seed for the random objects, for repeatability.
verbose : int, default=0
Verbosity.

Attributes

rule_ensemble : RuleEnsemble
The rule ensemble.
feature_names : list of str, optional
The names of the features (columns).
Expand source code
class StableLinear(RuleFit):

    def __init__(self,
                 weak_learners: List[BaseEstimator],
                 max_complexity: int,
                 min_mult: int = 1,
                 penalty='l1',
                 n_estimators=100,
                 tree_size=4,
                 sample_fract='default',
                 max_rules=30,
                 memory_par=0.01,
                 tree_generator=None,
                 lin_trim_quantile=0.025,
                 lin_standardise=True,
                 exp_rand_tree_size=True,
                 include_linear=False,
                 alpha=None,
                 random_state=None):
        super().__init__(n_estimators,
                         tree_size,
                         sample_fract,
                         max_rules,
                         memory_par,
                         tree_generator,
                         lin_trim_quantile,
                         lin_standardise,
                         exp_rand_tree_size,
                         include_linear,
                         alpha,
                         random_state)
        self.max_complexity = max_complexity
        self.weak_learners = weak_learners
        self.penalty = penalty
        self.min_mult = min_mult

    def fit(self, X, y=None, feature_names=None):
        super().fit(X, y, feature_names=feature_names)
        return self

    def _extract_rules(self, X, y) -> List[str]:
        return extract_ensemble(self.weak_learners, X, y, self.min_mult)

    def _score_rules(self, X, y, rules):
        X_concat = np.zeros([X.shape[0], 0])

        # standardise linear variables if requested (for regression model only)
        if self.include_linear:

            # standard deviation and mean of winsorized features
            self.winsorizer.train(X)
            winsorized_X = self.winsorizer.trim(X)
            self.stddev = np.std(winsorized_X, axis=0)
            self.mean = np.mean(winsorized_X, axis=0)

            if self.lin_standardise:
                self.friedscale.train(X)
                X_regn = self.friedscale.scale(X)
            else:
                X_regn = X.copy()
            X_concat = np.concatenate((X_concat, X_regn), axis=1)

        X_rules = self.transform(X, rules)
        if X_rules.shape[0] > 0:
            X_concat = np.concatenate((X_concat, X_rules), axis=1)
        
        # no rules fit and self.include_linear == False
        if X_concat.shape[1] == 0:
            return [], [], 0

        return score_linear(X_concat, y, rules, 
                            alpha=self.alpha, 
                            penalty=self.penalty,
                            prediction_task=self.prediction_task,
                            max_rules=self.max_rules, random_state=self.random_state)

Ancestors

  • RuleFit
  • sklearn.base.BaseEstimator
  • sklearn.utils._estimator_html_repr._HTMLDocumentationLinkMixin
  • sklearn.utils._metadata_requests._MetadataRequester
  • sklearn.base.TransformerMixin
  • sklearn.utils._set_output._SetOutputMixin
  • RuleSet
  • RulesMixin
  • TextMixin

Subclasses

Inherited members

class StableLinearClassifier (weak_learners: List[sklearn.base.BaseEstimator], max_complexity: int, min_mult: int = 1, penalty='l1', n_estimators=100, tree_size=4, sample_fract='default', max_rules=30, memory_par=0.01, tree_generator=None, lin_trim_quantile=0.025, lin_standardise=True, exp_rand_tree_size=True, include_linear=False, alpha=None, random_state=None)

Rulefit class. Rather than using this class directly, should use RuleFitRegressor or RuleFitClassifier

Parameters

n_estimators : int, default=100
Number of trees grown to generate candidate rules.
tree_size : int, default=4
Number of terminal nodes in generated trees. If exp_rand_tree_size=True, this is the mean number of terminal nodes.
sample_fract : float or "default", default="default"
Fraction of randomly chosen training observations used to produce each tree (Friedman and Popescu 2004, Sec. 2).
max_rules : int, default=30
Total number of terms included in the final model (both linear terms and rules). The approximate number of candidate rules generated is also based on this; the actual number is usually lower because of duplicates.
memory_par : float, default=0.01
Scale multiplier (shrinkage factor) applied to each new tree when sequentially induced (Friedman and Popescu 2004, Sec. 2).
tree_generator : estimator, optional
Used as provided to generate the rules, overriding most of the parameters above. Must be GradientBoostingRegressor(), GradientBoostingClassifier() or RandomForestRegressor(). A copy is fitted on the training data, so the object passed in is left untouched (and any previous fit of it is not reused). n_estimators, max_leaf_nodes and random_state are set on that copy while the trees are grown, so tuning them on the generator has no effect.
lin_trim_quantile : float, default=0.025
If lin_standardise is True, this quantile is used to trim linear terms before standardisation.
lin_standardise : bool, default=True
If True, linear terms are standardised as in Friedman and Popescu (Sec. 3.2), by multiplying the winsorised variable by 0.4 / stdev.
exp_rand_tree_size : bool, default=True
If True, each boosted tree has a different maximum number of terminal nodes, drawn from an exponential distribution about tree_size (Sec. 3.3).
include_linear : bool, default=True
Include linear terms as well as rules.
alpha : float, optional
Regularization strength; overrides max_rules.
cv : bool, default=True
Whether to use cross-validation scores to select the regularization strength, out of all values that satisfy max_rules. If False, the least regularization possible is used.
random_state : int, optional
Seed for the random objects, for repeatability.
verbose : int, default=0
Verbosity.

Attributes

rule_ensemble : RuleEnsemble
The rule ensemble.
feature_names : list of str, optional
The names of the features (columns).
Expand source code
class StableLinearClassifier(StableLinear, ClassifierMixin):
    def _init_prediction_task(self):
        self.prediction_task = 'classification'

Ancestors

  • StableLinear
  • RuleFit
  • sklearn.base.BaseEstimator
  • sklearn.utils._estimator_html_repr._HTMLDocumentationLinkMixin
  • sklearn.utils._metadata_requests._MetadataRequester
  • sklearn.base.TransformerMixin
  • sklearn.utils._set_output._SetOutputMixin
  • RuleSet
  • RulesMixin
  • TextMixin
  • sklearn.base.ClassifierMixin

Inherited members

class StableLinearRegressor (weak_learners: List[sklearn.base.BaseEstimator], max_complexity: int, min_mult: int = 1, penalty='l1', n_estimators=100, tree_size=4, sample_fract='default', max_rules=30, memory_par=0.01, tree_generator=None, lin_trim_quantile=0.025, lin_standardise=True, exp_rand_tree_size=True, include_linear=False, alpha=None, random_state=None)

Rulefit class. Rather than using this class directly, should use RuleFitRegressor or RuleFitClassifier

Parameters

n_estimators : int, default=100
Number of trees grown to generate candidate rules.
tree_size : int, default=4
Number of terminal nodes in generated trees. If exp_rand_tree_size=True, this is the mean number of terminal nodes.
sample_fract : float or "default", default="default"
Fraction of randomly chosen training observations used to produce each tree (Friedman and Popescu 2004, Sec. 2).
max_rules : int, default=30
Total number of terms included in the final model (both linear terms and rules). The approximate number of candidate rules generated is also based on this; the actual number is usually lower because of duplicates.
memory_par : float, default=0.01
Scale multiplier (shrinkage factor) applied to each new tree when sequentially induced (Friedman and Popescu 2004, Sec. 2).
tree_generator : estimator, optional
Used as provided to generate the rules, overriding most of the parameters above. Must be GradientBoostingRegressor(), GradientBoostingClassifier() or RandomForestRegressor(). A copy is fitted on the training data, so the object passed in is left untouched (and any previous fit of it is not reused). n_estimators, max_leaf_nodes and random_state are set on that copy while the trees are grown, so tuning them on the generator has no effect.
lin_trim_quantile : float, default=0.025
If lin_standardise is True, this quantile is used to trim linear terms before standardisation.
lin_standardise : bool, default=True
If True, linear terms are standardised as in Friedman and Popescu (Sec. 3.2), by multiplying the winsorised variable by 0.4 / stdev.
exp_rand_tree_size : bool, default=True
If True, each boosted tree has a different maximum number of terminal nodes, drawn from an exponential distribution about tree_size (Sec. 3.3).
include_linear : bool, default=True
Include linear terms as well as rules.
alpha : float, optional
Regularization strength; overrides max_rules.
cv : bool, default=True
Whether to use cross-validation scores to select the regularization strength, out of all values that satisfy max_rules. If False, the least regularization possible is used.
random_state : int, optional
Seed for the random objects, for repeatability.
verbose : int, default=0
Verbosity.

Attributes

rule_ensemble : RuleEnsemble
The rule ensemble.
feature_names : list of str, optional
The names of the features (columns).
Expand source code
class StableLinearRegressor(StableLinear, RegressorMixin):
    def _init_prediction_task(self):
        self.prediction_task = 'regression'

Ancestors

  • StableLinear
  • RuleFit
  • sklearn.base.BaseEstimator
  • sklearn.utils._estimator_html_repr._HTMLDocumentationLinkMixin
  • sklearn.utils._metadata_requests._MetadataRequester
  • sklearn.base.TransformerMixin
  • sklearn.utils._set_output._SetOutputMixin
  • RuleSet
  • RulesMixin
  • TextMixin
  • sklearn.base.RegressorMixin

Inherited members