{
"cells": [
{
"cell_type": "markdown",
"id": "intro-md",
"metadata": {},
"source": [
"# Benchmark: AutoCarver vs. optbinning vs. KBinsDiscretizer\n",
"\n",
"This notebook runs the three binning libraries side-by-side on two public datasets:\n",
"\n",
"1. **German Credit** — binary classification, mixed numeric / categorical features, 1,000 rows.\n",
"2. **California Housing** — regression, all-numeric features, 20,640 rows.\n",
"\n",
"For each library and dataset, we report:\n",
"\n",
"- **`fit` and `transform` wall-clock** (seconds)\n",
"- **Downstream-model score** — AUC for binary, R² for regression — using a linear model (logistic regression / ridge) on the one-hot-encoded bin output\n",
"- **`train` → `test` score drop** as a coarse proxy for drift sensitivity\n",
"\n",
"All three libraries see the same `train + dev` data and are evaluated on the same held-out `test`. AutoCarver uses the dev sample for its built-in robustness veto; optbinning and KBinsDiscretizer don't have a dev-set concept and so treat the union of train + dev as one pooled training set — which is the comparison practitioners actually run.\n",
"\n",
"**This is not an IV / Tschuprow's T leaderboard.** Those metrics structurally favour the library whose objective they are. The downstream-model score is the metric a real scorecard team would use to pick a binner.\n",
"\n",
"Numbers come from a single run on a single machine with a fixed seed; treat them as illustrative, not as authoritative benchmark figures. Re-run on your own data before drawing conclusions."
]
},
{
"cell_type": "markdown",
"id": "setup-md",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "imports",
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"import warnings\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"from sklearn.datasets import fetch_california_housing, fetch_openml\n",
"from sklearn.linear_model import LogisticRegression, Ridge\n",
"from sklearn.metrics import r2_score, roc_auc_score\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import KBinsDiscretizer\n",
"\n",
"from AutoCarver import BinaryCarver, ContinuousCarver, Features\n",
"from AutoCarver.discretizers.utils.base_discretizer import ProcessingConfig\n",
"\n",
"try:\n",
" from optbinning import ContinuousOptimalBinning, OptimalBinning\n",
"\n",
" HAS_OPTBINNING = True\n",
"except ImportError:\n",
" HAS_OPTBINNING = False\n",
" print('optbinning is not installed \\u2014 its rows will be skipped.')\n",
"\n",
"SEED = 42\n",
"warnings.filterwarnings('ignore')\n",
"plt.rcParams['figure.figsize'] = (10, 3.5)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "helpers",
"metadata": {},
"outputs": [],
"source": [
"def one_hot(df):\n",
" \"\"\"Treat every bin label as a categorical level and one-hot encode it.\n",
"\n",
" Lets a linear downstream model consume any of the three libraries' outputs\n",
" uniformly, without us computing WoE per bin.\n",
" \"\"\"\n",
" return pd.get_dummies(df.astype(str), drop_first=True).astype(float)\n",
"\n",
"\n",
"def fit_eval_binary(X_train, X_test, y_train, y_test):\n",
" Xtr = one_hot(X_train)\n",
" Xte = one_hot(X_test).reindex(columns=Xtr.columns, fill_value=0.0)\n",
" model = LogisticRegression(max_iter=1000, random_state=SEED).fit(Xtr, y_train)\n",
" return {\n",
" 'train_auc': roc_auc_score(y_train, model.predict_proba(Xtr)[:, 1]),\n",
" 'test_auc': roc_auc_score(y_test, model.predict_proba(Xte)[:, 1]),\n",
" }\n",
"\n",
"\n",
"def fit_eval_regression(X_train, X_test, y_train, y_test):\n",
" Xtr = one_hot(X_train)\n",
" Xte = one_hot(X_test).reindex(columns=Xtr.columns, fill_value=0.0)\n",
" model = Ridge(random_state=SEED).fit(Xtr, y_train)\n",
" return {\n",
" 'train_r2': r2_score(y_train, model.predict(Xtr)),\n",
" 'test_r2': r2_score(y_test, model.predict(Xte)),\n",
" }\n",
"\n",
"\n",
"def plot_bars(results_df, score_cols, title):\n",
" fig, axes = plt.subplots(1, len(score_cols), figsize=(4 * len(score_cols), 3.5))\n",
" if len(score_cols) == 1:\n",
" axes = [axes]\n",
" for ax, col in zip(axes, score_cols):\n",
" results_df.plot.bar(x='library', y=col, ax=ax, legend=False, color='#4C72B0')\n",
" ax.set_title(col)\n",
" ax.set_xlabel('')\n",
" ax.tick_params(axis='x', rotation=0)\n",
" fig.suptitle(title)\n",
" fig.tight_layout()\n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "binners",
"metadata": {},
"outputs": [],
"source": [
"from AutoCarver.combinations.binary import CramervCombinations\n",
"\n",
"MAX_N_MOD = 5\n",
"MIN_FREQ = 0.05\n",
"\n",
"def bin_with_autocarver(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, kind):\n",
" Carver = BinaryCarver if kind == 'binary' else ContinuousCarver\n",
" features = Features(categoricals=categoricals, numericals=quantitatives)\n",
" config = ProcessingConfig(verbose=False, dropna=False, ordinal_encoding=False) # showing statistics\n",
" combination_evaluator = CramervCombinations() if kind == 'binary' else None\n",
" carver = Carver(features=features, min_freq=MIN_FREQ, max_n_mod=MAX_N_MOD, config=config,combination_evaluator=combination_evaluator)\n",
"\n",
" t0 = time.perf_counter()\n",
" X_tr = carver.fit_transform(X_train.copy(), y_train, X_dev=X_dev.copy(), y_dev=y_dev)\n",
" fit_t = time.perf_counter() - t0\n",
"\n",
" X_dv = carver.transform(X_dev.copy())\n",
" t1 = time.perf_counter()\n",
" X_te = carver.transform(X_test.copy())\n",
" transform_t = time.perf_counter() - t1\n",
" return pd.concat([X_tr, X_dv]), X_te, fit_t, transform_t, carver\n",
"\n",
"\n",
"def bin_with_optbinning(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, kind):\n",
" Cls = OptimalBinning if kind == 'binary' else ContinuousOptimalBinning\n",
" X_all = pd.concat([X_train, X_dev])\n",
" y_all = pd.concat([y_train, y_dev])\n",
" binners = {}\n",
" train_binned = pd.DataFrame(index=X_all.index)\n",
" test_binned = pd.DataFrame(index=X_test.index)\n",
"\n",
" t0 = time.perf_counter()\n",
" for col in X_all.columns:\n",
" dtype = 'categorical' if col in categoricals else 'numerical'\n",
" binner = Cls(name=col, dtype=dtype, min_prebin_size=MIN_FREQ/2, max_n_bins=MAX_N_MOD)\n",
" binner.fit(X_all[col].to_numpy(), y_all.to_numpy())\n",
" binners[col] = binner\n",
" train_binned[col] = binner.transform(X_all[col].to_numpy(), metric='bins')\n",
" fit_t = time.perf_counter() - t0\n",
"\n",
" t1 = time.perf_counter()\n",
" for col, b in binners.items():\n",
" test_binned[col] = b.transform(X_test[col].to_numpy(), metric='bins')\n",
" transform_t = time.perf_counter() - t1\n",
" return train_binned, test_binned, fit_t, transform_t, binners\n",
"\n",
"\n",
"def bin_with_kbins(X_train, X_dev, X_test, categoricals, quantitatives, n_bins=5):\n",
" X_all = pd.concat([X_train, X_dev])\n",
" num_train = X_all[quantitatives].apply(lambda c: c.fillna(c.median()))\n",
" num_test = X_test[quantitatives].apply(lambda c: c.fillna(c.median()))\n",
" kbd = KBinsDiscretizer(n_bins=n_bins, encode='ordinal', strategy='quantile')\n",
"\n",
" t0 = time.perf_counter()\n",
" binned_num_train = pd.DataFrame(\n",
" kbd.fit_transform(num_train), columns=quantitatives, index=X_all.index\n",
" )\n",
" fit_t = time.perf_counter() - t0\n",
"\n",
" t1 = time.perf_counter()\n",
" binned_num_test = pd.DataFrame(\n",
" kbd.transform(num_test), columns=quantitatives, index=X_test.index\n",
" )\n",
" transform_t = time.perf_counter() - t1\n",
"\n",
" # KBins has no opinion on categoricals — pass them through as labels\n",
" train = pd.concat([binned_num_train, X_all[categoricals].astype(str)], axis=1)\n",
" test = pd.concat([binned_num_test, X_test[categoricals].astype(str)], axis=1)\n",
" return train, test, fit_t, transform_t, kbd"
]
},