Tutorial#

Cyclic Boosting can be used in a scikit-learn-like fashion.

Several examples can be found in the integration tests.

A more detailed example, including additional helper functionality, can be found here.

For the simplest, default case, just do:

from cyclic_boosting.pipelines import pipeline_CBPoissonRegressor

CB_est = pipeline_CBPoissonRegressor()
CB_est.fit(X_train, y)

yhat = CB_est.predict(X_test)

Analysis Plots#

To additionally create analysis plots of the training:

from cyclic_boosting.pipelines import pipeline_CBPoissonRegressor
from cyclic_boosting import observers
from cyclic_boosting.plots import plot_analysis

def plot_CB(filename, plobs, binner):
    for i, p in enumerate(plobs):
        plot_analysis(
            plot_observer=p,
            file_obj=filename + "_{}".format(i),
            use_tightlayout=False,
            binners=[binner]
        )

plobs = [observers.PlottingObserver(iteration=-1)]
CB_est = pipeline_CBPoissonRegressor(observers=plobs)

CB_est.fit(X_train, y)
plot_CB('analysis_CB_iterlast', [CB_est[-1].observers[-1]], CB_est[-2])

yhat = CB_est.predict(X_test)

Set Feature Properties#

By setting feature properties/flags (all available ones can be found here), you can also specify the treatment of individual features, e.g., as continuous or categorical (including treatment of missing values):

from cyclic_boosting.pipelines import pipeline_CBPoissonRegressor
from cyclic_boosting import flags

fp = {}
fp['feature1'] = flags.IS_UNORDERED
fp['feature1'] = flags.IS_CONTINUOUS | flags.HAS_MISSING | flags.MISSING_NOT_LEARNED

CB_est = pipeline_CBPoissonRegressor(feature_properties=fp)

CB_est.fit(X_train, y)

yhat = CB_est.predict(X_test)

Quick overview of the basic flags:

  • IS_CONTINUOUS: can be used to do a binning (by default equi-statistics) of a continuous feature and smooth the factors estimated for each bin by an orthogonal polynomial.

  • IS_LINEAR: works similar to IS_CONTINUOUS, but uses a linear function for smoothing.

  • IS_UNORDERED: can be used for categorical features.

  • IS_ORDERED: in principle, should smooth categorical features by weighing neighboring bins higher, but currently just points to IS_UNORDERED.

  • HAS_MISSING: learns an additional, separate category for missing values (all nan values of a feature).

  • MISSING_NOT_LEARNED: puts all missing values (all nan values of a feature) to an additional, separate category, which is set to the neutral factor (e.g., 1 for multiplicative or 0 for additive regression mode).

Set Features#

You can also specify which columns to use as features, including interaction terms (default is all available columns as individual features only):

from cyclic_boosting.pipelines import pipeline_CBPoissonRegressor

features = [
    'feature1',
    'feature2',
    ('feature1', 'feature2')
]

CB_est = pipeline_CBPoissonRegressor(feature_groups=features)

CB_est.fit(X_train, y)

yhat = CB_est.predict(X_test)

There is also some functionality for interaction term selection, exploiting feature binning:

from cyclic_boosting.interaction_selection import select_interaction_terms_anova

best_interaction_term_features = select_interaction_terms_anova(X_train, y, fp, 3, 5)

Manual Binning#

Behind the scenes, Cyclic Boosting works by combining a binning method (e.g., BinNumberTransformer) with a Cyclic Boosting estimator (find all estimators here).

If you want to use a different number of bins (default is 100):

from cyclic_boosting.pipelines import pipeline_CBPoissonRegressor

CB_est = pipeline_CBPoissonRegressor(number_of_bins=50)
CB_est.fit(X_train, y)

yhat = CB_est.predict(X_test)

If you want to use a different kind of binning (below is default), you can combine binners and estimators manually:

from sklearn.pipeline import Pipeline
from cyclic_boosting import binning, CBPoissonRegressor

binner = binning.BinNumberTransformer()
est = CBPoissonRegressor()
CB_est = Pipeline([("binning", binner), ("CB", est)])

CB_est.fit(X_train, y)

yhat = CB_est.predict(X_test)

Feature Importances#

To get a dictionary with the relative importances of the different model features in the training:

CB_est.get_feature_importances()

Individual Explainability#

To get a dictionary with the contributions of the different model features to the individual predictions of a given data set:

CB_est.get_feature_contributions(X_test)

Quantile Regression#

Below you can find an example of a quantile regression model for three different quantiles, with a subsequent quantile matching (to get a full individual probability distribution from the estimated quantiles) by means of a Johnson Quantile-Parameterized Distribution (J-QPD) for each test sample:

from cyclic_boosting.pipelines import pipeline_CBMultiplicativeQuantileRegressor
from cyclic_boosting.quantile_matching import J_QPD_S

CB_est_qlow = pipeline_CBMultiplicativeQuantileRegressor(quantile=0.2)
CB_est_qlow.fit(X_train, y)
yhat_qlow = CB_est_qlow.predict(X_test)

CB_est_qmedian = pipeline_CBMultiplicativeQuantileRegressor(quantile=0.5)
CB_est_qmedian.fit(X_train, y)
yhat_qmedian = CB_est_qmedian.predict(X_test)

CB_est_qhigh = pipeline_CBMultiplicativeQuantileRegressor(quantile=0.8)
CB_est_qhigh.fit(X_train, y)
yhat_qhigh = CB_est_qhigh.predict(X_test)

j_qpd_s = J_QPD_S(0.2, yhat_qlow, yhat_qmedian, yhat_qhigh)
yhat_percentile95 = j_qpd_s.ppf(0.95)

There is also a ready-made end-to-end practical training chain, employing quantile transformations to impose constraints on the target range (for bound or semi-bound scenarios) and maintain the order of symmetric-percentile triplet predictions (from an arbitrary quantile regression method, not restricted to Cyclic Boosting) used for J-QPD:

from cyclic_boosting.pipelines import pipeline_CBAdditiveQuantileRegressor
from cyclic_boosting.quantile_matching import QPD_RegressorChain

est = QPD_RegressorChain(
    pipeline_CBAdditiveQuantileRegressor(quantile=0.5),
    pipeline_CBAdditiveQuantileRegressor(quantile=0.5),
    pipeline_CBAdditiveQuantileRegressor(quantile=0.5),
    "S",
)
est.fit(X_train, y)
yhat_qlow, yhat_qmedian, yhat_qhigh, qpd = est.predict(X_test)