OptBinning: choosing the bin edges that make a scorecard honest
Optimal binning: monotonic binning with constraints. Support batch & stream optimal binning. Scorecard modelling and counterfactual explanations.
At a glance
- What is it?
- OptBinning solves the problem of how to cut a continuous predictor into ordered buckets, and it does it as a constrained optimisation rather than as a heuristic, so you can demand monotonicity, minimum counts per bin and a maximum of splits and let a solver find the best solution. The same machinery produces weight of evidence tables, information values and counterfactual explanations for scorecard models.
- Who is it for?
- Adopt OptBinning if you are building a scorecard or any model that needs a discretised predictor with guarantees, since the constrained optimisation gives you monotone event rates, minimum bin counts and an OPTIMAL status rather than quantile cuts that happen to look reasonable. Do not use it without a held-out split, because the method maximises separation on the data it is fitted to, and the example's total information value of 5.04 is a symptom of that.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the problem is, and why the answer is an optimisation
OptBinning is a library written in Python implementing a rigorous and flexible mathematical programming formulation to solve the optimal binning problem for a binary, continuous and multiclass target type, incorporating constraints not previously addressed.
The problem itself is one every credit modeller or data scientist hits. You have a continuous predictor, a probability of an event, and you want to turn that predictor into a handful of ordered buckets, each with a rate. The naive way is to cut on quantiles, which is easy and produces bad bins, because quantile cuts do not care whether the event rate is monotonic across the buckets, and a bucket with three events in it is useless in a scorecard.
OptBinning's contribution is to treat the bin edges as the output of a constrained optimisation problem rather than of a rule. You state the constraints, such as monotonicity of the event rate, minimum number of records per bin and a maximum number of splits, and a solver finds the best set of cut points that satisfies them.
The papers behind it are the formal statement of the method. Optimal binning: mathematical programming formulation, arXiv 2001.08025, and Optimal counterfactual explanations for scorecard modelling, arXiv 2104.08619. There is also a blog post on optimal binning for streaming data.
The primary language is Python, the licence is Apache-2.0, the default branch is master, and the homepage is gnpalencia.org/optbinning. The recent releases are v1.0.0 from 2026-09-12, v0.21.0 from 2025-10-26 and v0.20.1 from 2025-02-24, and the last push was on 2026-10-20 with the project not archived. The jump from 0.21 to 1.0 is a deliberate statement that the API is now stable, after two years of 0.x releases.
The topic list gives a good map of the scope: woe and woebinning, scorecard, credit-scoring, mdlp, counterfactual-explanations, optimization, and both batch-processing and streaming-data.
Installing it, and what the extra packages are for
The installation section is short, with three variants for the base package and one source route.
The current release from PyPI:
pip install optbinningThen there are two optional extras. To include batch and stream binning algorithms, which the README notes is not required for most users:
pip install optbinning[distributed]And to include support for the ecos solver:
pip install optbinning[ecos]And from source:
git clone https://github.com/guillermo-navas-palencia/optbinning.git
cd optbinning
pip install .The three solver options are worth understanding, because the solver choice is the one real decision you make. The main dependency is ortools, Google's OR-Tools, at 9.15 or newer, which provides the constraint programming solver. The default in the example is solver="cp", the constraint programming solver, and the ecos extra adds a solver from Embotech, which handles a different formulation of the problem.
The core dependency list is:
* matplotlib
* numpy (>=1.16.1)
* ortools (>=9.15)
* pandas
* ropwr (>=1.0.0)
* scikit-learn (>=1.6.0)
* scipy (>=1.6.0)So matplotlib for the plots, numpy, pandas and scikit-learn for the data handling, scipy for the numerical work, ortools for the optimisation, and ropwr at 1.0.0 or newer, which the manifest lists without further comment in the README, so its exact role is best read from its own documentation rather than guessed at here.
The distributed extra brings pympler and tdigest. The tdigest part is the interesting one, because a t-digest is a streaming sketch for computing quantiles over a stream without holding all the data, and that is exactly what you need to bin a stream: you cannot keep every record to find the right cut points, so you keep a sketch and bin from that.
pympler is a memory profiler, which is the other half of the streaming problem, since a streaming binning implementation has to be careful about what it retains.
The package metadata is modern. The build system is setuptools at 77 or newer with wheel, the version is dynamic and read from optbinning._version, the licence is Apache-2.0 with the licence file declared, and the platforms list says any. The classifiers list Python 3.11, 3.12 and 3.13, and the topic classifiers are Scientific/Engineering Mathematics plus the usual Python library ones.
The example, and what the binning table actually shows
The README's worked example uses the breast cancer dataset from scikit-learn, which is a good choice for a tutorial because the answer is well known.
The data is loaded and a variable is chosen to discretize:
import pandas as pd
from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
df = pd.DataFrame(data.data, columns=data.feature_names)
variable = "mean radius"
x = df[variable].values
y = data.targetThen the optimiser is instantiated with the variable name, its data type and a solver, in this case the constraint programming solver, and fitted with the arrays:
from optbinning import OptimalBinning
optb = OptimalBinning(name=variable, dtype="numerical", solver="cp")
optb.fit(x, y)After fitting, the status and the split points come back:
>>> optb.status
'OPTIMAL'
>>> optb.splits
array([11.42500019, 12.32999992, 13.09499979, 13.70499992, 15.04500008,
16.92500019])The status of OPTIMAL is the assertion that matters. It is not a heuristic result, it is a proof that the returned solution is optimal under the stated constraints, and that is the difference between this library and a quantile cut.
Then the binning table, which is where the credit modelling value is:
Bin Count Count (%) Non-event Event Event rate WoE IV JS
0 [-inf, 11.43) 118 0.207381 3 115 0.974576 -3.12517 0.962483 0.087205
1 [11.43, 12.33) 79 0.138840 3 76 0.962025 -2.71097 0.538763 0.052198
2 [12.33, 13.09) 68 0.119508 7 61 0.897059 -1.64381 0.226599 0.025513
3 [13.09, 13.70) 49 0.086116 10 39 0.795918 -0.839827 0.052131 0.006331
4 [13.70, 15.05) 83 0.145870 28 55 0.662651 -0.153979 0.003385 0.000423
5 [15.05, 16.93) 54 0.094903 44 10 0.185185 2.00275 0.359566 0.038678
6 [16.93, inf) 118 0.207381 117 1 0.008475 5.28332 2.900997 0.183436
7 Special 0 0.000000 0 0 0.000000 0 0.000000 0.000000
8 Missing 0 0.000000 0 0 0.000000 0 0.000000 0.000000
Totals 569 1.000000 212 357 0.627417 5.043925 0.393784Nine rows, and the last two are Special and Missing, both empty in this dataset. The columns are Count, Count (%), Non-event, Event, Event rate, WoE, IV and JS.
The WoE column is the weight of evidence, which is the transformation that turns a bucket into a scorecard point. The IV column is the information value, the total of which is 5.043925, and the JS column is the Jensen-Shannon divergence. A total IV of 5.04 is very high by credit scoring convention, which is a warning as much as an achievement, since an IV that high on a held-out sample usually means the variable is leaking rather than predictive.
And the event rate column shows the monotonicity working. Reading down the bins, the rate goes 0.974576, 0.962025, 0.897059, 0.795918, 0.662651, 0.185185, 0.008475. That is strictly decreasing, which is exactly the constraint the optimiser was asked to enforce, and it is the property that makes the scorecard monotone and therefore defensible.
The table is also readable in the way a modeller wants. The split points are printed with six decimal places, which tells you they are continuous values rather than rounded ones, and the bins are half-open intervals, [-inf, 11.43) through [16.93, inf), so the first and last catch the tails.
Plots come from the same object, either the WoE curve or the event rate curve, and there is a style option for showing actual bin widths and flags for leaving out the special and missing rows:
>>> optb.binning_table.plot(metric="woe")So the object carries the bins, the metrics, the plot and the splits, and the whole workflow is one fitted instance.
Scorecards and counterfactuals, and what the tutorials cover
The tutorials section lists seven areas, and reading the list tells you how the library is scoped.
There are the optimal binning tutorials and the binning process tutorials, which are the core. Then scorecard and counterfactual tutorials, which is the application layer. Then optimal piecewise binning tutorials, which is the generalisation from a single variable to a piecewise-linear form. Then batch and stream optimal binning tutorials. Then optimal binning under uncertainty. And then optimal binning 2D.
That last group is the more unusual half. Binning under uncertainty is a distinct problem, where the events themselves carry uncertainty rather than being a hard label, and it changes the objective. Binning 2D extends the formulation to a two-dimensional target, which is what you need when the relationship between a predictor and the event is not monotone in one direction.
The scorecard and counterfactual part is where the second paper comes in. A counterfactual explanation for a scorecard answers the question a declined applicant asks: what would have to have been different about this variable for the score to have been accepted. Since the scorecard is a sum of scaled weight of evidence values across bins, and a counterfactual explanation has to respect the constraints on the rest of the model, this is a constrained search over the bin space, and it is a natural application of the same machinery the binning uses.
The streaming part deserves a note too, because it is not a batch algorithm run repeatedly. The blog post is titled optimal binning for streaming data, and the distributed extra exists to support it, so the streaming implementation is a first-class path rather than an afterthought.
Everything is documented on the site, and the README says that if you are new to OptBinning you can get started by following the tutorials and checking the API references. The site carries both the current release documentation and the tutorials, and there is a separate page on the binning process itself, which suggests the documentation treats the process as something to be taught rather than just an API to be looked up.
How to evaluate it, and what to check first
There are five things to consider.
First, whether you need the optimisation at all. If you want three buckets for a chart, quantiles will do and will be faster. OptBinning earns its keep when you have constraints that must hold, in particular monotonicity, because a non-monotone scorecard is a regulatory and reputational problem in credit scoring rather than a cosmetic one.
Second, that the status field is the guarantee. The example asserts OPTIMAL, and you should check it on every fit rather than assuming it. A solver that returns a suboptimal or infeasible result under a tight constraint set is exactly the case where a heuristic would have silently produced bins that do not satisfy what you asked for.
Third, the overfitting risk, and this is the most important practical point. The information value of 5.04 in the example is far above what you would want to see in a model that has been validated, and the example is fitted and reported on the same data. The bin edges are chosen to maximise separation on the sample, which means a fine-grained binning of a modest dataset will fit noise. This is a property of the method rather than a bug in the implementation, and the way to manage it is to fit the binning on a training split and evaluate the table on a validation one, which the binning process documentation is where to look.
Fourth, the solver choice and the optional extras. The default constraint programming solver through OR-Tools will do most work, ecos is there for a different formulation, and the distributed extra is only needed for the streaming path, which the README explicitly says is not required for most users. So the default install is smaller than it looks.
Fifth, the version jump. v1.0.0 in September 2026 after two years of 0.x means the API is now meant to be stable, so a fresh install is a good moment to start, and a project that has been living with 0.x should check the changelog before upgrading.
What you get is a solver-backed binning library with an unusually explicit output, where the metrics are in the table rather than in a separate call, and where the constraint mechanism is the point rather than an afterthought. The cost is that it pulls in OR-Tools and a substantial scientific stack, and that like any fitted discretisation it can overfit if you let it see the data you will report on.
Editorial conclusion
Adopt OptBinning if you are building a scorecard or any model that needs a discretised predictor with guarantees, since the constrained optimisation gives you monotone event rates, minimum bin counts and an OPTIMAL status rather than quantile cuts that happen to look reasonable. Do not use it without a held-out split, because the method maximises separation on the data it is fitted to, and the example's total information value of 5.04 is a symptom of that. Before you commit, check the status attribute on every fit rather than assuming optimality, fit the binning on a training split and evaluate the resulting table on a validation one, and read the binning process documentation rather than only the API reference, because the process is where the overfitting and the constraint choices are actually decided.
Frequently asked questions
What is OptBinning?
It is a Python library implementing a mathematical programming formulation to solve the optimal binning problem for a binary, continuous and multiclass target, incorporating constraints not previously addressed. It is Apache-2.0 licensed, the author is Guillermo Navas-Palencia, and v1.0.0 was released on 2026-09-12.
How do I install OptBinning?
Run pip install optbinning for the current release from PyPI, pip install optbinning[distributed] to include the batch and stream binning algorithms, or pip install optbinning[ecos] to include the ecos solver. To install from source, clone the git repository, change into the directory and run pip install .
What dependencies does OptBinning need?
matplotlib, numpy 1.16.1 or newer, ortools 9.15 or newer, pandas, ropwr 1.0.0 or newer, scikit-learn 1.6.0 or newer and scipy 1.6.0 or newer. The distributed extra adds pympler and tdigest, and the test extra adds coverage, flake8, pytest, pyarrow, pympler and tdigest.
What does the OptBinning binning table contain?
A row per bin with the bin identifier, the interval, Count, Count percentage, Non-event, Event, Event rate, WoE, IV and JS, plus Totals row. The example on the breast cancer dataset gives six split points, eight bin rows including the empty Special and Missing rows, and a total IV of 5.043925.
How does OptBinning guarantee monotonicity?
The bin edges are the output of a constrained optimisation rather than of a rule, with OR-Tools providing the constraint programming solver by default. The example returns a status of OPTIMAL and the resulting event rates decrease strictly down the bins, from 0.974576 to 0.008475.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/guillermo-navas-palencia-optbinning)Was this useful?