
{
"cell_type": "markdown",
"id": "binary-md",
"metadata": {},
"source": [
"## Binary classification — German Credit\n",
"\n",
"20 features (numeric + categorical), 1,000 rows, target = `class == 'bad'`. Train / dev / test split = 60 / 20 / 20 %."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "381a7051",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"train=600, dev=200, test=200\n",
"categoricals=13, numericals=7\n",
"bad rate (train)=0.300, (test)=0.300\n"
]
}
],
"source": [
"credit = fetch_openml(data_id=31, as_frame=True)\n",
"df = credit.frame.copy()\n",
"\n",
"y_binary = (df['class'] == 'bad').astype(int)\n",
"X_binary = df.drop(columns=['class'])\n",
"\n",
"X_train, X_rest, y_train, y_rest = train_test_split(\n",
" X_binary, y_binary, test_size=0.4, random_state=SEED, stratify=y_binary,\n",
")\n",
"X_dev, X_test, y_dev, y_test = train_test_split(\n",
" X_rest, y_rest, test_size=0.5, random_state=SEED, stratify=y_rest,\n",
")\n",
"\n",
"categoricals = [c for c in X_binary.columns if X_binary[c].dtype == object or isinstance(X_binary[c].dtype, pd.CategoricalDtype)]\n",
"quantitatives = [c for c in X_binary.columns if c not in categoricals]\n",
"\n",
"print(f'train={len(X_train)}, dev={len(X_dev)}, test={len(X_test)}')\n",
"print(f'categoricals={len(categoricals)}, numericals={len(quantitatives)}')\n",
"print(f'bad rate (train)={y_train.mean():.3f}, (test)={y_test.mean():.3f}')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "run-binary",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"WARNING: No robust combination for Categorical('own_telephone'). Consider increasing the size of X_dev or dropping the feature (X not representative of X_dev for this feature).\n",
"WARNING: No robust combination for Categorical('foreign_worker'). Consider increasing the size of X_dev or dropping the feature (X not representative of X_dev for this feature).\n",
"WARNING: No robust combination for Numerical('residence_since'). Consider increasing the size of X_dev or dropping the feature (X not representative of X_dev for this feature).\n",
"WARNING: No robust combination for Numerical('existing_credits'). Consider increasing the size of X_dev or dropping the feature (X not representative of X_dev for this feature).\n",
"WARNING: No robust combination for Numerical('num_dependents'). Consider increasing the size of X_dev or dropping the feature (X not representative of X_dev for this feature).\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" library | \n",
" fit_s | \n",
" transform_s | \n",
" train_auc | \n",
" test_auc | \n",
" auc_drop | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" AutoCarver | \n",
" 1.102 | \n",
" 0.0109 | \n",
" 0.8496 | \n",
" 0.8044 | \n",
" 0.0451 | \n",
"
\n",
" \n",
" | 1 | \n",
" optbinning | \n",
" 1.099 | \n",
" 0.0114 | \n",
" 0.8523 | \n",
" 0.7931 | \n",
" 0.0592 | \n",
"
\n",
" \n",
" | 2 | \n",
" KBinsDiscretizer | \n",
" 0.003 | \n",
" 0.0016 | \n",
" 0.8401 | \n",
" 0.7943 | \n",
" 0.0458 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" library fit_s transform_s train_auc test_auc auc_drop\n",
"0 AutoCarver 1.102 0.0109 0.8496 0.8044 0.0451\n",
"1 optbinning 1.099 0.0114 0.8523 0.7931 0.0592\n",
"2 KBinsDiscretizer 0.003 0.0016 0.8401 0.7943 0.0458"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y_train_full = pd.concat([y_train, y_dev])\n",
"\n",
"runs = [(\n",
" 'AutoCarver',\n",
" lambda: bin_with_autocarver(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, 'binary'),\n",
")]\n",
"if HAS_OPTBINNING:\n",
" runs.append((\n",
" 'optbinning',\n",
" lambda: bin_with_optbinning(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, 'binary'),\n",
" ))\n",
"runs.append((\n",
" 'KBinsDiscretizer',\n",
" lambda: bin_with_kbins(X_train, X_dev, X_test, categoricals, quantitatives),\n",
"))\n",
"\n",
"rows = []\n",
"for name, run in runs:\n",
" X_tr, X_te, fit_t, transform_t, carver = run()\n",
" scores = fit_eval_binary(X_tr, X_te, y_train_full, y_test)\n",
" rows.append({\n",
" 'library': name,\n",
" 'fit_s': round(fit_t, 3),\n",
" 'transform_s': round(transform_t, 4),\n",
" 'train_auc': round(scores['train_auc'], 4),\n",
" 'test_auc': round(scores['test_auc'], 4),\n",
" 'auc_drop': round(scores['train_auc'] - scores['test_auc'], 4),\n",
" })\n",
"\n",
"binary_results = pd.DataFrame(rows)\n",
"binary_results"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8003c457",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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1HxOOZSUaF1J4Z9++ukzvUkAAKCAIuAEAAAAAAAATxX2dnEAAAAAAAAo6Ag4AQAAAAAAwFMEnAAAAAAAAOApAk4AAAAAAADwFAEnAAAAAAAAeIqAEwAAAAAAADxFwAkAAAAAAACeIuAEAAAAAAAATxFwAgAAAAAAgKcIOAEAAAAAAMBTBJwAAAAAAADgKQJOAAAAAAAA8BQBJwAAAAAAAHiKgBMAAAAAAAA8RcAJAAAAAAAAniLgBAAAAAAAAE8RcAIAAAAAAICnCDgBAAAAAADAUwScAAAAAAAA4CkCTgAAAAAAAPAUAScAAAAAAAB4ioATAAAAAAAAPEXACQXe559/bs2bN7dSpUpZoUKFrEOHDu5fAAAAAMirZsyY4Z5btm/ffqY3BQiLgBMKtN9++806depkP/30k40bN85ee+01q1atWprpRo0aZfPnzz8j2wgAOH3Lly+34cOH28GDB3PscFJWAAAA/IGAEwq07777znbs2GGPPvqo3X///faXv/zFxowZY7/++mvIdDxEAED+DziNGDGCgBMAAEAuIeCEAm3fvn3u3zJlygTGFS1a1KKios7gVgEAAADA6fP5fGlepgO5hYATCqx77rnHWrZs6f5Wszq1f7722mtdk4vgHE76++jRo/bqq6+6vzVo3syaPXu2NW7c2M455xwrXbq01atXzyZMmJAj+wQASEv39YEDB7q/L7zwwsC93J/z4p///Ke7T5coUcLOO+8869Kli+3atStkGd98843dfvvtVrFiRfdS4k9/+pOb7tChQ56UFc8//7zLJ1i2bFm3Hdqet956K2Qaba+Wq5wdqWm89jPY999/bz169LDKlStb8eLF3b736tXLTpw4wWUCAGGo5cODDz5ol156qbsX656s54TUOZJSPy+cKqfSBx984J47/M8DV1xxhc2aNStL5+Crr76y6667zm2XyqCnnnrKUlJS0kxXvXp1u+mmm2zx4sXWpEkTN/0//vEP993WrVvd/qisK1mypF155ZW2cOHCkPmTkpLcPsyZM8eGDBniyj3lur355pvTlI3AqRQ95RRAhPrrX/9qVapUcc3l+vbt6278FSpUsP/85z8h0ymv03333WdNmzZ1ze7koosuytQ6lixZYl27drXrr7/enn32WTdu06ZNbh39+vXLgb0CAKR222232ddff21vvPGGy9dXrlw5N/7888+3p59+2oYNG2Z33HGHu9fv37/fXnjhBbvmmmts3bp1rgasAjSxsbGWnJxsffr0cf/zrWDO+++/75roRUdHn1ZZIXoRof+Zv+uuu9z69LJCDwVaR7t27bJ8Un/44Qe3Ldo+bU+tWrXcNiuIdezYMStWrBgXCgCE6UxITbD1QkFBHQWOXnrpJfdS+r///a8L0mSVglD33nuvXXbZZTZ48GBXrqh8SUxMtDvvvDNTy9izZ4+1atXKfv/9d3v88cddAGjKlCkumBTOli1b3DOInnd69uzpAmh79+51LzZUBujZR8E0vSRR2aOy4dZbbw1ZhspHBZ4GDRrkWoWMHz/eWrdubevXr093vUAaPqAAW7ZsmU8/g7lz5wbGJSQkuHHBSpUq5evWrVuWl9+vXz9f6dKlfb///rsn2wsAyJ6//e1v7t6+bdu2wLjt27f7ihQp4nv66adDpv3yyy99RYsWDYxft25dmrIinOyWFXLs2LGQzydOnPDVrVvXd9111wXGadu1Ha+88kqa+TVe5ZdfXFycr3Dhwr7PP/88zbQpKSnZ2kYAiHSp78WyYsUKd4+dOXNmhs8LovtzcFlz8OBB3znnnOOLiYnx/frrr9m+F/fv398t97PPPguM27dvny86OjpN2VatWjU3LjExMewyPvnkk8C4I0eO+C688EJf9erVfSdPngx5PqpSpYrv8OHDgWnffPNNN37ChAmZ3m6AJnVADtIbDDWxUE0nAEDeMm/ePNccQbWbDhw4EBhUg6lmzZq2bNkyN51qMImaJ+jNcE4Iflv8888/u6Z6V199ta1duzbLy9I+qWfV9u3bu+YUqYVrBgIACL0XqzfrH3/80S6++GL3//TZuR/rGeDIkSOuVlLqHLFZuRcvWrTINX9TzVU/1dJVrdhw1IRaNXNTL0Pzt2jRIjDu7LPPdrVgVZNLNbiCxcXFuSaAfh07drRKlSq55QCZRcAJyEFqA37JJZfYDTfc4Krlqjqtqs8CAM485WVS5SAFl/Q/7sGDmj/7O5bQ/7gPGDDAXn75ZdccT/8TP2nSpED+Ji+o6ZweJvRAotwa2gY148jOOtQs8PDhw1a3bl3Ptg8ACgIl146Pj7eqVau63He65+t+rObJ2bkfq0dsOd37sXJLqaxKTU3lwlG5FW4Z4aavXbt24PtgqdenAJmCb6nzUwEZIYcTkIPKly/v2jnrrbiSBWp45ZVX3BsDtZkGAJw5qgmk/4HWvblIkSJpvtebX78xY8a4JODvvvuuffjhhy7/xejRo23lypXuhcLp+OSTT1wODeWNevHFF90b5LPOOsuVF8FJZdN7G37y5MnTWj8A4P8oT5/uvf3797dmzZq5Gq669yqnU3CC7rx+PybHEvIKAk5AJpxO8wMlZlWzBg0qqFTrST1FKEmt3hIAAM7MfVxJvVXDSW+CVRv1VNTLqIahQ4e6pLJXXXWVTZ482fUUlN46MuPtt992NZv0ckJv1P300BPs3HPPdf/qTXuw1G+l9TZevSBt3LgxW9sDAAWVkmd369bNvWTwO378eJr7bvD9WM3t0rsf+zuP0P34dP6/v1q1aq5Wbrjk4FlZRrjpN2/eHPg+WOr1qbz89ttvrX79+lnYchR0NKkDMkE9QaQuaDJD7b5DfnCFCwdu0urtCACQe/dxCb6Xq/c61WwaMWKE+x/pYPrsv4ereZp6BgqmwJPu6cH38uyWFdoGBauC34yryYLyMAVTEEnNOz7++OOQ8aoVFUzb1aFDB3vvvfds9erVadaXel8BAH/cj1PfI9VzaeqaS/5AUvD9WHlbU7dgaNOmjcuDpBqxClxl91584403uhq1q1atCmk+/frrr2dpGZp/xYoVIdus3u6qV69uderUCZl+5syZLv9UcDBu9+7dLlUIkFnUcAIyoXHjxvbRRx/Z2LFjrXLlyu5teExMzCnnUxfZP/30k1133XWuyYXeeqjQatiwYaC9NAAgd+7j8sQTT7imEWqyppqnqp2kbqoV4FGQRg8G27Zts3feecclUn300UftX//6l/Xu3ds6derkakIp+PTaa6+5B5Pbb7/9tMuKdu3auXnatm3rushW7ijliNLb8A0bNqQpV5555hn3rxKC62Hn66+/TrPMUaNGuaZ/LVu2dPuhMkcPCnPnzrVPP/005I08AOD/3HTTTe7+rqZ0CsAoOKP7etmyZdMEki644ALr0aOHDRw40JUH06dPdzVMd+7cGfKiYNy4ce6efcUVV7h7vGpHffHFF64Tisym2Hjsscfcdqmc6Nevn3vBoUCRaiWlLifSo8Tlb7zxhgsYqVm48gVq/SrzVNNWLyuC6XslGO/evbvt3bvXxo8f78qlnj17crkg8+ioDwWZv9vP4K6uw3VzunnzZt8111zjK1GihPsus91ev/XWW742bdr4ypcv7ytWrJjvggsu8P31r3/17d692/N9AQBkbOTIka6b58KFC4d0I/3222/7WrRo4StVqpQbatWq5XvooYd8W7Zscd9v3brVd++99/ouuugiX1RUlO+8887ztWrVyvfRRx95UlbItGnTfDVr1vQVL17crV9da4crj9Rld48ePVxX2Opq+4477nBdY2s6TR9sx44dvri4ON/555/vllujRg23X8nJyVwqABDGzz//7OvevbuvXLlyvrPPPtsXGxvr7u3VqlVLc09fs2aNLyYmJvD/+GPHjnX37uDyxW/BggW+5s2bu/KhdOnSvqZNm/reeOONLJ2DDRs2+Fq2bOnKIZVlKtNUdqRen7a1Xbt2YZfx3Xff+Tp27OgrU6aMW4624/333w/7fKTtGzx4sHuO0XZrmSpXgKwopP9kIT4FAAAAAAAiUFJSkrVq1crViO3YseOZ3hzkc+RwAgAAAAAAgKfI4QRkgxIHKlFfRtSddnCX2gCAgoWyAgCQkV9//dUOHTqU4TTKpaRer4H8iIATkA27du1yyWAzkpCQYMOHD+f4AkABRVkBAMjInDlzXFLujCxbtsyuvfZaDiTyJXI4Admgbk3Vy09GatSo4QYAQMFEWQEAyIh6D/3qq68ynEY9oKpnOyA/IuAEAAAAAAAAT5E0HAAAAAAAAAUvh1NKSor98MMPds4551ihQoXO9OYAQJ7k8/nsyJEjVrlyZStcuGC/T6DcAIBTo9yg3ACAnCw38kXAScGmqlWrnunNAIB8k6j4T3/6kxVklBsAkHmUG5QbAJAT5Ua+CDipZpN/p0qXLn2mNwcA8qTDhw+74Lz/nlmQUW4AwKlRblBuAEBOlhv5IuDkb0anYBMBJwDI3D2zIKPcAICs3zMLMsoNAPC+3CjYST4AAAAAAADgOQJOAAAAAHLNpEmTrHr16hYVFWUxMTG2atWqDKefO3eu1apVy01fr149W7RoUZppNm3aZDfffLNFR0dbqVKl7IorrrCdO3fm4F4AAE6FgBMAAACAXDFnzhwbMGCAJSQk2Nq1a61BgwYWGxtr+/btCzv98uXLrWvXrtajRw9bt26ddejQwQ0bN24MTPPdd99ZixYtXFAqKSnJNmzYYMOGDXMBKgDAmVPIp37t8kFiKr2tOHToEDmcAIB7JeUGAOTT/8dWjSbVPpo4caL7nJKS4hLQ9unTxx5//PE003fu3NmOHj1q77//fmDclVdeaQ0bNrTJkye7z126dLGzzjrLXnvttWxvF88bAOD9vZIaTgAAAABy3IkTJ2zNmjXWunXrPx5GChd2n1esWBF2Ho0Pnl5UI8o/vQJWCxcutEsuucSNL1++vAtqzZ8/P4f3BgBwKgScAAAAAOS4AwcO2MmTJ61ChQoh4/V5z549YefR+IymV1O8X375xZ555hlr27atffjhh3brrbfabbfdZv/+97/T3Zbk5GT3pj54AAB4i4ATACDPJYgdP368XXrppVaiRAnX1OLhhx+248ePc6YAACFUw0luueUWV1aoqZ2a5t10002BJnfhjB492jUL8Q8qawAA3iLgBADIUwliZ82a5R4WNL16HZo2bZpbxpAhQzhTAJCPlStXzooUKWJ79+4NGa/PFStWDDuPxmc0vZZZtGhRq1OnTsg0tWvXzrCXusGDB7scJP5h165dp7FnAIBwCDgBAHLU2LFjrWfPnta9e3f3QKA3ziVLlrTp06en2yPRVVddZXfeeaerFdWmTRvXQ9GpakUBAPK2YsWKWePGjW3p0qUhNZT0uVmzZmHn0fjg6WXJkiWB6bVMJSHfsmVLyDRff/21VatWLd1tKV68uEt4GzwAALxV1OPlRYT2j7xrkey9MbdYpIrkcxfJ5w2RnyBWb5IzmyC2efPm9s9//tMFmJo2bWpbt261RYsW2d13351hLg4NfrmdiyOS7z3C/QeAV1TjtVu3btakSRN3j1cTavVCp5cSEhcXZ1WqVHFN3qRfv37WsmVLGzNmjLVr185mz55tq1evtilTpgSWOXDgQNeb3TXXXGOtWrWyxMREe++99ywpKYkTB89FcplPeQ+vEXACAJyRBLGbN28OO49qNmm+Fi1amM/ns99//90eeOCBDJvU6cFkxIgRnm8/AMBbCgzt37/f4uPjXeJv5VxSgMhfTqgZnF5MBL+EUFProUOHunKgZs2arge6unXrBqZRknDVnlVZ0LdvX5cD8O2333blCADgzCHgBADIU/RGetSoUfbiiy+6BOPffvute8M9cuRIGzZsWNh5VINKb82DaziRABYA8qbevXu7IZxwtZI6derkhozce++9bgAA5B0EnAAAeSpBrIJKaj533333uc/16tVzzS3uv/9+e+KJJ0LefAfn4tAAZBVN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nLDY2Fh75plnXJety5cvt1WrVtlDDz1kL7zwgn311VfZXvZvv/1mObXN+EPFihVdF5deio6OtjJlyuSLw/zyyy/bXXfdZS+99JI98sgjblzbtm1t9+7dbli6dKkVLVrUbrrppsA8RYoUccdN4720ZcsW99v9/PPPbdCgQfbRRx+57pG//PLLXDm2p/ObO/vss61s2bKWU/jd5gzKDa6/7KDcoNzwo9woeCg3Mof/bwlFuUG5EXHlhq+AUbTv7LPP9m3evNnXuXNn39NPP51hNFrRQv9h0vfBNTo0aJzs2LHDd/PNN/tKlSrlO+ecc3ydOnXy7dmzJ7Ac1WxSraq1a9em2SbVbvrll1/c3x988IHvqquuctuhGiPt2rXzffvtt4Fpt23b5tY7e/Zs3zXXXONqm0yYMMEXFRXlW7RoUchy582b5/b16NGj7vPOnTvddmnZ5557rtteLS91hPmpp57yVapUyVe9enVfXqMaRn369PGdf/75bt91rFatWhVS++X999/31atXz30fExPj+/LLL0O+Dx5UY81fw+nJJ5/0denSxVeyZElf5cqVfRMnTkw3euw/D2+//bbv2muvdTXWVHNNb7NSX0+JiYm+WrVquWtDNYCCa+Kkjuq3bNnS7Z9q7OgcVahQIbCNfps2bXL7rf2rXbu2b8mSJWEj26creNt0/eoa0zWV3rbLJ5984rZl3759Icdp3bp1Iefgo48+8jVu3Ngdt2bNmrnfo9/69evdMdW1q99So0aNfJ9//nnI/KlrLh07dsx36aWXuuOS3vapdlbdunXdfui3df311wd+dzJt2jRfnTp1fMWKFfNVrFjR99BDDwW+0zpffPFFX/v27d314T8n8+fP911++eXuXFx44YW+4cOHB2pz6ZoKvtb0OVwtydTXZPC0ouu3bdu27vopX7687y9/+Ytv//79IdeMtrVfv36u1qSOHbxFuUG5QbmROZQblBug3OB5g+eNrKDceCjinzcKXMBJD5VNmjRxf7/33nu+iy66yJeSkpKpgJMeah955BHfZZdd5poJadC4kydPumY9LVq08K1evdq3cuVK9zCtE+OnYESbNm1OuX1vvfWWC2J888037iFdF5yCJ1pH8AO8gkGabuvWrS6A0bFjR3dhBLv99tsD4xTUUnDi3nvv9W3YsMH33//+13fnnXe6h3Q19fP/4PWQ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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_bars(binary_results, ['fit_s', 'test_auc', 'auc_drop'], 'German Credit \\u2014 binary classification')"
]
},