Changelog#
Unreleased#
Feature Added
EmpiricalMaxProfitandAUEPCstrategies for building custom metrics that compute the empirical (convex-hull-based) maximum profit and the area under the empirical profit curve, respectively.API Change
empc,mpc,empa,mpa,empcs,mpcs,empb,make_objective_churn,make_objective_acquisition, and their supportingAECObjectiveChurn,AECMetricChurn,AECObjectiveAcquisition, andAECMetricAcquisitionclasses have been removed.empc_score,mpc_score,empa_score,mpa_score,empcs_score,mpcs_score,empb_score, andauepc_scoreare now prebuiltMetric/MixtureMetricinstances instead of hand-written functions. The decision threshold (previously returned alongside the score by the removedempc/mpc/empa/mpa/empcs/mpcs/empbfunctions) can still be obtained with the.optimal_rate(...)method on the corresponding*_scoreinstance. Training a boosting model directly on any of these metrics (previously done throughmake_objective_churn/make_objective_acquisition) is now done by passing the metric as thelossargument toCSBoostClassifier.API Change
expected_cost_loss_churnandexpected_cost_loss_acquisitionnow always return the mean cost per instance (previously they returned the summed cost by default, with an optionalnormalize=Trueargument to switch to the mean).API Change
empa_score’sbetaparameter now represents the scale of the Gamma-distributed contribution (mean =alpha * beta), instead of the rate (mean =alpha / beta) used by the previousempa/empa_scorefunctions. The default value has been adjusted accordingly, so calls that rely on the default are unaffected; only explicit non-defaultbeta=overrides behave differently.API Change The generic (domain-agnostic) native functions
max_profit,make_objective_aec, and the supportingAECObjectiveandAECMetricclasses have been removed.max_profit_score,expected_cost_loss,expected_log_cost_loss, andexpected_savings_scoreare now prebuiltMetricinstances instead of hand-written functions (cost_lossandsavings_score, the hard-label variants that auto-threshold continuous scores, are unaffected and remain plain functions, since there is noMetric/MetricStrategyequivalent for that behavior). The decision threshold (previously returned alongside the score by the removedmax_profitfunction) can still be obtained with the.optimal_rate(...)method onmax_profit_score. Training a boosting or logistic-regression model directly on any of these metrics (previously done throughmake_objective_aec) is now done by passing the metric as thelossargument to a cost-sensitive model, e.g.CSBoostClassifierorCSLogitClassifier.API Change
max_profit_scorenow takestp_cost/tn_costparameters (costs) instead of the previous nativemax_profit/max_profit_scorefunctions’tp_benefit/tn_benefitparameters (benefits):tp_cost = -tp_benefitandtn_cost = -tn_benefit.fp_cost/fn_costare unchanged. This matches the parameter naming already used throughout the rest of the package (e.g. the cost-sensitive models’ default loss).API Change
expected_cost_lossandexpected_log_cost_lossnow always return the mean cost per instance (previously they returned the summed cost by default, with an optionalnormalize=Trueargument to switch to the mean). This also affects the default (unweighted-loss) out-of-bag weighted-voting behavior ofCSForestClassifierandCSBaggingClassifier, which useexpected_cost_lossas their fallback per-estimator weight.Fix Cost-sensitive models can now be trained with a
lossmetric whose cost matrix names one of its symbols (or aliases)tp_cost,tn_cost,fp_costorfn_cost. Those names collide with the dedicatedfit/predictparameters of the same name, so the value bound to the parameter and was silently discarded instead of reaching the metric, and training failed withTypeError: _lambdifygenerated() missing 1 required positional argument. This affected the cost matrices shipped withload_churn_tv_subscriptions,load_credit_scoring_pakddandfetch_give_me_some_credit. Such values are now routed to the metric, and a cost argument that the metric does not use raises a warning instead of being dropped silently. Note that__init__-time costs are still not forwarded to a metric loss, since they default to0.0and would silently zero out a cost matrix term of the same name.Fix Fix
RobustCSClassifiernot properly handling outlier sensitive costs when passing a custom loss function fromMetric.Fix Fix
empb_scoreandauepc_scorenot always incurring the contact cost for customers who are not contacted.Fix Fix
expected_savings_score’s (and theSavingsstrategy’s)baseline='prior'option: it previously computed the baseline cost by hard-thresholding the constant prior probability (via the same logic ascost_loss), which usually made it silently degenerate to the same result asbaseline='zero_one'/'one'. It now correctly evaluates the expected cost of predicting the prior probability of the majority or minority class, whichever is cheaper, as documented.Fix
Metricno longer shares mutable strategy state when the sameMetricStrategyinstance (e.g. a configuredMaxProfit) is passed to more than oneMetric. Previously, building a secondMetricfrom an already-used strategy instance silently rebuilt that strategy in place, so the firstMetricwould start returning values computed from the second metric’s cost matrix instead of its own. EachMetricnow builds and owns an independent copy of the strategy it is given.Fix
Metricno longer stays linked to the mutableCostMatrixit was constructed from. Previously, modifying theCostMatrixobject after building aMetricfrom it silently desynchronized the metric’s advertised cost expressions (e.g.metric.fn_cost) from what it actually computed, so a parameter the metric claimed to depend on could be silently ignored when scoring.Metricnow takes an independent copy of its cost matrix at construction time.Fix
Metricnow raises aValueErrorat construction time if the cost matrix uses a symbol name or alias reserved for internal use (y,s,F_0,F_1,pi_0,pi_1,N,i). Previously, a colliding symbol name was either silently fused with the identically-named internal variable (e.g. a user symbol namedF_0in aMaxProfitmetric), producing a wrong score with no warning, or raised a confusing internalTypeErroronly once the metric was called (e.g. a symbol namedyors).Fix
Metricnow raises aValueErrorwhen called with both a symbol’s own name and one of its aliases (or with two different aliases for the same symbol). Previously, whichever keyword argument was seen last silently won, so the computed score depended on the order the keyword arguments happened to be passed in.Fix
Metricnow raises aValueErrorat construction time if an alias’s target, or aset_defaultparameter name, does not match any symbol used in the cost matrix. This also catches the ordering footgun documented onset_default, where a default keyed by an alias name that was set before the alias was registered used to be silently stored under that raw (untranslated) name and then silently ignored, instead of ever being applied.Fix
Metricnow validatesy_true/y_score.Fix
Metricnow raises aValueErrornaming the offending parameter when an instance-dependent (array-like)cost_matrixparameter’s length doesn’t matchy_true/y_scoreand isn’t a single value broadcastable to every sample. Previously a length mismatch surfaced as an unrelated numpy broadcasting error, e.g.operands could not be broadcast together with shapes (3,) (5,), that didn’t say which parameter was wrong.Fix
Metric.optimal_threshold()andoptimal_ratenow raise aValueErrorwhen the cost matrix is degenerate for the given parameters (fp_cost + tn_benefit + fn_cost + tp_benefitevaluates to 0, making the optimal threshold undefined).Fix
CSThresholdClassifierandCSRateClassifierno longer silently skip learning a cost-sensitive threshold/rate when fitted with an aliasedMetricwith every required parameter supplied through its alias.Fix
CSBaggingClassifierwithcombination='weighted_voting'no longer raises a shape error when a sub-estimator draws a feature subset (max_features < 1.0orbootstrap_features=True).Fix
CSForestClassifierwithcombination='weighted_voting'no longer producesNaNout-of-bag estimator weights whenmax_samplesis anint.numbers.Integralis a subclass ofnumbers.Real.Fix Out-of-bag weighted voting (
CSForestClassifierandCSBaggingClassifierwithcombination='weighted_voting') no longer gives more weight to worse estimators, and no longer raises when instance-dependent (array-like) costs are used together with weighted voting.Fix
CSTreeClassifierandCSForestClassifierno longer raises when fitted with a metric strategy containing a stochastic (sympy.stats) variable.Fix
CSBoostClassifierno longer mutates a caller-suppliedfit_paramsdict in place.Fix
CSTreeClassifierno longer mutates a user-supplied customcriterioninstance in place.Fix
CSBoostClassifier’s LightGBM and CatBoost backends now start from the intended probability. The internal base-score nudge was applied as a raw (log-odds) score for LightGBM’sinit_score/CatBoost’sbaselinebut as a probability for XGBoost’sbase_score, and neither LightGBM nor CatBoost persist that offset into the saved model, sopredict_probanow adds it back manually before converting to a probability.Fix
BiasRelabelingClassifier,BiasResamplingClassifier, andBiasReweighingClassifiernow raise a clearValueErrorwhensensitive_featuredoes not have the same length asy, instead of silently proceeding.Fix
CSThresholdClassifierandCSRateClassifierno longer mutate a user-suppliedcalibratorestimator instance in place; a clone is configured and fitted instead, so the constructor argument is safe to reuse or refit.Fix
CSLogitClassifierandProfLogitClassifierdocumentedsoft_thresholdas defaulting toFalse; the actual default isTrue.
0.11.1 (08-05-2026)#
Fix Fix empulse not running properly on scikit-learn versions lower than 1.6.
0.11.0 (08-05-2026)#
Feature Added
ProfTreeClassifierto optimize a cost-sensitive metric using evolutionary trees (similar toProfLogitClassifier).Feature Added
CSRateClassifierto optimize for a specific predicted positive rate.Feature Allow
CSThresholdClassifierto optimize the decision threshold at training time. Users can now either specify the decision threshold to use at prediction time or let the model choose the optimal threshold during training.Feature (Experimental) When using the
MaxProfitstrategy, only one stochastic variable is present, and the cost/profit function is a polynomials of the stochastic variable: the metric will now be computed exactly instead of using numerical integration. This is currently supported for stochastic variables following the Normal, Log Normal, Uniform, Beta, Gamma, Chi Squared, Exponential, Weibull, Pareto, and Triangular distributions.Feature (Experimental) Added support for the MaxProfit strategy metrics to be optimized through gradient descent methods in
CSLogitClassifierandCSBoostClassifier. This is currently an experimental feature and is not recommended for use in production.API Change Updated the
ProfLogitClassifierinterface to be more consistent with other models in the package. By default optimizes the maximum profit metric.API Change
CSLogitClassifierno longer takes a string argument for the loss function to be more consistent with other models in the package. Default value for the loss is None.API Change
MaxProfitnow takes a numpy Generator instead of a RandomState instance.Enhancement Metrics built with the
MaxProfitstrategy can now handle instance-dependent costs. They will automatically be averaged over the instances. Mathematically this is equivalent to recomputing the EMP score for each instance and then averaging the scores.Enhancement Metrics built with the
CostandSavingsstrategies can now handle stochastic cost parameters. If the distribution allows it, the mean cost will be computed.Fix Fix
CSTreeClassifierandCSForestClassifiernot properly training when costs were negative.Fix Fix integration bounds inconsistently being calculated when the
MaxProfitstrategy was chosen.Fix Fix
CSBoostClassifierthrowing errors when one or two of the Boosting libraries were not installed (XGBoost, LGBM & Catboost).Fix Add __name__ attribute to
Metricclass to fix issues with scikit-learn compatibility.Fix Fix metadata routing not working for scikit-learn>=1.8.0
Fix Fix
MaxProfitstrategy not calculating Log Normal distributed variables correctly when using quasi monte carlo.Fix Fix some models not properly being able to be pickled when using a custom metric as the loss function.
Fix Fix some distributions not correctly computing the expected maximum profit score when using the
MaxProfitstrategy when using monte carlo or quasi monte carlo method.
0.10.4 (20-09-2025)#
Efficiency Changed to Cython implementation for the loss functions and impurity measures of
CSLogitClassifier,CSBoostClassifier,CSTreeClassifier, andCSForestClassifier. This improves the training time and memory efficiency of these models significantly. Training time speedups observed were up to 300x forCSTreeClassifierandCSForestClassifier, 30x forCSLogitClassifier, and 1.5x forCSBoostClassifierdepending on the dataset size and parameters.API Change Changed arguments to
CSTreeClassifier,CSForestClassifier, andCSBaggingClassifierto be in line with scikit-learn’s decision tree and ensemble models.API Change
CSForestClassifier, andCSBaggingClassifierno longer support stacking combination method. UseStackingClassifierinstead for stacking.API Change Extracted the construction of the cost matrix into a separate class
CostMatrixaway fromMetricto allow reusing the cost matrix in custom metrics.API Change
ProfLogitClassifierno longer uses the EMPC metric by default. Users now need to explicitely pass a loss to the model.API Change
CSLogitClassifierno longer accepts any callable as loss function. Users now need to pass aMetricinstance for a custom loss function.Feature
savings_scoreandexpected_savings_scorenow accept two more baseline options ‘one’ and ‘zero’ to always predict the positive and negative class, respectively.Feature Metrics with with the
Savingsstrategy now also accepts baseline options likesavings_scoreandexpected_savings_score.Enhancement Models which use a
Metricinstance as their loss function with theCostorSavingsstrategy as their loss function now are pickleable. TheMaxProfitstrategy will be updated to be pickleable in a future release.Enhancement Models which use a
Metricinstance as their loss function can now request arguments necessary for the metric to be passed during the fit method through Metadata Routing.Fix Fix
CSLogitClassifiernot properly calculating gradient penalty.Fix Fix default values not being properly when using aliases in
CostMatrix.Fix Fix
Metricthrowing errors when certain terms cancelled out.
0.9.0 (15-06-2025)#
Feature Added
optimal_thresholdandoptimal_ratemethods to calculate the optimal threshold(s) and optimal predicted positive rate for a given metric. This is useful for determining the best decision threshold and predicted positive rate for a cost-sensitive or value-driven model.Feature
CSTreeClassifier,CSForestClassifier, andCSBaggingClassifiercan now take aMetricinstance as their criterion to optimize.Feature
CSThresholdClassifiercan now take aMetricinstance to choose the optimal decision threshold.Feature
RobustCSClassifiercan now take estimators with aMetricinstance as the loss function or criterion.RobustCSClassifierwill treat any cost marked as outlier sensitive. This can be done by using themark_outlier_sensitivemethod.Feature Allow savings metrics to be used in
CSBoostClassifierandCSLogitClassifieras the objective function. Internally, the expected cost loss is used to train the model, since the expected savings score is just a transformation of the expected cost loss.API Change kind argument to
Metrichas been replaced by strategy. TheMetricclass now takes aMetricStrategyinstance. This change allows for more flexibility in defining the metric strategy. The currently available strategies are:Fix Fix error when importing Empulse without any optional dependencies installed.
Fix Fix
CSLogitClassifiernot properly using the gradient when using a custom loss function fromMetric.Fix Fix models throwing errors when differently shaped costs are passed to the fit or predict method.
Fix Fix sympy distribution parameters not being properly translated to scipy distribution parameters when using the
MaxProfitstrategy (formerly kind=’max profit’) with the quasi monte-carlo integration method.
0.8.0 (01-06-2025)#
Feature
CSBoostClassifier,CSLogitClassifier, andProfLogitClassifiercan now take aMetricinstance as their loss function. Internally, the metric instance is converted to the appropriate loss function for the model. For more information, read the User Guide.Feature Type hints are now available for all functions and classes.
Enhancement Add support for more than one stochastic variable when building maximum profit metrics with
MetricEnhancement Allow
Metricto be used as a context manager. This ensures the metric is always built after defining the cost-benefit elements.Fix Fix datasets not properly being packaged together with the package
Fix Fix
RobustCSClassifierwhen array-like parameters are passed to fit method.Fix Fix boosting models being biased towards the positive class.
0.7.0 (05-02-2025)#
Major Feature Add
CSTreeClassifier,CSForestClassifier, andCSBaggingClassifierto support cost-sensitive decision tree and ensemble modelsEnhancement Add support for scikit-learn 1.5.2 (previously Empulse only supported scikit-learn 1.6.0 and above).
API Change Removed the
emp_scoreandempfunctions from themetricsmodule. Use theMetricclass instead to define custom expected maximum profit measures. For more information, read the User Guide.API Change Removed numba as a dependency for Empulse. This will reduce the installation time and the size of the package.
Fix Fix
Metricwhen defining stochastic variable with fixed values.Fix Fix
Metricwhen stochastic variable has infinite bounds.Fix Fix
CSThresholdClassifierwhen costs of predicting positive and negative classes are equal.Fix Fix documentation linking issues to sklearn
0.6.0 (28-01-2025)#
Major Feature Add
Metricto easily build your own value-driven and cost-sensitive metricsFeature Add support for LightGBM and Catboost models in
CSBoostClassifierandB2BoostClassifierAPI Change
make_objective_churnandmake_objective_acquisitionnow take amodelargument to calculate the objective for either XGBoost, LightGBM or Catboost models.API Change XGBoost is now an optional dependency together with LightGBM and Catboost. To install the package with XGBoost, LightGBM and Catboost support, use the following command:
pip install empulse[optional]API Change Renamed
y_pred_baselineandy_proba_baselinetobaselineinsavings_scoreandexpected_savings_score. It now accepts the following arguments:If
'zero_one', the baseline model is a naive model that predicts all zeros or all ones depending on which is better.If
'prior', the baseline model is a model that predicts the prior probability of the majority or minority class depending on which is better (not available for savings score).If array-like, target probabilities of the baseline model.
Feature Add parameter validation for all models and samplers
API Change Make all arguments of dataset loaders keyword-only
Fix Update the descriptions attached to each dataset to match information found in the user guide
Fix Improve type hints for functions and classes
0.5.2 (12-01-2025)#
Feature Allow
savings_scoreandexpected_savings_scoreto calculate the savings score over the baseline model instead of a naive model, by setting they_pred_baselineandy_proba_baselineparameters, respectively.Enhancement Reworked the user guide documentation to better explain the usage of value-driven and cost-sensitive models, samplers and metrics
API Change
CSLogitClassifierandProfLogitClassifierby default do not perform soft-thresholding on the regression coefficients. This can be enabled by setting thesoft_thresholdparameter to True.Fix Prevent division by zero errors in
expected_cost_loss
0.5.1 (05-01-2025)#
Fix Fixed documentation build issue
0.5.0 (05-01-2025)#
Major Feature Added supported for python 3.13
- Major Feature Added cost-sensitive models
- Major Feature Added cost-sensitive metrics
Major Feature Added
empulse.datasetsmoduleFeature Added
CostSensitiveSamplerEnhancement Allow all cost-sensitive models and samplers to accept cost parameters during initialization
API Change Renamed metric arguments which expect target score from y_pred to y_score and target probabilities from y_pred to y_proba