{"id":13713006,"url":"https://github.com/guillermo-navas-palencia/optbinning","last_synced_at":"2026-04-08T13:31:13.150Z","repository":{"id":37572779,"uuid":"231076826","full_name":"guillermo-navas-palencia/optbinning","owner":"guillermo-navas-palencia","description":"Optimal binning: monotonic binning with constraints.  Support batch \u0026 stream optimal binning. Scorecard modelling and counterfactual explanations.","archived":false,"fork":false,"pushed_at":"2026-02-10T19:18:26.000Z","size":11047,"stargazers_count":513,"open_issues_count":46,"forks_count":112,"subscribers_count":17,"default_branch":"master","last_synced_at":"2026-02-10T22:43:21.230Z","etag":null,"topics":["batch-processing","binning","counterfactual-explanations","credit-scoring","mdlp","optimization","python","scorecard","stream","streaming-data","woe","woebinning"],"latest_commit_sha":null,"homepage":"http://gnpalencia.org/optbinning/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guillermo-navas-palencia.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-12-31T11:17:44.000Z","updated_at":"2026-02-08T21:41:23.000Z","dependencies_parsed_at":"2023-12-06T13:25:10.292Z","dependency_job_id":"b66f1a29-5cbb-41e3-a408-f147bbec16a9","html_url":"https://github.com/guillermo-navas-palencia/optbinning","commit_stats":{"total_commits":752,"total_committers":10,"mean_commits":75.2,"dds":"0.021276595744680882","last_synced_commit":"c446115bc9b418613b0a4d864b19ee557f5f0b61"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/guillermo-navas-palencia/optbinning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillermo-navas-palencia%2Foptbinning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillermo-navas-palencia%2Foptbinning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillermo-navas-palencia%2Foptbinning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillermo-navas-palencia%2Foptbinning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guillermo-navas-palencia","download_url":"https://codeload.github.com/guillermo-navas-palencia/optbinning/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillermo-navas-palencia%2Foptbinning/sbom","scorecard":{"id":448805,"data":{"date":"2025-08-11","repo":{"name":"github.com/guillermo-navas-palencia/optbinning","commit":"0720b8dd2b60a723cfb16e1f830da1d62598171a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.1,"checks":[{"name":"Code-Review","score":3,"reason":"Found 3/8 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/python-package.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":1,"reason":"0 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/guillermo-navas-palencia/optbinning/python-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/guillermo-navas-palencia/optbinning/python-package.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:35","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":2,"reason":"8 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-856 / GHSA-5545-2q6w-2gh6","Warn: Project is vulnerable to: GHSA-6p56-wp2h-9hxr","Warn: Project is vulnerable to: PYSEC-2021-857 / GHSA-f7c7-j99h-c22f","Warn: Project is vulnerable to: GHSA-fpfv-jqm9-f5jm","Warn: Project is vulnerable to: PYSEC-2020-73","Warn: Project is vulnerable to: PYSEC-2024-110 / GHSA-jw8x-6495-233v","Warn: Project is vulnerable to: PYSEC-2023-102","Warn: Project is vulnerable to: PYSEC-2023-114"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T07:37:22.088Z","repository_id":37572779,"created_at":"2025-08-19T07:37:22.089Z","updated_at":"2025-08-19T07:37:22.089Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31558380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["batch-processing","binning","counterfactual-explanations","credit-scoring","mdlp","optimization","python","scorecard","stream","streaming-data","woe","woebinning"],"created_at":"2024-08-02T23:01:25.875Z","updated_at":"2026-04-08T13:31:13.127Z","avatar_url":"https://github.com/guillermo-navas-palencia.png","language":"Python","funding_links":[],"categories":["Data Processing","Python","Technical Resources"],"sub_categories":["Data Pre-processing \u0026 Loading","Open Source/Access Responsible AI Software Packages"],"readme":"==========\nOptBinning\n==========\n\n.. image::  https://github.com/guillermo-navas-palencia/optbinning/workflows/CI/badge.svg\n   :target: https://github.com/guillermo-navas-palencia/optbinning/workflows/CI/badge.svg\n\n.. image::  https://img.shields.io/github/license/guillermo-navas-palencia/optbinning\n   :target: https://img.shields.io/github/license/guillermo-navas-palencia/optbinning\n\n.. image:: https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue\n   :target: https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue\n\n.. image:: https://img.shields.io/pypi/v/optbinning?color=blueviolet\n   :target: https://img.shields.io/pypi/v/optbinning?color=blueviolet\n\n.. image:: https://static.pepy.tech/badge/optbinning\n   :target: https://pepy.tech/project/optbinning\n\n.. image:: https://static.pepy.tech/badge/optbinning/month\n   :target: https://pepy.tech/project/optbinning/month\n\n\n**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.\n\n* **Papers**:\n   * Optimal binning: mathematical programming formulation. http://arxiv.org/abs/2001.08025\n   * Optimal counterfactual explanations for scorecard modelling. https://arxiv.org/abs/2104.08619\n* **Blog**: Optimal binning for streaming data. http://gnpalencia.org/blog/2020/binning_data_streams/\n\n.. list-table::\n\n    * - .. figure:: doc/source/_images/binning_binary.png\n\n      - .. figure:: doc/source/_images/binning_data_stream.gif\n\n.. list-table::\n\n    * - .. figure:: doc/source/_images/binning_2d_readme.png\n\n      - .. figure:: doc/source/_images/binning_2d_readme_woe.png\n\n\n.. contents:: **Table of Contents**\n\nInstallation\n============\n\nTo install the current release of OptBinning from PyPI:\n\n.. code-block:: text\n\n   pip install optbinning\n\nTo include batch and stream binning algorithms (this option is not required for most users):\n\n.. code-block:: text\n\n  pip install optbinning[distributed]\n\nTo include support for the `ecos \u003chttps://github.com/embotech/ecos\u003e`_ solver:\n\n.. code-block:: text\n\n  pip install optbinning[ecos]\n\nTo install from source, download or clone the git repository\n\n.. code-block:: text\n\n   git clone https://github.com/guillermo-navas-palencia/optbinning.git\n   cd optbinning\n   python setup.py install\n\nDependencies\n------------\nOptBinning requires\n\n* matplotlib\n* numpy (\u003e=1.16.1)\n* ortools (\u003e=9.4)\n* pandas\n* ropwr (\u003e=1.0.0)\n* scikit-learn (\u003e=1.6.0)\n* scipy (\u003e=1.6.0)\n\nOptBinning[distributed] requires additional packages\n\n* pympler\n* tdigest\n\n\nGetting started\n===============\n\nPlease visit the OptBinning documentation (**current** release) http://gnpalencia.org/optbinning/. If your are new to OptBinning, you can get started following the `tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html\u003e`_ and checking the API references.\n\nTutorials\n---------\n\n* `Optimal binning tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html#optimal-binning-tutorials\u003e`_\n* `Binning process tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html#binning-process-tutorials\u003e`_\n* `Scorecard and counterfactual tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html#scorecard-tutorials\u003e`_\n* `Optimal piecewise binning tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html#optimal-piecewise-binning-tutorials\u003e`_\n* `Batch and stream optimal binning tutorials \u003chttp://gnpalencia.org/optbinning/tutorials.html#optimal-binning-for-batch-and-streaming-data-processing\u003e`_\n* `Optimal binning under uncertainty \u003chttp://gnpalencia.org/optbinning/tutorials.html#optimal-binning-under-uncertainty\u003e`_\n* `Optimal binning 2D \u003chttp://gnpalencia.org/optbinning/tutorials.html#optimal-binning-2d\u003e`_\n\n\nExample: Optimal binning with binary target\n-------------------------------------------\n\nLet's load a well-known dataset from the UCI repository and choose a variable to discretize and the binary target.\n\n.. code-block:: python\n\n   import pandas as pd\n   from sklearn.datasets import load_breast_cancer\n\n   data = load_breast_cancer()\n   df = pd.DataFrame(data.data, columns=data.feature_names)\n\n   variable = \"mean radius\"\n   x = df[variable].values\n   y = data.target\n\nImport and instantiate an ``OptimalBinning`` object class. We pass the variable name, its data type, and a solver, in this case, we choose the constraint programming solver. Fit the optimal binning object with arrays ``x`` and ``y``.\n\n.. code-block:: python\n\n   from optbinning import OptimalBinning\n   optb = OptimalBinning(name=variable, dtype=\"numerical\", solver=\"cp\")\n   optb.fit(x, y)\n\nCheck status and retrieve optimal split points\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.status\n   'OPTIMAL'\n\n   \u003e\u003e\u003e optb.splits\n   array([11.42500019, 12.32999992, 13.09499979, 13.70499992, 15.04500008,\n          16.92500019])\n\nThe optimal binning algorithms return a binning table; a binning table displays the binned data and several metrics for each bin. Call the method ``build``, which returns a pandas.DataFrame.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.build()\n\n.. code-block:: text\n\n                      Bin  Count  Count (%)  Non-event  Event  Event rate       WoE        IV        JS\n   0        [-inf, 11.43)    118   0.207381          3    115    0.974576  -3.12517  0.962483  0.087205\n   1       [11.43, 12.33)     79   0.138840          3     76    0.962025  -2.71097  0.538763  0.052198\n   2       [12.33, 13.09)     68   0.119508          7     61    0.897059  -1.64381  0.226599  0.025513\n   3       [13.09, 13.70)     49   0.086116         10     39    0.795918 -0.839827  0.052131  0.006331\n   4       [13.70, 15.05)     83   0.145870         28     55    0.662651 -0.153979  0.003385  0.000423\n   5       [15.05, 16.93)     54   0.094903         44     10    0.185185   2.00275  0.359566  0.038678\n   6         [16.93, inf)    118   0.207381        117      1    0.008475   5.28332  2.900997  0.183436\n   7              Special      0   0.000000          0      0    0.000000         0  0.000000  0.000000\n   8              Missing      0   0.000000          0      0    0.000000         0  0.000000  0.000000\n   Totals                    569   1.000000        212    357    0.627417            5.043925  0.393784\n\nYou can use the method ``plot`` to visualize the histogram and WoE or event rate curve. Note that the Bin ID corresponds to the binning table index.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.plot(metric=\"woe\")\n\n.. image:: doc/source/_images/binning_readme_example_woe.png\n   :target: doc/source/_images/binning_readme_example_woe.png\n\nOptionally, you can show the binning plot with the actual bin widths.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.plot(metric=\"woe\", style=\"actual\", add_special=False, add_missing=False)\n\n.. image:: doc/source/_images/binning_readme_example_split_woe.png\n   :target: doc/source/_images/binning_readme_example_split_woe.png\n\nNow that we have checked the binned data, we can transform our original data into WoE or event rate values.\n\n.. code-block:: python\n\n   x_transform_woe = optb.transform(x, metric=\"woe\")\n   x_transform_event_rate = optb.transform(x, metric=\"event_rate\")\n\nThe ``analysis`` method performs a statistical analysis of the binning table, computing the statistics Gini index, Information Value (IV), Jensen-Shannon divergence, and the quality score. Additionally, several statistical significance tests between consecutive bins of the contingency table are performed.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.analysis()\n\n.. code-block:: text\n\n   ---------------------------------------------\n   OptimalBinning: Binary Binning Table Analysis\n   ---------------------------------------------\n\n     General metrics\n\n       Gini index               0.87541620\n       IV (Jeffrey)             5.04392547\n       JS (Jensen-Shannon)      0.39378376\n       Hellinger                0.47248971\n       Triangular               1.25592041\n       KS                       0.72862164\n       HHI                      0.15727342\n       HHI (normalized)         0.05193260\n       Cramer's V               0.80066760\n       Quality score            0.00000000\n\n     Monotonic trend            descending\n\n     Significance tests\n\n       Bin A  Bin B  t-statistic       p-value  P[A \u003e B]      P[B \u003e A]\n           0      1     0.252432  6.153679e-01  0.684380  3.156202e-01\n           1      2     2.432829  1.188183e-01  0.948125  5.187465e-02\n           2      3     2.345804  1.256207e-01  0.937874  6.212635e-02\n           3      4     2.669235  1.023052e-01  0.955269  4.473083e-02\n           4      5    29.910964  4.523477e-08  1.000000  9.814594e-12\n           5      6    19.324617  1.102754e-05  0.999999  1.216668e-06\n\nPrint overview information about the options settings, problem statistics, and the solution of the computation.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.information(print_level=2)\n\n.. code-block:: text\n\n   optbinning (Version 0.21.0)\n   Copyright (c) 2019-2025 Guillermo Navas-Palencia, Apache License 2.0\n\n     Begin options\n       name                         mean radius   * U\n       dtype                          numerical   * d\n       prebinning_method                   cart   * d\n       solver                                cp   * d\n       divergence                            iv   * d\n       max_n_prebins                         20   * d\n       min_prebin_size                     0.05   * d\n       min_n_bins                            no   * d\n       max_n_bins                            no   * d\n       min_bin_size                          no   * d\n       max_bin_size                          no   * d\n       min_bin_n_nonevent                    no   * d\n       max_bin_n_nonevent                    no   * d\n       min_bin_n_event                       no   * d\n       max_bin_n_event                       no   * d\n       monotonic_trend                     auto   * d\n       min_event_rate_diff                    0   * d\n       max_pvalue                            no   * d\n       max_pvalue_policy            consecutive   * d\n       gamma                                  0   * d\n       class_weight                          no   * d\n       cat_cutoff                            no   * d\n       user_splits                           no   * d\n       user_splits_fixed                     no   * d\n       special_codes                         no   * d\n       split_digits                          no   * d\n       mip_solver                           bop   * d\n       time_limit                           100   * d\n       verbose                            False   * d\n     End options\n\n     Name    : mean radius\n     Status  : OPTIMAL\n\n     Pre-binning statistics\n       Number of pre-bins                     9\n       Number of refinements                  1\n\n     Solver statistics\n       Type                                  cp\n       Number of booleans                    26\n       Number of branches                    58\n       Number of conflicts                    0\n       Objective value                  5043922\n       Best objective bound             5043922\n\n     Timing\n       Total time                          0.04 sec\n       Pre-processing                      0.00 sec   (  0.33%)\n       Pre-binning                         0.00 sec   (  5.54%)\n       Solver                              0.04 sec   ( 93.03%)\n         model generation                  0.03 sec   ( 85.61%)\n         optimizer                         0.01 sec   ( 14.39%)\n       Post-processing                     0.00 sec   (  0.30%)\n\n\nExample: Optimal binning 2D with binary target\n----------------------------------------------\n\nIn this case, we choose two variables to discretized and the binary target.\n\n.. code-block:: python\n\n   import pandas as pd\n   from sklearn.datasets import load_breast_cancer\n\n   data = load_breast_cancer()\n   df = pd.DataFrame(data.data, columns=data.feature_names)\n\n   variable1 = \"mean radius\"\n   variable2 = \"worst concavity\"\n   x = df[variable1].values\n   y = df[variable2].values\n   z = data.target\n\nImport and instantiate an ``OptimalBinning2D`` object class. We pass the variable names, and monotonic trends. Fit the optimal binning object with arrays ``x``, ``y`` and ``z``.\n\n.. code-block:: python\n\n   from optbinning import OptimalBinning2D\n   optb = OptimalBinning2D(name_x=variable1, name_y=variable2, monotonic_trend_x=\"descending\",\n                           monotonic_trend_y=\"descending\", min_bin_size=0.05)\n   optb.fit(x, y, z)\n\n\nShow binning table:\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.build()\n\n.. code-block:: text\n\n                   Bin x         Bin y  Count  Count (%)  Non-event  Event  Event rate       WoE        IV        JS\n   0        (-inf, 13.70)  (-inf, 0.21)    219   0.384886          1    218    0.995434 -4.863346  2.946834  0.199430\n   1         [13.70, inf)  (-inf, 0.21)     48   0.084359          5     43    0.895833 -1.630613  0.157946  0.017811\n   2        (-inf, 13.09)  [0.21, 0.38)     48   0.084359          1     47    0.979167 -3.328998  0.422569  0.037010\n   3       [13.09, 15.05)  [0.21, 0.38)     46   0.080844         17     29    0.630435 -0.012933  0.000013  0.000002\n   4         [15.05, inf)  [0.21, 0.32)     32   0.056239         29      3    0.093750  2.789833  0.358184  0.034271\n   5         [15.05, inf)   [0.32, inf)    129   0.226714        128      1    0.007752  5.373180  3.229133  0.201294\n   6        (-inf, 15.05)   [0.38, inf)     47   0.082601         31     16    0.340426  1.182548  0.119920  0.014173\n   7              Special       Special      0   0.000000          0      0    0.000000  0.000000  0.000000  0.000000\n   8              Missing       Missing      0   0.000000          0      0    0.000000  0.000000  0.000000  0.000000\n   Totals                                  569   1.000000        212    357    0.627417            7.234600  0.503991\n\nSimilar to the optimal binning, you can generate a histogram 2D to visualize WoE and event rate.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e optb.binning_table.plot(metric=\"event_rate\")\n\n\n.. image:: doc/source/_images/binning_2d_readme_example.png\n   :target: doc/source/_images/binning_2d_readme_example.png\n\n\nExample: Scorecard with continuous target\n-----------------------------------------\n\nLet's load the California housing dataset.\n\n.. code-block:: python\n\n   import pandas as pd\n\n   from sklearn.datasets import fetch_california_housing\n   from sklearn.linear_model import HuberRegressor\n\n   from optbinning import BinningProcess\n   from optbinning import Scorecard\n\n   data = fetch_california_housing()\n\n   target = \"target\"\n   variable_names = data.feature_names\n   X = pd.DataFrame(data.data, columns=variable_names)\n   y = data.target\n\n\nInstantiate a binning process, an estimator, and a scorecard with scaling\nmethod and reverse mode.\n\n.. code-block:: python\n\n   binning_process = BinningProcess(variable_names)\n\n   estimator = HuberRegressor(max_iter=200)\n\n   scorecard = Scorecard(binning_process=binning_process, estimator=estimator,\n                         scaling_method=\"min_max\",\n                         scaling_method_params={\"min\": 0, \"max\": 100},\n                         reverse_scorecard=True)\n\n   scorecard.fit(X, y)\n\nPrint overview information about the options settings, problems statistics,\nand the number of selected variables after the binning process.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e scorecard.information(print_level=2)\n\n.. code-block:: text\n\n   optbinning (Version 0.21.0)\n   Copyright (c) 2019-2025 Guillermo Navas-Palencia, Apache License 2.0\n\n     Begin options\n       binning_process                      yes   * U\n       estimator                            yes   * U\n       scaling_method                   min_max   * U\n       scaling_method_params                yes   * U\n       intercept_based                    False   * d\n       reverse_scorecard                   True   * U\n       rounding                           False   * d\n       verbose                            False   * d\n     End options\n\n     Statistics\n       Number of records                  20640\n       Number of variables                    8\n       Target type                   continuous\n\n       Number of numerical                    8\n       Number of categorical                  0\n       Number of selected                     8\n\n     Timing\n       Total time                          2.31 sec\n       Binning process                     1.83 sec   ( 79.00%)\n       Estimator                           0.41 sec   ( 17.52%)\n       Build scorecard                     0.08 sec   (  3.40%)\n         rounding                          0.00 sec   (  0.00%)\n\n.. code-block:: python\n\n   \u003e\u003e\u003e scorecard.table(style=\"summary\")\n\nTwo scorecard styles are available: ``style=\"summary\"`` shows the variable name, and their corresponding bins and assigned points; ``style=\"detailed\"`` adds information from the corresponding binning table.\n\n.. code-block:: text\n\n        Variable                 Bin     Points\n   0      MedInc        [-inf, 1.90)   9.869224\n   1      MedInc        [1.90, 2.16)  10.896940\n   2      MedInc        [2.16, 2.37)  11.482997\n   3      MedInc        [2.37, 2.66)  12.607805\n   4      MedInc        [2.66, 2.88)  13.609078\n   ..        ...                 ...        ...\n   2   Longitude  [-118.33, -118.26)  10.470401\n   3   Longitude  [-118.26, -118.16)   9.092391\n   4   Longitude      [-118.16, inf)  10.223936\n   5   Longitude             Special   1.376862\n   6   Longitude             Missing   1.376862\n\n   [94 rows x 3 columns]\n\n\n.. code-block:: python\n\n   \u003e\u003e\u003e scorecard.table(style=\"detailed\")\n\n.. code-block:: text\n\n        Variable  Bin id                 Bin  Count  Count (%)  ...  Zeros count       WoE        IV  Coefficient     Points\n   0      MedInc       0        [-inf, 1.90)   2039   0.098789  ...            0 -0.969609  0.095786     0.990122   9.869224\n   1      MedInc       1        [1.90, 2.16)   1109   0.053731  ...            0 -0.836618  0.044952     0.990122  10.896940\n   2      MedInc       2        [2.16, 2.37)   1049   0.050824  ...            0 -0.760779  0.038666     0.990122  11.482997\n   3      MedInc       3        [2.37, 2.66)   1551   0.075145  ...            0 -0.615224  0.046231     0.990122  12.607805\n   4      MedInc       4        [2.66, 2.88)   1075   0.052083  ...            0 -0.485655  0.025295     0.990122  13.609078\n   ..        ...     ...                 ...    ...        ...  ...          ...       ...       ...          ...        ...\n   2   Longitude       2  [-118.33, -118.26)   1120   0.054264  ...            0 -0.011006  0.000597     0.566265  10.470401\n   3   Longitude       3  [-118.26, -118.16)   1127   0.054603  ...            0 -0.322802  0.017626     0.566265   9.092391\n   4   Longitude       4      [-118.16, inf)   6530   0.316376  ...            0 -0.066773  0.021125     0.566265  10.223936\n   5   Longitude       5             Special      0   0.000000  ...            0 -2.068558  0.000000     0.566265   1.376862\n   6   Longitude       6             Missing      0   0.000000  ...            0 -2.068558  0.000000     0.566265   1.376862\n\n   [94 rows x 14 columns]\n\nCompute score and predicted target using the fitted estimator.\n\n.. code-block:: python\n\n   score = scorecard.score(X)\n   y_pred = scorecard.predict(X)\n\n\nExample: Counterfactual explanations for scorecard with continuous target\n-------------------------------------------------------------------------\n\nFirst, we load the dataset and a scorecard previously developed.\n\n.. code-block:: python\n\n   import pandas as pd\n\n   from optbinning import Scorecard\n   from optbinning.scorecard import Counterfactual\n\n   from sklearn.datasets import load_boston\n\n   data = load_boston()\n   X = pd.DataFrame(data.data, columns=data.feature_names)\n\n   scorecard = Scorecard.load(\"myscorecard.pkl\")\n\nWe create a new Counterfactual instance that is fitted with the dataset\nused during the scorecard development. Then, we select a sample from which to generate\ncounterfactual explanations.\n\n.. code-block:: python\n\n   cf = Counterfactual(scorecard=scorecard)\n   cf.fit(X)\n\n   query = X.iloc[0, :].to_frame().T\n\nThe scorecard model predicts 26.8. However, we would like to find out what needs to be\nchanged to return a prediction greater or equal to 30.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e query\n         CRIM    ZN  INDUS  CHAS    NOX     RM   AGE   DIS  RAD    TAX  PTRATIO      B  LSTAT\n   0  0.00632  18.0   2.31   0.0  0.538  6.575  65.2  4.09  1.0  296.0     15.3  396.9   4.98\n\n   \u003e\u003e\u003e scorecard.predict(query)\n   array([26.83423364])\n\n\nWe can generate a single counterfactual explanation:\n\n.. code-block:: python\n\n   \u003e\u003e\u003e cf.generate(query=query, y=30, outcome_type=\"continuous\", n_cf=1, max_changes=3,\n                   hard_constraints=[\"min_outcome\"])\n\n   \u003e\u003e\u003e cf.status\n   'OPTIMAL'\n\n   \u003e\u003e\u003e cf.display(show_only_changes=True, show_outcome=True)\n              CRIM ZN INDUS CHAS           NOX            RM AGE DIS RAD TAX PTRATIO  B LSTAT   outcome\n   0  [0.04, 0.07)  -     -    -  [0.45, 0.50)  [6.94, 7.44)   -   -   -   -       -  -     -  31.28763\n\n\nOr simultaneously three counterfactuals, enforcing diversity on the feature values and selecting only a few actionable features.\n\n.. code-block:: python\n\n   \u003e\u003e\u003e cf.generate(query=query, y=30, outcome_type=\"continuous\", n_cf=3, max_changes=3,\n                   hard_constraints=[\"diversity_values\", \"min_outcome\"],\n                   actionable_features=[\"CRIM\", \"NOX\", \"RM\", \"PTRATIO\"])\n\n   \u003e\u003e\u003e cf.status\n   'OPTIMAL'\n\n   \u003e\u003e\u003e cf.display(show_only_changes=True, show_outcome=True)\n              CRIM ZN INDUS CHAS           NOX            RM AGE DIS RAD TAX         PTRATIO  B LSTAT    outcome\n   0  [0.03, 0.04)  -     -    -  [0.42, 0.45)  [6.94, 7.44)   -   -   -   -               -  -     -  31.737844\n   0  [0.04, 0.07)  -     -    -             -   [7.44, inf)   -   -   -   -  [17.85, 18.55)  -     -  36.370086\n   0             -  -     -    -  [0.45, 0.50)  [6.68, 6.94)   -   -   -   -   [-inf, 15.15)  -     -  30.095258\n\n\nBenchmarks\n==========\n\nThe following table shows how OptBinning compares to `scorecardpy \u003chttps://github.com/ShichenXie/scorecardpy\u003e`_ 0.1.9.1.1 on a selection of variables from the public dataset, Home Credit Default Risk - Kaggle’s competition `Link \u003chttps://www.kaggle.com/c/home-credit-default-risk/data\u003e`_. This dataset contains 307511 samples.The experiments were run on Intel(R) Core(TM) i5-3317 CPU at 1.70GHz, using a single core, running Linux. For scorecardpy, we use default settings only increasing the maximum number of bins ``bin_num_limit=20``. For OptBinning, we use default settings (``max_n_prebins=20``) only changing the maximum allowed p-value between consecutive bins, ``max_pvalue=0.05``.\n\nTo compare softwares we use the shifted geometric mean, typically used in mathematical optimization benchmarks: http://plato.asu.edu/bench.html. Using the shifted (by 1 second) geometric mean we found that **OptBinning** is **17x** faster than scorecardpy, with an average IV increment of **12%**. Besides the speed and IV gains, OptBinning includes many more constraints and monotonicity options.\n\n+----------------------------+------------------+----------------+-----------------+---------------+\n| Variable                   | scorecardpy_time | scorecardpy_IV | optbinning_time | optbinning_IV |\n+============================+==================+================+=================+===============+\n| AMT_INCOME_TOTAL           |           6.18 s |    0.010606    |      0.363 s    |   0.011705    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| NAME_CONTRACT_TYPE (C)     |           3.72 s |    0.015039    |      0.148 s    |   0.015039    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| AMT_CREDIT                 |           7.10 s |    0.053593    |      0.634 s    |   0.059311    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| ORGANIZATION_TYPE (C)      |           6.31 s |    0.063098    |      0.274 s    |   0.071520    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| AMT_ANNUITY                |           6.51 s |    0.024295    |      0.648 s    |   0.031179    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| AMT_GOODS_PRICE            |           6.95 s |    0.056923    |      0.401 s    |   0.092032    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| NAME_HOUSING_TYPE (C)      |           3.57 s |    0.015055    |      0.140 s    |   0.015055    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| REGION_POPULATION_RELATIVE |           4.33 s |    0.026578    |      0.392 s    |   0.035567    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| DAYS_BIRTH                 |           5.18 s |    0.081270    |      0.564 s    |   0.086539    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| OWN_CAR_AGE                |           4.85 s |    0.021429    |      0.055 s    |   0.021890    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| OCCUPATION_TYPE (C)        |           4.24 s |    0.077606    |      0.201 s    |   0.079540    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| APARTMENTS_AVG             |           5.61 s |    0.032247(*) |      0.184 s    |   0.032415    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| BASEMENTAREA_AVG           |           5.14 s |    0.022320    |      0.119 s    |   0.022639    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| YEARS_BUILD_AVG            |           4.49 s |    0.016033    |      0.055 s    |   0.016932    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| EXT_SOURCE_2               |           5.21 s |    0.298463    |      0.606 s    |   0.321417    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| EXT_SOURCE_3               |           5.08 s |    0.316352    |      0.303 s    |   0.334975    |\n+----------------------------+------------------+----------------+-----------------+---------------+\n| **TOTAL**                  |      **84.47 s** |**1.130907**    | **5.087 s**     | **1.247756**  |\n+----------------------------+------------------+----------------+-----------------+---------------+\n\n(C): categorical variable.\n(*): max p-value between consecutive bins \u003e 0.05.\n\nThe binning of variables with monotonicity trend peak or valley can benefit from the option ``monotonic_trend=\"auto_heuristic\"`` at the expense of finding a suboptimal solution for some cases. The following table compares the options ``monotonic_trend=\"auto\"`` and ``monotonic_trend=\"auto_heuristic\"``,\n\n+----------------------------+----------------+----------------+----------------+----------------+\n| Variable                   |      auto_time |        auto_IV | heuristic_time |   heuristic_IV |\n+============================+================+================+================+================+\n| AMT_INCOME_TOTAL           |      0.363 s   |    0.011705    |      0.322 s   |    0.011705    |\n+----------------------------+----------------+----------------+----------------+----------------+\n| AMT_CREDIT                 |      0.634 s   |   0.059311     |      0.469 s   |    0.058643    |\n+----------------------------+----------------+----------------+----------------+----------------+\n| AMT_ANNUITY                |      0.648 s   |   0.031179     |      0.505 s   |    0.031179    |\n+----------------------------+----------------+----------------+----------------+----------------+\n| AMT_GOODS_PRICE            |      0.401 s   |   0.092032     |      0.299 s   |    0.092032    |\n+----------------------------+----------------+----------------+----------------+----------------+\n| REGION_POPULATION_RELATIVE |      0.392 s   |   0.035567     |      0.244 s   |    0.035567    |\n+----------------------------+----------------+----------------+----------------+----------------+\n| **TOTAL**                  | **2.438 s**    | **0.229794**   | **1.839 s**    | **0.229126**   |\n+----------------------------+----------------+----------------+----------------+----------------+\n\nObserve that CPU time is reduced by 25% losing less than 1% in IV. The differences in CPU time are more noticeable as the\nnumber of bins increases, see http://gnpalencia.org/optbinning/tutorials/tutorial_binary_large_scale.html.\n\n\nContributing\n============\nFound a bug? Want to contribute with a new feature, improve documentation, or add examples? We encourage you to create pull requests and/or open GitHub issues. Thanks! :octocat: :tada: :+1:\n\n\nWho uses OptBinning?\n====================\nWe would like to list companies using OptBinning. Please send a PR with your company name and @githubhandle if you may.\n\nCurrently **officially** using OptBinning:\n\n1. `Jeitto \u003chttps://www.jeitto.com.br\u003e`_ [`@BrennerPablo \u003chttps://github.com/BrennerPablo\u003e`_ \u0026 `@ds-mauri \u003chttps://github.com/ds-mauri\u003e`_ \u0026 `@GabrielSGoncalves \u003chttps://github.com/GabrielSGoncalves\u003e`_]\n2. `Bilendo \u003chttps://www.bilendo.de\u003e`_ [`@FlorianKappert \u003chttps://github.com/floriankappert\u003e`_ \u0026 `@JakobBeyer \u003chttps://github.com/jakobbeyer\u003e`_]\n3. `Aplazame \u003chttps://www.aplazame.com/\u003e`_\n4. `Praelexis Credit \u003chttps://www.praelexis.com/praelexis-credit/\u003e`_\n5. `ING \u003cwww.ing.com\u003e`_ \n6. `DBRS Morningstar \u003chttps://www.dbrsmorningstar.com/\u003e`_\n7. `Loginom \u003chttps://loginom.ru/\u003e`_\n8. `Risika \u003chttps://risika.com/\u003e`_\n9. `Tamara \u003chttps://tamara.co/\u003e`_\n10. `BBVA AI Factory \u003chttps://www.bbvaaifactory.com/\u003e`_\n11. `N26 \u003chttps://n26.com/\u003e`_\n12. `Home Credit International \u003chttps://www.homecredit.net/\u003e`_\n13. `Farm Credit Canada \u003chttps://www.fcc-fac.ca/\u003e`_\n\n\nCitation\n========\n\nIf you use OptBinning in your research/work, please cite the paper using the following BibTeX::\n\n  @article{Navas-Palencia2020OptBinning,\n    title     = {Optimal binning: mathematical programming formulation},\n    author    = {Guillermo Navas-Palencia},\n    year      = {2020},\n    eprint    = {2001.08025},\n    archivePrefix = {arXiv},\n    primaryClass = {cs.LG},\n    volume    = {abs/2001.08025},\n    url       = {http://arxiv.org/abs/2001.08025},\n  }\n\n  @article{Navas-Palencia2021Counterfactual,\n    title     = {Optimal Counterfactual Explanations for Scorecard modelling},\n    author    = {Guillermo Navas-Palencia},\n    year      = {2021},\n    eprint    = {2104.08619},\n    archivePrefix = {arXiv},\n    primaryClass = {cs.LG},\n    volume    = {abs/2104.08619},\n    url       = {http://arxiv.org/abs/2104.08619},\n  }  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillermo-navas-palencia%2Foptbinning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguillermo-navas-palencia%2Foptbinning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillermo-navas-palencia%2Foptbinning/lists"}