
{
"cell_type": "markdown",
"id": "regression-md",
"metadata": {},
"source": [
"## Regression — California Housing\n",
"\n",
"6 numeric demographic features (Latitude / Longitude dropped — see comment in the next cell), 20,640 rows, target = median house value. Same 60 / 20 / 20 split."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "load-regression",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"train=12384, dev=4128, test=4128\n",
"numericals=8 (['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude'])\n"
]
}
],
"source": [
"housing = fetch_california_housing(as_frame=True)\n",
"X_reg = housing.frame.drop(columns=['MedHouseVal'])\n",
"y_reg = housing.frame['MedHouseVal']\n",
"\n",
"X_train, X_rest, y_train, y_rest = train_test_split(X_reg, y_reg, test_size=0.4, random_state=SEED)\n",
"X_dev, X_test, y_dev, y_test = train_test_split(X_rest, y_rest, test_size=0.5, random_state=SEED)\n",
"\n",
"quantitatives = list(X_reg.columns)\n",
"categoricals = []\n",
"\n",
"print(f'train={len(X_train)}, dev={len(X_dev)}, test={len(X_test)}')\n",
"print(f'numericals={len(quantitatives)} ({quantitatives})')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "adebc1c4",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" library | \n",
" fit_s | \n",
" transform_s | \n",
" train_r2 | \n",
" test_r2 | \n",
" r2_drop | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" AutoCarver | \n",
" 2.870 | \n",
" 0.0093 | \n",
" 0.6652 | \n",
" 0.6595 | \n",
" 0.0057 | \n",
"
\n",
" \n",
" | 1 | \n",
" optbinning | \n",
" 2.274 | \n",
" 0.0089 | \n",
" 0.5145 | \n",
" 0.5077 | \n",
" 0.0068 | \n",
"
\n",
" \n",
" | 2 | \n",
" KBinsDiscretizer | \n",
" 0.008 | \n",
" 0.0015 | \n",
" 0.6181 | \n",
" 0.6192 | \n",
" -0.0011 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" library fit_s transform_s train_r2 test_r2 r2_drop\n",
"0 AutoCarver 2.870 0.0093 0.6652 0.6595 0.0057\n",
"1 optbinning 2.274 0.0089 0.5145 0.5077 0.0068\n",
"2 KBinsDiscretizer 0.008 0.0015 0.6181 0.6192 -0.0011"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y_train_full = pd.concat([y_train, y_dev])\n",
"\n",
"runs = [(\n",
" 'AutoCarver',\n",
" lambda: bin_with_autocarver(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, 'continuous'),\n",
")]\n",
"if HAS_OPTBINNING:\n",
" runs.append((\n",
" 'optbinning',\n",
" lambda: bin_with_optbinning(X_train, y_train, X_dev, y_dev, X_test, categoricals, quantitatives, 'continuous'),\n",
" ))\n",
"runs.append((\n",
" 'KBinsDiscretizer',\n",
" lambda: bin_with_kbins(X_train, X_dev, X_test, categoricals, quantitatives),\n",
"))\n",
"\n",
"rows = []\n",
"for name, run in runs:\n",
" X_tr, X_te, fit_t, transform_t, carver = run()\n",
" scores = fit_eval_regression(X_tr, X_te, y_train_full, y_test)\n",
" rows.append({\n",
" 'library': name,\n",
" 'fit_s': round(fit_t, 3),\n",
" 'transform_s': round(transform_t, 4),\n",
" 'train_r2': round(scores['train_r2'], 4),\n",
" 'test_r2': round(scores['test_r2'], 4),\n",
" 'r2_drop': round(scores['train_r2'] - scores['test_r2'], 4),\n",
" })\n",
"\n",
"regression_results = pd.DataFrame(rows)\n",
"regression_results"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "b7da7c9b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABJ4AAAFcCAYAAACJC3TyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABWlUlEQVR4nO3dCZxN9f/48bclM7YZJMaWPUyWYUSWLEW2RN+StMwQ2qiRoi9pxlbKvmYrhHyJUEmWhsm3KFkjEVlGdpU1Rsb9P96f/+/c770zd8bcMWfuLK/n43Ga7rmfc89678d5n8/n/cnhcDgcAgAAAAAAAKSxnGn9gQAAAAAAAACBJwAAAAAAANiGFk8AAAAAAACwBYEnAAAAAAAA2ILAEwAAAAAAAGxB4AkAAAAAAAC2IPAEAAAAAAAAWxB4AgAAAAAAgC0IPAEAAAAAAMAWBJ4AAMggmjVrZibL4cOHJUeOHDJnzhy3cqtWrZKQkBDx9/c37587dy5dt1O3R9er25edDB482Ow3MreYmBhzHvUvAACwH4EnAABS6bfffpPnn39eKlSoYIJAAQEB0qhRI5kwYYJcuXLFluP6xx9/yOOPPy558+aVKVOmyLx58yR//vySmVmBrC1btnh8X4Nx1atXT/ftAgAAwK3LnQafAQBAtvPll19Kp06dxM/PT8LCwkxg5Nq1a/Ltt99Kv3795Oeff5YZM2bc0jrKli1rAli33Xabc96PP/4oFy9elGHDhkmLFi3EF5555hl54oknzL5nJ4MGDZJ///vfvt4M3KImTZqY71WePHk4lgAApAMCTwAAeOnQoUMm8KKBoXXr1kmJEiWc7/Xq1UsOHDhgAlO3SlsBaUsqV6dPnzZ/CxUqlGbn7fLly161msqVK5eZspvcuXObKStzOBxy9epV06IuPXh77aWFnDlzJvpeAQAA+9DVDgAAL40cOVIuXbokH374oVvQyVKpUiWJiIhwvp49e7bcf//9UqxYMdNKKDg4WKZOnXrT9STM8aRdzsLDw83/33PPPea9rl27OssvXrxYQkNDTdCgaNGi8vTTT8uxY8fcPlPLFyhQwHQTbNu2rRQsWFCeeuop855+Xu/evWX58uWmBZdu6913321ySt0sx9Nnn30m7dq1k5IlS5rlKlasaFplxcfHix2uX79uPl/Xo+srV66cDBw4UOLi4tzK6XZqbqaEtLzrsfvnn39kyJAhUrlyZROUuP3226Vx48aydu3aZHM8pfSYKc0pVLduXfP5ut3Tp0/3ed4oPQ4PPfSQrF692mybXju6XUpzh/Xp00fKlClj9kuv6/fee09u3LiRqPuntoLTrqYaENVrdOfOnYnykyV37elnjh8/3hw7PT7Fixc33Vj/+usvt3Vpd8xWrVqZ61u3tXz58vLss8+6lVm4cKH5Hujn6zbVqFHDdH+9WY4nb74/Or9jx47m/++44w55/fXXbbvWAQDI7LL2YzsAAGzwxRdfmLxODRs2TFF5DTLpDfXDDz9sWszo8i+99JK52dYWUin15ptvSpUqVUwXvqFDh5qbbg1gKL3B79atmwlIjRgxQk6dOmVutr/77jvZvn27WwspDdrozbsGVkaPHi358uVzvqddBZcuXWq2T2/cJ06cKI8++qjExsaaYExSdP16E963b1/zV1uCRUZGyoULF2TUqFEp2r/z58/L2bNnE83XoFBCPXr0kI8++kgee+wxee211+SHH34w+/3LL7/IsmXLxFsaANLl9XPr1atntluDHNu2bZOWLVsmu2xKjpmeg9atW5tApQa4NEih51CDFr62b98+6dKliwn09OzZ01xjf//9tzRt2tQEWHT+nXfeKRs3bpQBAwbIiRMnTJBI6TXcvn172bx5s7z44otStWpVE4S0AqQJJXXt6Tqsa/iVV14xrQonT55sjptew9rdVFv7Pfjgg+aYaZdHvaY1+KnH3qKBQt2XBx54wATJlF4T+hmuweCEvPn+6LnTfahfv77Zh6+//lrGjBljvot6DAAAQAIOAACQYufPn3do9dmhQ4cUL/P3338nmteqVStHhQoV3OY1bdrUTJZDhw6Zdc2ePds5T/9f5/3444/OedeuXXMUK1bMUb16dceVK1ec81esWGHKRkZGOueFh4ebef/+978TbZPOz5Mnj+PAgQPOeTt37jTzJ02alGgbdPuS28fnn3/ekS9fPsfVq1eTPT7W5yU33X333c7yO3bsMPN69Ojh9jmvv/66mb9u3Tq3fYqKikq0zrJly5pjYalVq5ajXbt2yW6nfk7Cfzql9Ji1b9/eHItjx4455+3fv9+RO3fuRJ+ZnvQ46PpXrVrlNn/YsGGO/PnzO3799Ve3+Xrd5MqVyxEbG2tef/rpp2b58ePHO8vEx8c77r///kTX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kuy2WjdwVjDWlSY5X7t2rUnav2bNGpOw/80335QffvhBihYtmqJjkfDa1+/MkCFD5F//+leisv7+/uKN+fPny7hx4yQmJsYcc9d16Hf+vffeS7SMdRPqaduQMVCnUKfcqqxUp1Cf/A/1CVKDOoU65VZRp3CP4p9J7lGydIsnDTjNnTtXxowZ42zBoZNG8zTA85///McEYC5evCiXL192LqdlEgZ44uPj3eZVq1ZNjh49aibLnj175Ny5c6blk9IbbR2Za/v27Ym2TYNbus4//vjDPO0YNGiQaZ2hn2u12kgJHZFs1apVZoS8devWmdeWOnXqmNZUxYoVM4EE10kDCRmRPuXV4/3dd9+5HSsd6cw6rur77793/r8er19//dUcu6TOl6flrNfWchmFtt7S6+rUqVPOebr/aUkDnd98842cPHnSBJ/0O5AUvYHRAO2VK1duORD76quvmiCRBnZmz56dbHld34wZM6RJkyZugdKE26at4zRYpN8zPffLli0zgTQNVumofN7Q74x+HxN+X3TSY2BV8EldXxZ9gqAtvKZPny733ntvonXo91W3L+E6CDZlbNQp1CkJUadQnySF+gTUKdynKO5TvMM9StatU7J04GnFihXmy969e3fTgsh1evTRR81Thvr165tm7drcTJuQaauhOXPmuH2OHvxDhw6ZgNTZs2clLi7OdBnSLj4a6Nm2bZvpkhQWFiZNmzZ1No3r06ePuSnWgNKUKVNMwOvgwYPyySefmBOtQaHChQubIQ71Blu7xWnwSLslpZTelGvzed2O8uXLm/2x6Dxt+dGhQwf573//a/ZBI5uvvPKK/P7775IR6UX94osvSr9+/UxATYN52oxQmxDqebRoU0MNKuzevVu6du1q9rNjx47O86URW31fz5dr80MNaI0cOdIEqvScLF68WCIiIiQjadmypQnAhYeHy08//WS2WQOTSXU5Sy3teqHXg3bH0O50Fy5cMPP1+taAlE7a4ujll192RsBTQwNIvXv3NuvS7nq6PxpISxjw0+3Qder3QltD6XdHz9/UqVM9fq62bHrnnXdky5Ytplvq0qVL5cyZM87P1VZWGnSeOHGi+Uz9nmqrqORERkaaYLUGsvSHV/dft8U6/soKaOm2egoS63xtyaWtEPW4WsdSt0316tVL/vzzT9O9Vo+D/u6sXr1aunXrdtPKAr5FnUKdQp3iGfVJYtQnoE7hPoX7lNShTsmidYojC9PRztq2bevxPU1WrLu/c+dOk4RLM7prgmpdZsaMGW7Jxa9evWpGiytUqJAzW7zSDPMPP/ywScKsyZM7derkOHnypNt6dFkd8UZHqbOGfNchjTXRsjWKjSb51FFrdGhEHQlPRwbzlJDUSuackI5Qpu9HRkYmek+TiYaFhZmE6vr5FSpUcPTs2dMkIveUpDQj0ITUOjS0tc16vKyE7VYiah2dUEdK00TZOjqPnkdXL7zwghniUctaQ1Bq0r4hQ4aY86RDUwYFBTkmTJjgttzNjrsmwNZ53iSn95QIVoegdKXva7mEQ1/r/ukISLq/+pk6xPat8HS+f//9d0flypUd9957r0ky5zq8pl7XmqRWR168WXJx1+Tg+p7O07KauF6HGy9TpozZH0363bt3b2ficWt5nXQkJl2nJsHT0RJck+Em3H4dpVGHGdfRF/Q6ueuuuxyTJk1yKz9t2jSTYF8T1mvyPb2uLEkl1tVjrIk+9fdAR4/Q60t/Eyyff/65+b3QZL2ehip13Z+khirVkaf0WOtviq5Hz7EmEbQGAvB0jcD3qFOoU6hT/of6hPoE1CmK+xTuU9LiPoU65eUsf4+S4/92DsgUtNWM5ibSKK4mcs8utJVQ48aNTas416SzAIDUo06hTgGAtEKdQp2CbJxcHMiMNE+RjiRQuXJlE2zS7oDa9YygEwCAOgUA4CvcpyA1CDwBGZAm+37jjTdM7iLNX6U5xTRfEQAA1CkAAF/hPgWpQVc7AAAAAAAA2CJLj2oHAAAAAAAA3yHwBAAAAAAAAFsQeAIAAAAAAIAtCDwBAAAAAADAFgSeAAAAAAAAYAsCTwAAAAAAALAFgScAAAAAAADYgsATAAAAAAAAbEHgCQAAAAAAAGKH/wcP9P87cFpv1QAAAABJRU5ErkJggg==",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_bars(regression_results, ['fit_s', 'test_r2', 'r2_drop'], 'California Housing \\u2014 regression')"
]
},
{
"cell_type": "markdown",
"id": "notes-md",
"metadata": {},
"source": [
"## How to read these numbers\n",
"\n",
"- **`fit_s` / `transform_s`** measure only `.fit` / `.transform` wall-clock — not data loading, not one-hot encoding, not the downstream model.\n",
"- **`test_auc` / `test_r2`** are the headline metric. They reflect how well a *simple* downstream model performs on each library's binned output. A tree-based downstream model would tell a different (and less binning-sensitive) story.\n",
"- **`auc_drop` / `r2_drop`** are `train - test` and measure how much each library's bins overfit. Lower is more robust. AutoCarver's dev-set veto is designed to keep this small.\n",
"- **Same data, same seed, same downstream model** across libraries — but a single run, on one machine, with one set of hyper-parameters. Treat as illustrative.\n",
"\n",
"## When the result will move\n",
"\n",
"- **Bigger `max_n_mod` / smaller `min_freq`** will improve AutoCarver and optbinning's in-sample scores at the cost of `*_drop`. KBins doesn't have a target, so it's mostly insensitive.\n",
"- **Different downstream model.** Gradient-boosted trees on the raw features beat any binning + linear pipeline. The point of binning is interpretability, not raw accuracy.\n",
"- **Different dataset.** German Credit is small; on a 10M-row credit-risk dataset, `fit_s` is what dominates the comparison.\n",
"\n",
"See [comparison.rst](../../comparison.html) for the qualitative scope and algorithmic comparison."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "AutoCarver",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}