├── .gitignore ├── Notebook.ipynb ├── README.md ├── Sigmoid regression.ipynb ├── calibration.py ├── model.py ├── plotting.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A guide to model calibration 2 | 3 | A simple implementation of two methods of calibrating machine learning models - Platt scaling and isotonic regression. 4 | For the main notebook with a demo of the calibration on MNIST dataset, see [Notebook.ipynb](Notebook.ipynb). The modules used are contained in [model.py](model.py), [calibration.py](calibration.py), and [plotting.py](plotting.py). 5 | 6 | For a short description of fitting a logistic regression line using linear regression, see [Sigmoid regression.ipynb](Sigmoid%20regression.ipynb). 7 | -------------------------------------------------------------------------------- /Sigmoid regression.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "id": "8268718f", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import numpy as np\n", 11 | "from sklearn.linear_model import LinearRegression\n", 12 | "import matplotlib.pyplot as plt" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "20d2d4a1", 18 | "metadata": {}, 19 | "source": [ 20 | "Creating some dummy, noised, S-shaped points:" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 19, 26 | "id": "06109975", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "x = np.linspace(-5, 5, 10)\n", 31 | "x += (np.random.random(10)-0.5)/1.5\n", 32 | "y = 1 / (1 + np.exp(-x))\n", 33 | "y += (np.random.random(10)-0.5)/6\n", 34 | "x = np.clip((x+5)/10, 0.01, 0.99)\n", 35 | "y = np.clip(y, 0.01, 0.99)" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "5c683818", 41 | "metadata": {}, 42 | "source": [ 43 | "Fitting the regresssion model:" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 20, 49 | "id": "2aee6c6a", 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsIAAAJzCAYAAAAFhHUJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAACD3klEQVR4nOzde5yWc/7H8ddHRYMYSw5NJcdWTkVOP7vOJKzC7joT0bJrsQg5r2W12nW2yGGd5ZSEyCE5hxJKtJuUmhyKhjA6fn5/fL+Te273PXPPzD1zzT33+/l43I+57+v4ua7rvu/53N/rezB3R0RERESk2KyQdAAiIiIiIklQIiwiIiIiRUmJsIiIiIgUJSXCIiIiIlKUlAiLiIiISFFSIiwiIiIiRUmJsIiIiIgUJSXCIiJSVMysq5m9a2YLzOzUJtjfB2a2W2PvJ2V/M8xsr6baX5YYmuSYm/Lc5uu8JvB+qHF/dTmuhpwDM1vBzLbNcdkVzewtM2trZgeZ2U112E/PusSlRFhERHJmZiuZ2e1mNjMmku+aWe8c1/0u5bHMzCpTXh/Z2LGnOBt40d3buft1jb0zd9/c3cc2xrabQ9KbSV2OuSHH0FT7yafUmJsipqbeXw1OBqblsqC7LwJuB64Djgb+XIf9rGtmW+S6sBJhERGpi9bALGBXYHXgAuAhM+tS24ruvmrVA/gU+E3KtPtSlzWz1vkPfbn1gQ/qs2IjxyXSIpnZJsBK7v5NHVZ7HegP/NHdl+S6krs/Cfwx1+WVCIuISM7c/Xt3v8TdZ7j7svhP5xMgp1ueNYmlVeeY2fvA92bW2szONbOPY+nzFDM7KG35s8zsfTP7xsweNLO2KfPPMbPyuO5UM9vTzMYAuwM3xJLoTc1sMzMba2YV8TbygTnENcPMBsZ9fx9Lydcxs6fj/p43szVS1t8rl7jNbBszmxi38XCcd1mW83UP0Bl4Ih7L2Smzu2fZfgcze9TM5prZJzVVDYlxDornfb6Z/Sft/GY9b7kec7ZjyHTtaohxrxzOa7b91Hjtazg3NR17jdewKuaGHLuZHWdmT6S8/p+ZPZzyepaZdc9lf1HG90sO56HGz2CKc4GHctlm3O5awDXAhcBRua6XYp6ZbZ/Tku6uhx566KGHHvV6AOsAPwK/rON6M4C9Mkx7F+gElMRpvwM6EApuDgW+B9ZLWf6tOP8XwIfASXFeV0LJdYf4uguwUXw+FjghPm9DuF17HrAisAewAOhaS1wzgHHx+MuAL4F3gB5AW2AMcHGmY80Wd9z/TOC0GNfBwCLgsnqcx0zbXwGYAFwU97UhMB3oVcO2J8fj/gXwWlUstZ23XI85y7JZr11Nx1/TPrLsp9Zrn2lfNa2XyzXMEHOdjz1eu4p4TTvEfc5OmTcfWKG2/eVy3mp6v+WybozxnTp8N6wEjAK2jOfwbWCVOn6/HABcnsuyKhFuRszsSDN7tob5u5nZ7KaMqbkws1+b2dQm2tfJZvZF/MW8ZiPvq8mOq9CYmZvZxknHIdmZWRvgPuAud/8oT5u9zt1nuXslgLs/7O5zPJQ+Pwj8D9g+bfk57v418ATQPU5fSviH2s3M2ngowf44w/52BFYFBrv7IncfAzwJHF5TXNH17v6Fu5cDrwBvuvtEd/8ReIyQFNd0nOlx70ioenKduy929+GEJKM+Mm1/O6C9u18aj3U6cCtwWA3buSEe99fA5fx0XnI9b7XFlEmu164h+6jvMdS2XkOvYU7HHq/dgnh8uwCjgTlm9ktCtaVX3H1ZHfZbl/NW13U3J/xQzIm7L3T3/dx9UjyH27n793WIB8IPuN1yWbAgEmEzO8XMxpvZQjO7s47rdoy3gebFYvvJZtYvzusS/9k2qM5X+i2g+nL3+9x9n5TtKhGI3P0Vd++ay7IN+cEQ/7FfBezjod7iV/XZTq7qclxJircAdzOzS8zskpTp51m4vfqdmc02swdrW0daBjNbAbiHUNp1Sh43PSttP8dYaJBXYWYVwBbAWimLfJ7y/AdCgoK7TwNOBy4BvjSzYWbWIcP+OgCz0pKGmYRS3qxxRV+kPK/M8HrVDOvUFHcHoNxjkVYN+81Fpu2vD3SoOpfxfJ5HKNXOJnX/M2OMkPt5qy2mn6nDtav3PqL6HENt6zXoGtbx2F8iJHu7xOdjCUnwrvF1XdTlvNV13TJCCXVTquCn92qNCiIRBuYAlwF31GPdewhvwvWBNQmtD7+ocY0cNTSBlmZpHcJtzTo3pLGgUD5TDWZmxxI+T3t5aPzUE3gh2aikKZiZEVp0rwMc4u6L87j55QmEma1PKLE8BVjT3UsJJT2W04bc73f3XxG+/x34R4bF5gCd0j67nYHybHE1os+Asnh+q3SqZZ26xDUL+MTdS1Me7dx9vxrWSd1/Z8L5gtzPWy5+dgw5XruG7qe+x1DTenW9hg059qpE+Nfx+UvUngg3xfs43S+A71InxIK+RnnEXSyI+61VQfzTdvfh7j4CqE/p3HbAnR4aeCyJt62ejvNejn8rYonWTma2kZmNMbOvYinyfWZWWrUx+3mjiQfIXvm8ap2XzOyQ+HzneLH2j6/3NLN34/N+ZvZqfF4V23txu4embO9MM/vSzD4zs+OyHXjc3nQLFe4/sdg9kYW+/C6w0P3Rl2Z2t5mtHudVlZIfZ6Gy/XwzO8nMtrNQGb7CzG5I28/xZvZhXHZ0/OeVKZ6qbQ8wszkx/rNS5q9kZtfEeXPi85XivGqlvJa94cUqwNOEUo+qbpk6mNn2Fu4qfGuh2sNVGeLbFKiqplBhoVENZvZ/ZvZ23M/bZvZ/KeuMNbPLzew1wi/hDeMx/tFC44UFZva3+L56Pe7/ITNbsS7HlTL/7Hje5pjZCVbDXYN4DT+MMUw3sz+kzNvNQgluTu+lLLYDRlfdtnP3z919aF02YGYbx8/HNxY+bw+mLbJXPI8VZnajWfjnYrl9Tmtq5HOA/VTK+LqZbVXHYy92NwGbEXp9qKxt4QZYhfCPey6E9zShRLhWFvoK3iN+h/xIKKHNdKv4TcJn92wza2Ohv9XfAMMaHH3dvUG4NX6KhQZ5faheDSSTLwh1QnPxFrDAwv+wEjNrZWZbmNl2NazzJwt3Vn8BnA9UfUbzed6qHUMdrl2D9kP9j6Gm9ep6DRty7C8BuxPqrc8mVM/Zl1DoNzGX/TWRb4GStGmlhLq/3wNburvl6xG3v3Lcb60KIhFuoHHAjWZ2mJl1Tpu3S/xbGm+Dv0EoabiCUKS+GeGX3CVp6x0O7B/XO5zq3QBdmSGGql9tEH6pTU/Zd8Zfbu5eNX/ruN2qL591CV0WlRG6FbnRYsvkVDEhvA7o7e7tgP8jNPYA6BcfuxM+EKsCN6RtYgdgE0LjlGsIX4B7Eer6/N7Mdo376UO4tXYw0J7wQXwgwzlItXvc9j7AOfZTtZLzCfWrugNbE748LqhhO78nfOg3ALYC+sV6RL2BOf5Tt0xzgGuBa919NWAjMrRedff/xuODcG33iF/+TxHO5ZqEahNPWfW6w0cDA4B2hNtjAL0Ireh3JPRZOpTQ8rUT4R95TXXQfnZcAGa2L3AG4TpsTO31n74kNBhYDTgOuNrMtkmZn9N7CcDdd3P3sR56C7gkTh4HHGOh5XxPM2uVwzrp/gY8C6wBdASuT5t/ACHh3opwXnrF6bl8To+My28EbEp8L5lZD8LdpT8QruktwMj4j0dqYeGH7h8In9PPLa0fYAu9JpyXj325+xTgX4Tk4gtC45nXclx9JWAwMI9w63ZtYFCGfSwiJDG947L/Bo7x/NV5zlmM5WDC57GC8J3xJLCwhtWuAC6IP+rOqmE53H0p4TPVndDTxzzgNsL3QDb3Ez6j04GPCXdn833e0o8hp2vX0P3U9xhqWq8e17Dexx7/Z31H+L+Lu39LuE6vxWudy/6awuf8/D32AyGPeqSR9rk61atsZOd1aIWX9IPwAbyzjuusQXhTfUD4lfYusJ3/1BrTgdY1rN8XmJjyegZwfNoyM0hrhZk2f0/g/fj8GeAEYFx8/RJwcHzeD3g1ZT0HNk55vRvh12HrlGlfAjtm2OcqhA/hIcRWzinzXiD0y1f1uiuwmFDBv+qclKXM/wo4NOX1o8Dp8fnTQP+UeSsQ3uDrZ4ipatu/TJl2JXB7fP4xsF/KvF7AjJRjn512zo9K287NmZaN014G/gqsVcv7pdp7gpDkvpW2zBuEpBtCnaxL0+Y7sHPK6wnAOSmv/wVcU4/jugO4ImXexunvkVqObQRwWl3fS7Vs80jgecKv+q9SjzPH9e8m/EjomGGeA79Kef0QcG6W7fTl55/T1Nbi+wEfx+c3AX9LW38qsGtdYtdDj6Z4EEofj0to3zOo4X+bHs3/GjaHByG5n5hl3p3AFvXY5oqEOxxtgYOAm9Lm70ko/Kp1Wy2+RNjd57v7ue6+OaE+27vAiKpbrOks9AM5zEIfft8C91K9YQbUvfHCG8CmZrYO4Zf43YT6RWsRSj1frmHddF959Y6lM1Zq91Ayeiihy5zPzOwpC61J4aeuVqrMJCTBqQ0mcm0Esj5wrf3U8OJrQmldTY0Namp8kR5XTZXd61K5vz+hVPAjC9UbDqhh2VTpMVXFlXp8TdGIpiqW1H3V+D40s95mNs7Mvo7XZj+qv5dzei/VxEMDz70It7lOAv5mZr1qXquaswnvl7cs9MV5fNr8jOeiHp/T1PfS+sCZVr3BUCdybFgh0pjMbFczWzfeVj+WcDfkmaTjktzpGlbn7guBT7LdcaznNmsbeW5bQkl8rVp8IpzK3ecB/+Sn/u4yVRr/e5y+pYfb6Efx84YZ6evVWPnc3X8glAqeBkyOF/B1wm3uj2Nceefuo919b2A94CNCoxMIFf1T6/F2BpZQv0aEs4A/ePXGFyXu/noN69TU+CI9rjnUXabGB//zUI1lbULDg0di9ZHapMdUFVdqY4qmanzwGaH6QJWsDTDibf5HCe/3dTw0MhpFjo2M6spDFzcPA++TYx3OuN7n7n6iu3cg3G7/t+XWU0oun9Ns77NZhP4lU9+zK7t7bVV6RJpCV+A9wh29M4HfuvtniUYkdaVr+HP/IvQJXqv4I2Jshse6aYvWNPLcpoS7lbUqiEQ4/qpqC7QCWlloFJVTjw1m9o/YGKC1mbUjjnXtoVusuYRK6KkVx9sR6tx8Y2ZlwMAcdpNL5fOXCC2fq+oDj017Xd/tZhRLzPrEZG8h4ZiqKtw/APzFzDYws1UJScWDGd5IubgZGGRmm8f9rm5mtb3ZLzSzleM6x/FT44sHCHWX2sfS8osIJX119QWwpsUGgDGuo8ysvYfubiri5FwaX4wilOYfEd9DhwLdyPGXZp49BBxnYUSjlQkj7mSzIuF21FxgiZn1JtTJzhsLjTH3N7N2Fhpg9ibUsX6zDtv4nZlVJffzCcltLtcll89ptkY+twInmdkOFqxSdRy5xi3SWNx9qLuv46F9w1bu/lSCsXRx95ySCflJc7qGzYW7vwa0t9BFaW3Lfu6hjUn6Y/kdQqth5Dkz2xl4wGMdidoURCJMaORSSRii76j4vKrhS+fYUCO9IVyVlQkdm1cQKpGvDxwIy0tqLwdei7dIdyTUI90G+IbQSGp4DvHlUvn8JcI/75ezvM7kEuCuuN3f5xBHqhUIJc5zCNUVdiX8CIBQ1/SeuO9PCC1T028r5MTdHyOUsA6Lt6gnExoQ1OQlwqg8LwD/dPeqQUQuA8YTShUnEUZpyji0aC0xfURIqqfHc9eB0PjsAzP7jtBw7jDPobV7/MF0AOFX/VeEW/kHNFYpfi2xPE24DfQi4fyNi7N+1gjD3RcApxKS5/nAEcDIPIf0LaGh5KeEz9eVwMnu/modtrEd8Ga8LiMJdZin57BeLp/TbI18xgMnEhqIziecy351iFlEROruGkIDcgDMbBShgOZWi+M75CLe8byb0N/yEODQtDu8q7p7zl15Wo4Js0iDmVkXQuLdpp6lz5LCzDYj/PBYSeezOjObQRhCV6VZIiKSVaGUCIsIYGYHWehveQ1CSfwTSoJFRETqR4mwSGH5A6Gbs48J3QGeXPPiIiIiko2qRoiIiIhIUVKJsIiIiIgUJSXCIiIikYUhoo/NcVnP1u917F6wLj2oFDUz283MZicdRz6Y2a/NbGqOyzb4uFPfh2Z2s5nV1LWmpMmpL14REZFi4O61df8oLZiZXUIYtv6o2pbNxt1fIQyqkY947gRmu/sFOe77pHzst5ioRFhERESqyXXQqua27cYWB+FR7tSC6GKKiEjRMLOBZvZo2rTrzOza+HysmZ2QMu94M/vQzOab2WgzSx9yvWq5Nc1spJl9a2ZvARulzDMzu9rMvozzJ5lZxqHIzey4uL8FZjbdzP5Qw7H0M7PX4rYr4vL/F6fPivs7NmX51c3sbjOba2YzzeyCqqQubVtfAZfErhr/aWafmtkX8bZ7SZZYVojbmxn3e7fF0T3NrEu8fd/fzD4FxmQ7ppTtdTCzR2Osn5jZqSnztjez8fFcfmFmV8Xpbc3sXjP7Kp6Pt81snSzbP8fMyuN5nmpme5rZvoRBgg61MFDXe3HZsWZ2uZm9BvwAbFjTdUqv7mBm25jZxLjsw2b2oJldlhbPmfG8fWZmx8VpA4AjgbNjPE/kcN7urNp2VRyZth3n53x9WzIlwiIiUkzuBfY1s1JYXjp5GGGkqmrMrA8hMToYaA+8Qhi1MpMbCaN0rgccHx9V9gF2ATYFVgd+TxipMpMvCaNZrkYYgv5qM9umhuPZgTAa55qE0RSHEUZs3JgwEusNZrZqXPb6uP8NCaONHhP3kbqt6cA6hFFXB8eYu8ftlQEXZYmjX3zsHre/KmH0xlS7ApsBvWo4HmJy/gTwXtznnsDpZla13rXAte6+GuEHx0Nx+rHx+DrF83ESYSTa9O13BU4BtnP3djGeGe7+DPB34ME4PPLWKasdDQwgjAg7kxyvk5mtSBjd9k7gF4T3z0Fpi60b4y4D+gM3mtka7j4UuA+4Msbzm5rOWxYZtx3n1eX6tlhKhEVEpGi4+2eE4eV/FyftC8xz9wkZFj8JuMLdP4wD1/wd6G5ppcJm1go4BLjI3b9398nAXSmLLCYkUL8kdFv6YYwjU3xPufvHHrxEGCb81zUc0ifu/h93Xwo8SEgCL3X3hXH4+kXAxjHGw4BB7r7A3WcA/yIkeFXmuPv18Vh/JCR+f3H3r+Ow7X+P28jkSOAqd5/u7t8Bg4DDrHo1iEvi+altePvtgPbufqm7L4rDrt+asu/F8ZjWcvfv3H1cyvQ1CXV8l7r7BHf/NsP2lwIrAd3MrI27z3D3j2uJ6U53/8Ddl7j74jpcpx0J7bGui+sNB95KW2Yx4ZotdvdRwHfkqY5xtm2bmVG369tiKREWEZFicxehtJT4954sy60PXBtvs1cAXwNGKDlL1Z6Q7MxKmTaz6om7jyGUjt4IfGlmQ81stUw7NLPeZjbOzL6O+9wPWKuGY/ki5Xll3F/6tFXjNtqkxhWfpx5LavztgZWBCSnH/0ycnkmHDNtuTShdzrT9mqwPdKjab9z3eSnb6k8oyfwoVn84IE6/BxgNDDOzOWZ2pZm1Sd+4u08DTgcuIVyPYWbWoZaYqsVeh+vUASj36oM2pJ+Hr9JGCP2BcM3yIdu263p9WywlwiIiUmxGAFtZqKd7AOH2cyazgD+4e2nKo8TdX09bbi6whFAaW6Vz6gLufp27bwt0IyRxA9N3ZmYrAY8C/wTWcfdSYBQh+W6oeYTSwdTS7M5AeWqYactXApunHPvq7p4tQZuTYdtLqJ6o5zqC1yxCSXfqeW/n7vsBuPv/3P1wYG3CUPOPmNkqsdTzr+7eDfg/wrU9JtMO3P1+d/9VjNnjdmqKcfn0Ol6nz4CyWAJbpVOG5bJprFHP6np9WywlwiIiUlTc/UfgEUKd2rfc/dMsi94MDDKzzWF5Y7PfpS8UqyUMJzQwW9nMuhHqqxLX287Mdoilk98Tqh0sy7C/FQm37OcCS8ysN6F+cYPFGB8CLjezdrF6xxmEOtOZll9GqI5wtZmtHY+jLKWebroHgL+Y2QaxTnJVXdslWZavyVvAgtigrcTMWpnZFma2XYzjKDNrH2OsiOssM7PdzWzLWA3kW0Li/7PzbGZdzWyPmND+SEgIq5b7AuhiNfcMUZfr9AahKsYpZtY61jvfPuczEeLZsA7L56Qe17fFUiIsIiLF6C5gS7JXi8DdHyOUFA4zs2+ByUC2foZPIdxy/pzQMOo/KfNWIyQd8wlVBr4ChmTY3wLgVELCOh84AhhZh2OqzZ8Jifh04FXCD4E7alj+HGAaMC4e//Nkr7t6B+Fcvgx8Qkgw/1yfIGPSfgChEdcnhNLL2wiNviDU6/7AzL4jNJw7LNY7XpfwA+db4EPgJTJf35UIDcXmEa7X2oQ6zQAPx79fmdk7WeLL+Tq5+yJCY8v+hKT9KOBJYGGNJ+EntxPqMleY2Ygc18lV1utrZp1jTxWda9pAS2DVq62IiIi0fPEf/EfAulkaVIk0CjN7E7jZ3f9T68LS6FQiLCIiRSXe9j4DGKYkWBqbme1qZuvGqhHHAlsRGqZJM1Cwo7uIiIjUlZmtQqh3OZNwi12ksXUlVKNYhVAt5bfZus+TpqeqESIiIiJSlFQ1QkRERESKkhJhERFpcmY21sxOiM+PNLNnk46pUMXW/XnvYqsxmdmdZnZZjsvOMLO9GjumGvbfxcw8bZS8hmzvZDP7Il63NZO+fmbWz8xerWH+07Fuc0P3k+h1zEaJsIiI5E1McOfHPlpz4u73uXte+sstRu6+ahyGWJq52Jf0VcA+8bp9lXr9cvmBEJPyjeu5/zon9e7e293vqn3J/GnIMdaVEmEREckLM+sC/JowGtaByUZTu1ySgTg4Q5PtT1q8dYC2wAdJByKBEmEREcmXY4BxhAElcr6Vmn5rNpYGnWRm/4sDCdyYOkStmR1vZh/GkufRcZS0qnnXmtksM/vWzCaY2a9T5l1iZo+Y2b1xAIF+GWK508xuMrNRZvY9sLuZdTCzR81srpl9YmanpixfYmZ3xVg+NLOzzWx2yvwZcYS094HvYxdaO5rZ6/HY3jOz3dLOxXQzWxD3dWScvrGZvWRm35jZPDN7MO18bRyfr25md8dYZ5rZBbG7uOXn2cz+GeP9xMKoaNmuywwzG2hm75vZ92Z2u5mtE2+VLzCz581sjZTlDzSzD+JxjTWzzVLm9TCzd+J6DxKSwdR9HWBm78Z1XzezrbLFlbZeiZn9Kx7rN/H4SuK8h83s8zj9ZYsjBKZc5xvN7KkY05tmtlEtuzvezOaY2WdmdlbKtlYws3PN7GMz+8rMHjKzX2SIdVNganxZYWZj4nSP13cAcCRwtoXqEk9k2MbL8el7cZlD4/QTzWyamX1tZiPNrEOWY6havyKuv1PKtjO+L6x6Naas78MMsR4dr8tXZnZ+2rztzeyNeL0/M7MbzGzFbMdoZmuY2ZPxfT0/Pu+Ybd914u566KGHHnro0eAHYZSqPwLbEoa3XaeGZccCJ8Tn/YBXU+Y5YfStUqAzYSjbfeO8PnE/mxG6AL0AeD1l3aOANeO8Mwkjh7WN8y6JcfUlFASVZIjrTuAbYOe4zMrABOAiwtC6GxK6wOoVlx9MGMFsDaAj8D4wO2V7M4B3gU5ACVBGGFluv7j9vePr9oTutb4FusZ11wM2j88fAM6P67QFfpV2vjaOz+8GHgfaAV2A/wL9U87zYuBEoBVwMjCH2INUhnMxg/DDZp0Y95fAO0CPGMMY4OK47KaEUev2BtoAZ8frtGJ8zAT+Euf9NsZxWVy3R9z2DjGuY+O+V0qJY68sMd5IeC+VxXX/L2W94+N5WAm4Bng37Tp/RRjuuDVwH6Ff6Uz76BLP8QPxGm1JeE/uFeefFs9Tx7ivW4AHatlW6yzX786q81LDZ2f58vH1HoRR8raJ+78eeLkO+6/xfUH1z2rW92HafroB3wG7xJiuApaknLNtgR3jue9CGAnw9BqOcU3gEMLnsR1hBMARefneaqovSD300EMPPVruA/hV/Ge6Vnz9EfCXGpZP/efaj58nwqmJ3kPAufH508TELr5eAfgBWD/LfuYDW8fnl2RLEFKWvxO4O+X1DsCnacsMAv4Tny9PiuPrE/h5Inx8yutzgHvStjeakPytQhiG9xDSknRCgjsU6JghZgc2jknMIqBbyrw/AGNTzvO0lHkrx3XXzXIuZgBHprx+FLgp5fWfq5IR4ELgobTrUg7sFpOhagk38Do/JcI3AX9L2/dUYNeUOH6WCMd9VFZd31qua2k81tVTrvNtKfP3Az7Ksm6XuO4vU6ZdCdwen38I7Jkybz3CZ6F1DdvKZyJ8O3BlyutV4/675Lj/Gt8XVP+sZn0fpu3nIlJ+WBDe24syXcc4/3TgsWzHmGH57sD82q57Lg9VjRARkXw4FnjW3efF1/dTh+oRGXye8vwHwj93gPWBa+Mt1Qrga8AIJYKY2VkWqih8E+evDqyVsq1ZOew7dZn1gQ5V+4vbPI9QSgrQIW35TNtP397v0rb3K2A9d/8eOBQ4Cfgs3rb/ZVzv7Hicb8XqB8dn2M9ahBLXmSnTZhLPTbT8vLr7D/HpqmT3Rcrzygyvq9btkLpfd19GOO6yOK/cYwaTEleV9YEz085Jp7heTdYilEp+nD7DzFqZ2eBYXeFbQjJdtU6VbO+xbFKv48yU+NYHHkuJ/UNgKT+9Rxpb+rn/jlDaXZZ1jZ/L9X2Ry/uwKqbl5yu+t7+qem1mm8bqDZ/H6/N3ql+basxsZTO7JVa1+JZQxaPU8lCHX4mwiIg0SKyT+Xtg1/iP7XPCbfCtzWzrPO9uFvAHdy9NeZS4++sW6gOfHWNZw91LCdUcLGV9//kmfyZ1mVnAJ2n7a+fu+8X5nxFuiVfplMP27knb3iruPhjA3Ue7+96EUsWPgFvj9M/d/UR370Ao5f23/bxV/TxCSeD6KdM6E0pmG9uc1P2amRHORTnhHJXFaalxVZkFXJ52TlZ29wdq2ec84EcgU93eIwjVaPYi/BjqUhVa7of0M6nXtjPhmCHE3zst/rbuXp/znsv7M136uV+FUJUg0/7rs/2fVs7tfQjhmi8/X2a2coypyk2E9/cm7r4a4cdlTdfmTMIIfTvE5Xep2nS9DyZSIiwiIg3Vl1AC1o1wy7I7oQ7vK4QGdPl0MzCoquGThcZhv4vz2hHqIc4FWpvZRcBqDdzfW8ACCw3eSmJJ4xZmtl2c/1CMZw0zKwNOqWV79wK/MbNecVttzWw3M+tooSFan5jILCTUsVwWj/N3KY2D5hMSmmWpG3b3pTGey82snYVGhGfEfTa2h4D9zWxPC12EnRmP4XXgDcJ1OdXM2pjZwYS6uVVuBU4ysx0sWMXM9jezdjXtMJY63wFcZaFBYysz28lC133t4v6/Itzq/3sejvHCWDK5OXAcUNVQ7GbCOV8fwMzam1mfeu7jC0I99Los8wBwnJl1j8f+d+BNd5+RYd25hPdNvfotzuV9GD0CHGBmv4qN4C6les7ZjlAf/rt41+PktPXTj7Ed4Q5EhYWGiBfXJ/5MlAiLiEhDHUuoM/tpLDH63N0/B24AjrQ8dhvm7o8B/wCGxVukk4GqFu6jgWcIDcRmEkoLc6kKUdP+lgIHEJL7TwilkLcRShkh/IOfHec9T0gAFtawvVmEksrzCEnJLGAg4f/xCoTEdQ6hyseu/JQgbAe8aWbfASOB0zxz38F/JjRamw68SqiickedD7yO3H0qoaHi9YRz9BvgN+6+yN0XAQcT6qJ+Taj+MTxl3fGEhlo3EJKraWTo0SOLs4BJwNtx2/8gnMe7Ce+BcmAKoTFbQ70UY3sB+Ke7Vw0Ccy3hmjxrZgvivnao5z5uB7rFahYjsixzCXBXXOb37v48oY72o4SS2I2AwzKtGKs9XA68FtffsY7x5fQ+dPcPgD8R3n+fEa7r7JRFziKU2i8g/BBK732i2jESGjuWEN5b4wif8+XM7GYzu7mOxxLWrV5lR0REROrLzE4GDnP3XZOORURqpxJhERGRejKz9cxsZwt9yXYlVAl4LOm4RCQ3GuVGRESk/lYk9Bu7AaHrs2HAv5MMSERyp6oRIiIiIlKUVDVCRERERIqSEmERERERKUqJ1RFea621vEuXLkntXkSk3iZMmDDP3dsnHUdT0ne2iBSybN/biSXCXbp0Yfz48UntXkSk3sxsZu1LtSz6zhaRQpbte1tVI0RERESkKCkRFhEREZGiVGsibGZ3mNmXZjY5y3wzs+vMbJqZvW9m2+Q/TBERERGR/MqlRPhOYN8a5vcGNomPAcBNDQ9LRERERKRx1ZoIu/vLwNc1LNIHuNuDcUCpma2XrwBFRERERBpDPnqNKANmpbyeHad9lr6gmQ0glBrTuXPnPOxaRKR+RkwsZ8joqcypqKRDaQkDe3Wlb4+ypMMSEZEMGus7u0kby7n7UHfv6e4927cvqi44RaQZGTGxnEHDJ1FeUYkD5RWVDBo+iRETy5MOTURE0jTmd3Y+EuFyoFPK645xmohIszRk9FQqFy+tNq1y8VKGjJ6aUEQiIpJNY35n56NqxEjgFDMbBuwAfOPuP6sWISJSk6asqjCnorJO00VEJDmN+Z1dayJsZg8AuwFrmdls4GKgDYC73wyMAvYDpgE/AMc1OCoRKSpVt72qfvFX3fYCGiUZ7lBaQnmGL9AOpSV535eIiDRMY35n59JrxOHuvp67t3H3ju5+u7vfHJNgYm8Rf3L3jdx9S3fXGJwiUidNXVVhYK+ulLRpVW1aSZtWDOzVtVH2JyIi9deY39n5qBohItIgTV1VoaqUWb1GiIg0f435na1EWEQSl0RVhb49ypT4iogUiMb6zm7S7tNERDJRVYVkmFkrM5toZk8mHYuISK1eeAGm5rfKnBJhEUlc3x5lXHHwlpSVlmBAWWkJVxy8pUpsG99pwIdJByEiUqPKSjj9dNhrL7j00rxuWlUjRKRZUFWFpmVmHYH9gcuBMxIOR0QkswkT4Oij4cMP4dRTYfDgvG5eJcIiIsXpGuBsYFnCcYiI/NySJfC3v8GOO8KCBfDcc3DttVCS37YjSoRFRIqMmR0AfOnuE2pZboCZjTez8XPnzm2i6ESk6P33v/CrX8FFF8Hvfw/vvx+qRTQCJcIiIsVnZ+BAM5sBDAP2MLN70xdy96Hu3tPde7Zv376pYxSRYuMO//43dO8ekuEHH4T77oM11mi0XSoRFhEpMu4+KA6Q1AU4DBjj7kclHJaIFLM5c6B3b/jTn2CXXWDy5FAa3MiUCIuIiIhIch58ELbYAl55JZQIP/00dOjQJLtWIiwiUsTcfay7H5B0HCJShObPhyOOgMMOg003hXffhZNPBrMmC0Hdp4nIciMmlmvYYRERaXzPPQfHHQdffBF6hzj3XGjd9GmpSoRFBAhJ8KDhkyivqMSB8opKBg2fxIiJ5UmHJiIiLcUPP8Cf/wz77AOrrQbjxsEFFySSBIMSYRGJhoyeSuXipdWmVS5eypDR+R3OUkRECt+IieXsPHgMG5z7FDsPHpNbocnbb8M228ANN4SR4iZMgG23bfRYa6JEWEQAmFNRWafpIiJSnOp8B3HxYrjkEthpp1Ai/MILcPXVeR8coz6UCIsIAB1KM38hZZsuIiLFqU53ED/6CP7v/+Cvf4XDDw+DY+yxRxNFWjslwiICwMBeXSlp06ratJI2rRjYq2tCEYmISHOU0x3EZcvg+uuhRw/45BN4+GG45x4oLW2aIHOkXiNEBGB57xDqNUJERGrSobSE8gzJ8PI7iLNnhx4hnn8e9tsPbrsN1luviaPMjRJhEVmub48yJb4iIlKjgb26Mmj4pGrVI0ratGLgPpvC/feH0eEWL4ZbboETT2zSfoHrSomwiIiIiOQs0x3E83Zcm/3/cSY89FBoFHf33bDxxglHWjslwiIiIiJSJ9XuID7zDByxD8ydC5dfDmefnVi/wHWlxnIiIiIiUnfffw9//CP07g1rrAFvvQXnnVcwSTAoERYRERGRunrzzdAjxM03wxlnhMExevRIOqo6UyIsIiIiIrlZvBguvDD0DbxwIYwZA//6F7Rtm3Rk9VI4ZdciIiIikpwpU+Doo+Gdd+DYY+Haa2H11ZOOqkFUIiwiIiIi2S1bBtdcA9tsA59+CsOHw513FnwSDCoRFhEREZFsPv00DI4xZgwccADceiusu27SUeWNSoRFRIqQmbU1s7fM7D0z+8DM/pp0TCLSjLiHIZG32ir0BnHrrTByZItKgkElwiIixWohsIe7f2dmbYBXzexpdx+XdGAikrB58+Ckk+DRR2HnncPgGBtumHRUjUKJsEgTGDGxvNoIPAN7ddVQxpIod3fgu/iyTXx4chGJSLMwahT07w9ffQWDB8NZZ0GrVklH1WhUNUKkkY2YWM6g4ZMor6jEgfKKSgYNn8SIieVJhyZFzsxamdm7wJfAc+7+ZsIhiUhSvvsulALvvz+0bw9vvw3nnNOik2BQIizS6IaMnkrl4qXVplUuXsqQ0VMTikgkcPel7t4d6Ahsb2ZbpM43swFmNt7Mxs+dOzeRGEWkCbzxBnTvDkOHwsCBIQneeuuko2oSOSXCZravmU01s2lmdm6G+Z3N7EUzm2hm75vZfvkPVaQwzamorNN0kabm7hXAi8C+adOHuntPd+/Zvn37RGITkUa0aBGcfz786lewdCmMHQtXXgkrrZR0ZE2m1kTYzFoBNwK9gW7A4WbWLW2xC4CH3L0HcBjw73wHKlKoOpSW1Gm6SFMws/ZmVhqflwB7Ax8lGpSINJ3Jk2GHHeDvfw/do733HuyyS9JRNblcSoS3B6a5+3R3XwQMA/qkLePAavH56sCc/IUoUtgG9upKSZvqdaxK2rRiYK+uCUUkAsB6wItm9j7wNqGO8JMJxyQijW3ZMrjqKujZE8rL4fHH4bbbYLXVal+3Bcql14gyYFbK69nADmnLXAI8a2Z/BlYB9spLdCItQFXvEOo1QpoTd38f6JF0HCLShGbOhH79QhWIPn1CneC11046qkTlq/u0w4E73f1fZrYTcI+ZbeHuy1IXMrMBwACAzp0752nXIs1f3x5lSnxFRCQZ7qEv4FNPDc/vuCMkxGZJR5a4XKpGlAOdUl53jNNS9QceAnD3N4C2wFrpG1LDCxEREZEmNHcuHHJISHy7d4f33w91gpUEA7klwm8Dm5jZBma2IqEx3Mi0ZT4F9gQws80IibD62hERERFJypNPwhZbwFNPwT//CS++CF26JB1Vs1JrIuzuS4BTgNHAh4TeIT4ws0vN7MC42JnAiWb2HvAA0C+OWiQiIiIiTWnBAjjxRPjNb2C99WD8eDjzTFhBw0eky6mOsLuPAkalTbso5fkUYOf8hiYiIiIidfLqq3DMMaFh3KBBcPHFRdUvcF3pp4GIiIhIoVu4EM49N/QFbAYvvxz6CFYSXKN89RohIiIiIkmYNAmOOio0hDvxxNBP8KqrJh1VQVCJsIiIiEghWroUhgwJg2N88QU88UToG1hJcM5UIiwiIiJSaD75BI49Fl55BQ4+GG6+GdQ1bZ2pRFhERESkUFQNiLHVVvDee2GgjEceURJcT0qERURERArBl1/CQQdB//6w3XahbvDRR2twjAZQIiwiIiLS3D3+eBgc45lnQmO4559nxFet2HnwGDY49yl2HjyGERPTB/6V2igRFhEREWmuvv0Wjj8e+vaFjh1hwgT4y18Y8d5nDBo+ifKKShwor6hk0PBJSobrSImwiIiISHP08suw9dZw111w/vkwbhxsvjkAQ0ZPpXLx0mqLVy5eypDRU5OItGApERYRERFpTn78EQYOhN12g9atw2hxl10GK664fJE5FZUZV802XTJT92kiwIiJ5QwZPZU5FZV0KC1hYK+u9O1RlnRYIiJSbN57LwyOMXkynHQS/POfsMoqP1usQ2kJ5RmS3g6lJU0RZYuhEmEpeiMmlquelRQdM+tkZi+a2RQz+8DMTks6JpGitnQpDB4ceoOYNw9GjYKbbsqYBAMM7NWVkjatqk0radOKgb26NkW0LYYSYSl6qmclRWoJcKa7dwN2BP5kZt0SjkmkOE2fDrvuCoMGhUZxkydD7941rtK3RxlXHLwlZaUlGFBWWsIVB2+pu5l1pKoRUvRUz0qKkbt/BnwWny8wsw+BMmBKooGJFBN3uO02+MtfQl3ge++FI47IuV/gvj3KlPg2kEqEpehlq0+lelZSLMysC9ADeDPhUESKx+efw4EHwoABsMMOYXCMI4/U4BhNTImwFD3Vs5JiZmarAo8Cp7v7t2nzBpjZeDMbP3fu3GQCFGmJhg8Pg2M8/zxcey089xx06pR0VEVJibAUPdWzkmJlZm0ISfB97j48fb67D3X3nu7es3379k0foEhL8803cOyxcMgh0KULvPMOnHoqrKB0LCmqIyyC6llJ8TEzA24HPnT3q5KOR6TFe/FF6NcPysvhoovgggugTZukoyp6+gkiIlKcdgaOBvYws3fjY7+kgxJpcX78Ec44A/bYA1ZaCV57Df76VyXBzYRKhEVEipC7vwqoVY5IY5o4MQyOMWUK/PGPcOWVWfsFlmSoRFhEREQkn5Ysgcsvh+23h/nz4Zln4MYblQQ3QyoRFhEREcmXadPgmGPgjTfg0EPh3/+GX/wi6agkC5UIi4iIiDSUO9x8M2y9NXz4Idx/PwwbpiS4mVOJsIiIiEhDfPYZ9O8PTz8Ne+8Nd9wBHTsmHZXkQImwiIiISIoRE8sZMnoqcyoq6VBawsBeXbN3sfnww3DSSVBZCddfHxrFqV/ggqFEWERERCQaMbGcQcMnUbl4KQDlFZUMGj4JoHoyXFEBp5wC990H220H99wDXTUiaaHRTxYRERGRaMjoqcuT4CqVi5cyZPTUnya88AJsuWWoA3zJJaFvYCXBBUmJsIiIiEg0p6Iy+/TKSjjtNNhrr9AV2htvwMUXa3CMAqaqESIiIiJRh9ISyjMkw3t89ylssw189BH8+c8weDCsvHICEUo+qURYREREJBrYqyslbVotf91q2VLOfGMYt95yKixYAM8+C9ddpyS4hVCJsIiIiEhU1SBuyOiprDR9Gtc/fTWbz/4IjjgCbrgB1lgj4Qgln5QIi4iIiKTo270DfV8fAfcOhLZtQ6O4Qw9NOixpBEqERURERKqUl8Pxx4cqEL16we23Q1mWPoSl4OVUR9jM9jWzqWY2zczOzbLM781sipl9YGb35zdMERERkUb24IOhW7RXXoEbbwwjxSkJbtFqLRE2s1bAjcDewGzgbTMb6e5TUpbZBBgE7Ozu881s7cYKWERERCSv5s+HP/0JHngAdtgB7r4bNt006aikCeRSIrw9MM3dp7v7ImAY0CdtmROBG919PoC7f5nfMEVEREQawXPPhVLghx+Gv/0NXn1VSXARySURLgNmpbyeHael2hTY1MxeM7NxZrZvvgIUEZH8M7M7zOxLM5ucdCwiifjhhzBE8j77QLt2MG4cXHABtFbzqWKSr36EWwObALsBhwO3mllp+kJmNsDMxpvZ+Llz5+Zp1yIiUg93Aiq0kOL09tvQo0eoB3zaafDOO7DttklHJQnIJREuBzqlvO4Yp6WaDYx098Xu/gnwX0JiXI27D3X3nu7es3379vWNWUREGsjdXwa+TjoOkSa1eDFccgnstFMoEX7+ebjmGigpSToySUgu5f9vA5uY2QaEBPgw4Ii0ZUYQSoL/Y2ZrEapKTM9jnCIiIiIAjJhYzpDRU5lTUUmH0hIG9uq6fCCMrD76CI4+GsaPh6OOguuvh9LSJolXmq9aS4TdfQlwCjAa+BB4yN0/MLNLzezAuNho4CszmwK8CAx0968aK2gREWl8qs4mzdGIieUMGj6J8opKHCivqGTQ8EmMmJh+szpatiwkvT16wPTpoVHcPfcoCRYgxwE13H0UMCpt2kUpzx04Iz5ERKQFcPehwFCAnj17esLhiABh6OPKxUurTatcvJQho6f+vFR49mw47rhQBaJ37zA4xnrrNWG00tzlq7GciIiISKObU1FZ+3R3uP/+0C3a66/DzTfDU08pCZafUSIsIlKEzOwB4A2gq5nNNrP+ScckkosOpZkbti2f/vXXcNhhcOSRsNlm8N578Ic/gFkTRimFQomwiEgRcvfD3X09d2/j7h3d/fakYxLJxcBeXSlp06ratJI2rRjYqys88wxssQUMHw6XXw4vvwwbb5xQpFII1Gu0iIiIFIyqesCpvUacu0snfnPr5XDTTdCtW6gG0aNHwpFKIVAiLCIiIgWlb4+ynxrGvfkmHL0/TJsGZ5wRSoLbtk02QCkYqhohIiIihWfxYrjoIth5Z1i4EMaMgX/9S0mw1IlKhEVERKSwfPhhGBxjwgQ49li49lpYffWko5ICpBJhERERKQzLloWkd5ttYOZMePRRuPNOJcFSbyoRFhERkebv00/D4BhjxsABB8Ctt8K66yYdlRQ4lQiLiIhI8+UO994LW20VGsbdeiuMHKkkWPJCibCIiIg0T/Pmwe9/H+oDb7EFvP8+nHCCBseQvFEiLCIiIs3PqFFhiOTHH4fBg+Gll2DDDZOOSloYJcIiIiLSfHz3HZx0Euy/P7RvD2+/DeecA61a1b6uSB0pERYREZHm4fXXoXt3GDoUBg4MSfDWWycdlbRgSoRFREQkWYsWwXnnwa9/DUuXwtixcOWVsNJKSUcmLZy6TxMREZHkTJ4cGsO9+y4cfzxcfTWstlrSUUmRUImwiIiINL1ly+Cqq6BnTygvhxEj4PbblQRLk1KJsIiIiDStmTPD0MgvvQR9+oQ6wWuvnXRUUoRUIiwiIiJNwz0MibzllvDOO3DHHfDYY0qCJTFKhEVEipSZ7WtmU81smpmdm3Q80sLNnQuHHBKGSe7RIwyOcdxxGhxDEqVEWESkCJlZK+BGoDfQDTjczLolG5W0WE88EUaGe+opGDIExoyBLl2SjkpEibCISJHaHpjm7tPdfREwDOiTcEzS0ixYACeeCAceCOutB+PHw1lnaXAMaTaUCIuIFKcyYFbK69lxmkh+vPpqGAzjjjvg3HPhzTdD3WCRZkSJsIiIZGRmA8xsvJmNnzt3btLhSKFYuDAMibzLLqH+78svwxVXaHAMaZaUCIuIFKdyoFPK645x2nLuPtTde7p7z/bt2zdpcFKgJk2C7bcPo8KdcEIYJGPnnZOOSiQrJcIiIsXpbWATM9vAzFYEDgNGJhyTFKqlS0MjuJ494YsvQuO4oUOhXbukIxOpkQbUEBEpQu6+xMxOAUYDrYA73P2DhMOSQvTJJ2FwjFdegYMPhptvBt1BkAKhRFhEpEi5+yhgVNJxSIFyh//8B047DVZYAe66C44+Wv0CS0FRIiwiIiJ18+WXoVu0kSNht93CaHHrr590VCJ1pjrCIiIikrvHHw+DY4weDVddBS+8oCRYCpZKhEVERKR2334Lp58eqkP06AH33AObb17jKiMmljNk9FTmVFTSobSEgb260reHuquW5kOJsIiIiNTspZdCg7hZs+D88+Gii2DFFWtcZcTEcgYNn0Tl4qUAlFdUMmj4JAAlw9JsqGqEiIiIZPbjjzBwIOy+O7RpE0aLu+yyWpNggCGjpy5PgqtULl7KkNFTGytakTrLKRE2s33NbKqZTTOzc2tY7hAzczPrmb8QRX4yYmI5Ow8ewwbnPsXOg8cwYmJ57SuJiEjdvfcebLcd/POf8Ic/wMSJsNNOOa8+p6KyTtNFklBrImxmrYAbgd5AN+BwM+uWYbl2wGnAm/kOUgR+us1WXlGJ89NtNiXDIiJ5tHQpDB4ckuB582DUKLjpJlh11TptpkNpSZ2miyQhlxLh7YFp7j7d3RcBw4A+GZb7G/AP4Mc8xieynG6ziYg0so8/hl13hUGDoG9fmDwZeveu16YG9upKSZtW1aaVtGnFwF5d8xCoSH7kkgiXAbNSXs+O05Yzs22ATu7+VB5jE6lGt9lERBqJO9x6K2y9dUh+770XHnwQ1lyz3pvs26OMKw7ekrLSEgwoKy3hioO3VEM5aVYa3GuEma0AXAX0y2HZAcAAgM6dOzd011JkOpSWUJ4h6dVtNhGRBvj88zA4xpNPwh57hMExOnXKy6b79ihT4ivNWi4lwuVA6ieiY5xWpR2wBTDWzGYAOwIjMzWYc/eh7t7T3Xu21zjkUke6zSYikmfDh4fBMZ5/Hq65Bp57Lm9JsEghyKVE+G1gEzPbgJAAHwYcUTXT3b8B1qp6bWZjgbPcfXx+Q5ViV1WqoM7ZRUQa6Jtv4NRT4e67Ydttw+AYm22WdFQiTa7WRNjdl5jZKcBooBVwh7t/YGaXAuPdfWRjBylSRbfZREQa6MUXoV8/KC8PA2NccEHoI1ikCOVUR9jdRwGj0qZdlGXZ3RoeloiIiOTVjz/CeefB1VfDJpvAa6/BDjskHZVIojTEsoiISEs3cSIcdRRMmQJ//CNceSWsskrSUYkkTkMsi4iItFRLlsDll8P228P8+fDMM3DjjUqCRSIlwiIiRcbMfmdmH5jZskw9/EgLMW0a7LJLqAN8yCGhf+BevZKOSqRZUSIsIlJ8JgMHAy8nHYg0Ane4+eYwOMaHH8L998OwYfCLXyQdmUizozrCIiJFxt0/BDCzpEORfPvsM+jfH55+GvbeG+64Azp2TDoqkWZLJcIiIiItwcMPh8Exxo6F668P9YGVBIvUSCXCIiItkJk9D6ybYdb57v54jtsYAAwA6Ny5cx6jk7yqqIBTToH77oPttguDY3TViJsiuVAiLCLSArn7XnnYxlBgKEDPnj29wUFJ/r3wQhgc47PP4JJLQj/BGhxDJGeqGiEiIlJoKivhtNNgr71CV2hvvAEXX6wkWKSOlAiLiBQZMzvIzGYDOwFPmdnopGOSOhg/HrbZBq67Dv78Z3jnnVAlQkTqTFUjRESKjLs/BjyWdBxSR0uWwBVXwKWXwjrrwLPPhp4hRKTelAiLiIg0d//9Lxx9NLz1FhxxBNxwA6yxRtJRiRQ8VY0QERFprtzDkMjdu8P//gcPPhh6h1ASLJIXKhEWERFpjsrL4fjjQxWIXr3C4BgdOiQdlUiLohJhERGR5ubBB2HLLeHVV+Hf/w4jxSkJFsk7JcIiIiLNxfz5oQ7wYYfBppvCu+/CySeDhsMWaRRKhEVERJqD554LpcAPPwx/+1soDd5kk6SjEmnRlAiLiIgk6YcfwhDJ++wDq60G48bBBRdAazXjEWlsSoRFRESS8vbb0KNH6Bni9NNhwgTYdtukoxIpGkqERUREmtrixXDJJbDTTmG45BdegKuvhpKSpCMTKSq67yIiItKUPvooDI4xfnz4e911UFqadFQiRUklwiIiIk1h2bKQ9PboAZ98Ao88AnffrSRYJEEqERYREWlss2fDccfB88/DfvvBbbfBeuslHZVI0VOJsIiISGNxh/vvD92ivfEG3HILPPmkkmCRZkKJsIiISGP4+uswMMaRR8Jmm4XBMQYM0OAYIs2IqkaIiIjk2zPPwPHHw7x58Pe/w8CBTdYv8IiJ5QwZPZU5FZV0KC1hYK+u9O1R1iT7Fik0KhEWERHJl++/Z/rvj4XevZm6uA39TrqeEfse06RJ8KDhkyivqMSB8opKBg2fxIiJ5U2yf5FCo0RYRKTImNkQM/vIzN43s8fMrDTpmFqEceP4rtuWdHn4HoZudxAHHnsNY1fu2KSJ6JDRU6lcvLTatMrFSxkyemqT7F+k0CgRFhEpPs8BW7j7VsB/gUEJx1PYFi+GCy+EnXfmu2+/54jDL+fve/RnYesVgaZNROdUVNZpukixUx1hEZEi4+7PprwcB/w2qVgK3pQpYVCMd96BY49lnzX249uVVvnZYk2ViHYoLaE8w746lGrEOpFMVCIsIlLcjgeeTjqIgrNsGVxzDWyzDXz6KQwfDnfeSbt11sq4eFMlogN7daWkTatq00ratGJgr65Nsn+RQqNEWESkBTKz581scoZHn5RlzgeWAPdl2cYAMxtvZuPnzp3bVKE3f59+CnvvDX/5C+yzD0yeDAcdBCSfiPbtUcYVB29JWWkJBpSVlnDFwVuq1wiRLFQ1QkSkBXL3vWqab2b9gAOAPd3ds2xjKDAUoGfPnhmXKSrucO+9cMopoUT41luhf/9q/QJXJZxJdl/Wt0eZEl+RHOWUCJvZvsC1QCvgNncfnDb/DOAEQsnCXOB4d5+Z51hFRCQP4nf62cCu7v5D0vEUhHnz4KST4NFHYeed4e67YcMNMy6qRFSkcNRaNcLMWgE3Ar2BbsDhZtYtbbGJQM/YAvkR4Mp8ByoiInlzA9AOeM7M3jWzm5MOqFkbNSoMkTxyJAweDC+9lDUJFpHCkkuJ8PbANHefDmBmw4A+wJSqBdz9xZTlxwFH5TNIERHJH3ffOOkYCsJ338GZZ8LQoSERfuYZ2HrrpKMSkTzKpbFcGTAr5fXsOC2b/qgFsoiIFLLXX4fu3UM94IED4e23lQSLtEB57TXCzI4CegJDssxXC2QREWm+Fi2C886DX/8ali6FsWPhyithpZWSjkxEGkEuiXA50Cnldcc4rRoz2ws4HzjQ3Rdm2pC7D3X3nu7es3379vWJV0REpHFMngw77ABXXAH9+sF778EuuyQdlYg0olwS4beBTcxsAzNbETgMGJm6gJn1AG4hJMFf5j9MERGRRrJsGVx1FfTsCeXlMGIE3H47rLZa0pGJSCOrtbGcuy8xs1OA0YTu0+5w9w/M7FJgvLuPJFSFWBV42EJ/ip+6+4GNGLeIiEjDzZwJxx4beoLo0yc0jFt77aSjEpEmklM/wu4+ChiVNu2ilOc1dtwuIiLSrLjDXXfBqaeG13fcEapDpAyOISItn4ZYFhGR4jJ3LhxyCBx3HPToAe+/H54rCRYpOkqERUSkeDz5JGyxBTz1FAwZAmPGQJcuSUclIglRIiwiIi3fggVw4onwm9/AeuvB+PFw1lnQqlXSkYlIgnKqIywiIlIXIyaWM2T0VOZUVNKhtISBvbrSt0dNYzE1oldfhWOOCQ3jzj0XLrlE/QKLCKASYRERybMRE8sZNHwS5RWVOFBeUcmg4ZMYMfFnXdA3roUL4ZxzQl/AZvDyy6GPYCXBIhIpERYRkbwaMnoqlYuXVptWuXgpQ0ZPbbogJk2C7bcPo8KdcAK8+y7svHPT7V9ECoKqRkitmtUtThFp9uZUVNZpel4tXRoGx7jgAlhjDXjiCTjggMbfr4gUJCXCBSDJRLTqFmdV6U7VLU5AybCIZNShtITyDElvh9KSxt3xJ5+EwTFeeQUOOghuuQXat2/cfYpIQVPViGYu6bp2zeIWp4gUlIG9ulLSpnpvDCVtWjGwV9fG2aF7GBBjq63gvffCQBmPPqokWERqpUS4mUs6EU30FqeIFKS+Pcq44uAtKSstwYCy0hKuOHjLxrmL9OWX0Lcv9O8PPXuGwTGOOUaDY4hITlQ1oplLOhFN7BaniDQaM/sb0AdYBnwJ9HP3OfncR98eZY1fferxx0PfwN9+G+oFn3YarKDyHRHJnb4xmrlsCWdTJaJNfotTRJrCEHffyt27A08CFyUcT918+y0cf3woCS4rgwkT4C9/URIsInWmb41mLulEtElvcYpIk3D3b1NergJ4UrHU2csvw9Zbh3rA550Hb74Jm2+edFQiUqBUNaKZq0o4k+y+rElucYpIkzKzy4FjgG+A3RMOp3Y//ggXXgj/+hdsuGHoGeL//i/pqESkwCkRLgBKREWkrszseWDdDLPOd/fH3f184HwzGwScAlycYRsDgAEAnTt3bsxwa/bee3zz20NZfdpU7uu+L//pewqnlKxP3+QiEpEWQomwiEgL5O575bjofcAoMiTC7j4UGArQs2fPpq8+sXQpDBnCsgsvYlHbVen324sZu9F2UIn6MxeRvFAdYRGRImNmm6S87AN8lFQsWU2fDrvuCoMGMfaXO7HPcTeEJDhSf+Yikg8qERYRKT6Dzawrofu0mcBJCcfzE3e47bbQC0Tr1nDPPfSfVIpn6BdY/ZmLSEMpERYRKTLufkjSMWT0+eehX+Ann4Q99oA774ROnegweIz6MxeRRqGqESIikrzhw2GLLeD55+Gaa+C556BTJyD5biRFpOUqmBLhERPLE+1CTEREGsE338Cpp8Ldd8O228I998Bmm1VbpDl0IykiLVNBJMIjJpYzaPgkKhcvBaC8olIthkVECt2LL0K/flBeHvoIvvBCaNMm46LqRlJEGkNBVI0YMnrq8iS4iloMi4gUqB9/hDPOCPWAV1oJXnsNLr00axIsItJYCqJEOFvLYLUYFhEpMBMnwlFHwZQp8Mc/wpVXwiqrJB2ViBSpgigRztYyWC2GRUQKxJIlcPnlsP32MH8+PPMM3HijkmARSVRBJMKN0WJ4xMRydh48hg3OfYqdB49hxMTyhoYpIiKZTJsGu+wCF1wAhxwCkydDr15JRyUiUhhVI/LdYliN70REmoA73HILnHkmrLgi3H8/HH540lGJiCxXEIkw5LfFcE2N75QIi4jkyYABYZS4vfeGO+6Ajh2TjkhEpJqCSYTzSY3vRESawOGHw1ZbwZ/+BCsURE08ESkyRZkIdygt0XCdIiKNbY89wkNEpJkqyp/oGq5TRERERIqyRFjDdYqIiIhIUSbCoOE6RURERIpdTlUjzGxfM5tqZtPM7NwM81cyswfj/DfNrEveIxURERERyaNaE2EzawXcCPQGugGHm1m3tMX6A/PdfWPgauAf+Q5URERERCSfcikR3h6Y5u7T3X0RMAzok7ZMH+Cu+PwRYE8zs/yFKSIiIiKSX7kkwmXArJTXs+O0jMu4+xLgG2DNfAQoIiIiItIYmrT7NDMbYGbjzWz83Llzm3LXIiIiIiLV5NJrRDnQKeV1xzgt0zKzzaw1sDrwVfqG3H0oMBTAzOaa2cws+1wLmJdDbIVMx9hyFMNx6hirW78xA2mOJkyYME/f2S3+GKE4jlPH2HI0+Hs7l0T4bWATM9uAkPAeBhyRtsxI4FjgDeC3wBh395o26u7ts80zs/Hu3jOH2AqWjrHlKIbj1DGKvrNb/jFCcRynjrHlyMdx1poIu/sSMzsFGA20Au5w9w/M7FJgvLuPBG4H7jGzacDXhGRZRERERKTZymlADXcfBYxKm3ZRyvMfgd/lNzQRERERkcbTpI3l6mBo0gE0AR1jy1EMx6ljlJoUw7krhmOE4jhOHWPL0eDjtFqq8oqIiIiItEjNtURYRERERKRRJZYIm9m+ZjbVzKaZ2bkZ5q9kZg/G+W+aWZcEwmywHI7zDDObYmbvm9kLZlZw3TLVdowpyx1iZm5mBdeSNZdjNLPfx2v5gZnd39Qx5kMO79fOZvaimU2M79n9koizIczsDjP70swmZ5lvZnZdPAfvm9k2TR1jc1UM39v6zq62XMF+Z0NxfG/rOzsP39nu3uQPQu8THwMbAisC7wHd0pb5I3BzfH4Y8GASsTbBce4OrByfn1xox5nLMcbl2gEvA+OAnknH3QjXcRNgIrBGfL120nE30nEOBU6Oz7sBM5KOux7HuQuwDTA5y/z9gKcBA3YE3kw65ubwKIbvbX1nV1uuYL+z63AtC/p7W9/Zy+c36Ds7qRLh7YFp7j7d3RcBw4A+acv0Ae6Kzx8B9jQza8IY86HW43T3F939h/hyHGHAkkKSy7UE+BvwD+DHpgwuT3I5xhOBG919PoC7f9nEMeZDLsfpwGrx+erAnCaMLy/c/WVCN4/Z9AHu9mAcUGpm6zVNdM1aMXxv6zv7J4X8nQ3F8b2t7+ygQd/ZSSXCZcCslNez47SMy7j7EuAbYM0miS5/cjnOVP0Jv2oKSa3HGG9TdHL3p5oysDzK5TpuCmxqZq+Z2Tgz27fJosufXI7zEuAoM5tN6FLxz00TWpOq6+e2WBTD97a+s2kR39lQHN/b+s4OGvSdnVM/wtL4zOwooCewa9Kx5JOZrQBcBfRLOJTG1ppwm203QgnRy2a2pbtXJBlUIzgcuNPd/2VmOxEG0tnC3ZclHZhIU9J3dotQDN/b+s6uRVIlwuVAp5TXHeO0jMuYWWtCkf5XTRJd/uRynJjZXsD5wIHuvrCJYsuX2o6xHbAFMNbMZhDq74wssMYXuVzH2cBId1/s7p8A/yV8wRaSXI6zP/AQgLu/AbQljPXekuT0uS1CxfC9re/slvGdDcXxva3v7KBB39lJJcJvA5uY2QZmtiKhUcXItGVGAsfG578FxnisFV1Aaj1OM+sB3EL4Qi20+klQyzG6+zfuvpa7d3H3LoQ6dQe6+/hkwq2XXN6vIwilCpjZWoRbbtObMMZ8yOU4PwX2BDCzzQhfqnObNMrGNxI4JrZE3hH4xt0/SzqoZqAYvrf1nd0yvrOhOL639Z0dNOw7O8FWgPsRfn19DJwfp11K+MBBuFgPA9OAt4ANk4q1kY/zeeAL4N34GJl0zPk+xrRlx1KYLZBru45GuJ04BZgEHJZ0zI10nN2A1witk98F9kk65noc4wPAZ8BiQolQf+Ak4KSUa3ljPAeTCvH9muD7o+C/t/Wd/bNlC/I7O8drWfDf2/rObvh3tkaWExEREZGipJHlRERERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaKkRFhEREREipISYREREREpSkqERURERKQoKREWERERkaLUohNhM9vNzGYnHUdSzOxpMzu2EbZ7p5ldFp//2sym5nsfTcXMLjGze5OOIx/M7DIzm2dmnycdSzozG2tmJ2SZ1yjXwMxmmNle+d6uiIi0HM0iETaze83sMzP71sz+m+0fZob1njaz7+JjsZktSnl9c2PH3dy5e293v6uR9/GKu3dtzH0UitQfCAnsuzNwJtDN3ddNIoZCZmZuZhsnHYeIiDSt1kkHEF0B9Hf3hWb2S2CsmU109wk1reTuvauem9mdwGx3vyBl2m6NEy6YWWt3X5LH7bVy96X52p40P/l+z6TpDHzl7l/WdcVGjktERKTZahYlwu7+gbsvrHoZHxvla/tmdqaZfRlLnY9Lmb6Smf3TzD41sy/M7GYzK8myjX5m9pqZXW1mXwGX1La+mZ0d9znHzE5ILXWKpYc3mdkoM/se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\n", 55 | "text/plain": [ 56 | "
" 57 | ] 58 | }, 59 | "metadata": { 60 | "needs_background": "light" 61 | }, 62 | "output_type": "display_data" 63 | } 64 | ], 65 | "source": [ 66 | "plt.figure(figsize=(12, 10))\n", 67 | "plt.subplots_adjust(hspace=.5)\n", 68 | "plt.subplot(2,2,1)\n", 69 | "plt.title('1. Start with some points forming an \"S\" shape\\n\\n', fontsize=12)\n", 70 | "plt.scatter(x, y)\n", 71 | "\n", 72 | "plt.subplot(2,2,2)\n", 73 | "y_logit = np.log(y / (1 - y))\n", 74 | "regressor = LinearRegression().fit(x.reshape(-1, 1), y_logit.reshape(-1, 1))\n", 75 | "y_predicted = regressor.predict(x.reshape(-1, 1))\n", 76 | "plt.title('2. Transforming the points into logits with $\\\\ln{\\\\left(\\\\frac{x}{1-x}\\\\right)}$\\nyields a more or less straight line.\\nA linear regression model can be fit to this data.', fontsize=12)\n", 77 | "plt.scatter(x, y_logit)\n", 78 | "plt.plot(x, y_predicted, color='red')\n", 79 | "\n", 80 | "plt.subplot(2,2,3)\n", 81 | "plt.title('3. The regression line can be transformed back to\\nthe original domain using sigmoid function $\\\\frac{1}{1+e^{-x}}$', fontsize=12)\n", 82 | "x_new = np.linspace(0,1,100)\n", 83 | "y_new = regressor.predict(x_new.reshape(-1, 1))\n", 84 | "y_new_sigmoid = 1 / (1 + np.exp(-y_new))\n", 85 | "plt.scatter(x, y)\n", 86 | "plt.plot(x_new, y_new_sigmoid, color='red')\n", 87 | "plt.savefig('sigmoid-regression.svg', bbox_inches='tight')\n", 88 | "plt.show()" 89 | ] 90 | } 91 | ], 92 | "metadata": { 93 | "kernelspec": { 94 | "display_name": "Python [conda env:calibration]", 95 | "language": "python", 96 | "name": "conda-env-calibration-py" 97 | }, 98 | "language_info": { 99 | "codemirror_mode": { 100 | "name": "ipython", 101 | "version": 3 102 | }, 103 | "file_extension": ".py", 104 | "mimetype": "text/x-python", 105 | "name": "python", 106 | "nbconvert_exporter": "python", 107 | "pygments_lexer": "ipython3", 108 | "version": "3.8.11" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 5 113 | } 114 | -------------------------------------------------------------------------------- /calibration.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.isotonic import IsotonicRegression 3 | from sklearn.linear_model import LinearRegression 4 | 5 | 6 | class SigmoidCalibrator: 7 | def __init__(self, prob_pred, prob_true): 8 | prob_pred, prob_true = self._filter_out_of_domain(prob_pred, prob_true) 9 | prob_true = np.log(prob_true / (1 - prob_true)) 10 | self.regressor = LinearRegression().fit( 11 | prob_pred.reshape(-1, 1), prob_true.reshape(-1, 1) 12 | ) 13 | 14 | def calibrate(self, probabilities): 15 | return 1 / (1 + np.exp(-self.regressor.predict(probabilities.reshape(-1, 1)).flatten())) 16 | 17 | def _filter_out_of_domain(self, prob_pred, prob_true): 18 | filtered = list(zip(*[p for p in zip(prob_pred, prob_true) if 0 < p[1] < 1])) 19 | return np.array(filtered) 20 | 21 | 22 | class IsotonicCalibrator: 23 | def __init__(self, prob_pred, prob_true): 24 | self.regressor = IsotonicRegression(out_of_bounds="clip") 25 | self.regressor.fit(prob_pred, prob_true) 26 | 27 | def calibrate(self, probabilities): 28 | return self.regressor.predict(probabilities) -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | import h2o 2 | import numpy as np 3 | import pandas as pd 4 | from h2o.estimators import H2OEstimator as H2OClassifier 5 | from sklearn.base import ClassifierMixin as ScikitClassifier 6 | from sklearn.calibration import calibration_curve 7 | from tensorflow.keras import Model as KerasBaseModel 8 | 9 | from calibration import IsotonicCalibrator, SigmoidCalibrator 10 | 11 | 12 | class CalibratableModelFactory: 13 | def get_model(self, base_model): 14 | if isinstance(base_model, H2OClassifier): 15 | return H2OModel(base_model) 16 | elif isinstance(base_model, ScikitClassifier): 17 | return ScikitModel(base_model) 18 | elif isinstance(base_model, KerasBaseModel): 19 | return KerasModel(base_model) 20 | raise ValueError("Unsupported model passed as an argument") 21 | 22 | 23 | class CalibratableModelMixin: 24 | def __init__(self, model): 25 | self.model = model 26 | self.name = model.__class__.__name__ 27 | self.sigmoid_calibrator = None 28 | self.isotonic_calibrator = None 29 | self.calibrators = { 30 | "sigmoid": None, 31 | "isotonic": None, 32 | } 33 | 34 | def calibrate(self, X, y): 35 | predictions = self.predict(X) 36 | prob_true, prob_pred = calibration_curve(y, predictions, n_bins=10) 37 | self.calibrators["sigmoid"] = SigmoidCalibrator(prob_pred, prob_true) 38 | self.calibrators["isotonic"] = IsotonicCalibrator(prob_pred, prob_true) 39 | 40 | def calibrate_probabilities(self, probabilities, method="isotonic"): 41 | if method not in self.calibrators: 42 | raise ValueError("Method has to be either 'sigmoid' or 'isotonic'") 43 | if self.calibrators[method] is None: 44 | raise ValueError("Fit the calibrators first") 45 | return self.calibrators[method].calibrate(probabilities) 46 | 47 | def predict_calibrated(self, X, method="isotonic"): 48 | return self.calibrate_probabilities(self.predict(X), method) 49 | 50 | def score(self, X, y): 51 | return self._get_accuracy(y, self.predict(X)) 52 | 53 | def score_calibrated(self, X, y, method="isotonic"): 54 | return self._get_accuracy(y, self.predict_calibrated(X, method)) 55 | 56 | def _get_accuracy(self, y, preds): 57 | return np.mean(np.equal(y.astype(np.bool), preds >= 0.5)) 58 | 59 | 60 | class H2OModel(CalibratableModelMixin): 61 | def train(self, X, y): 62 | self.features = list(range(len(X[0]))) 63 | self.target = "target" 64 | train_frame = self._to_h2o_frame(X, y) 65 | self.model.train(x=self.features, y=self.target, training_frame=train_frame) 66 | 67 | def predict(self, X): 68 | predict_frame = self._to_h2o_frame(X) 69 | return self.model.predict(predict_frame).as_data_frame()["p1"].to_numpy() 70 | 71 | def _to_h2o_frame(self, X, y=None): 72 | df = pd.DataFrame(data=X, columns=self.features) 73 | if y is not None: 74 | df[self.target] = y 75 | h2o_frame = h2o.H2OFrame(df) 76 | if y is not None: 77 | h2o_frame[self.target] = h2o_frame[self.target].asfactor() 78 | return h2o_frame 79 | 80 | 81 | class ScikitModel(CalibratableModelMixin): 82 | def train(self, X, y): 83 | self.model.fit(X, y) 84 | 85 | def predict(self, X): 86 | return self.model.predict_proba(X)[:, 1] 87 | 88 | 89 | class KerasModel(CalibratableModelMixin): 90 | def train(self, X, y): 91 | self.model.fit(X, y, batch_size=128, epochs=10, verbose=0) 92 | 93 | def predict(self, X): 94 | return self.model.predict(X).flatten() 95 | -------------------------------------------------------------------------------- /plotting.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from sklearn.calibration import calibration_curve 4 | from sklearn.metrics import brier_score_loss 5 | 6 | 7 | def plot_sample(X, title=None, size=8): 8 | fig = plt.figure() 9 | st = fig.suptitle(title) 10 | for i, im in enumerate(np.random.permutation(X)[:size]): 11 | fig.add_subplot(1, size, i + 1) 12 | plt.axis("off") 13 | plt.imshow(im.reshape(28, 28), cmap="gray") 14 | fig.tight_layout() 15 | st.set_y(0.59) 16 | 17 | 18 | def plot_sample_predictions(models, X, X_unscaled, size=8): 19 | indexes = np.random.permutation(len(X))[:size] 20 | fig = plt.figure(figsize=(6, len(models) * 1.6), constrained_layout=True) 21 | subfigs = fig.subfigures(len(models)) 22 | for j, model in enumerate(models): 23 | subfig = subfigs.flat[j] 24 | subfig.suptitle(model.name) 25 | for i, idx in enumerate(indexes): 26 | prediction = model.predict(np.array([X[idx]]))[0] 27 | subfig.add_subplot(1, size, i + 1) 28 | plt.axis("off") 29 | plt.title(f"{round(100*prediction,2)}%", fontsize=10) 30 | plt.imshow(X_unscaled[idx].reshape(28, 28), cmap="gray") 31 | 32 | 33 | def plot_calibration_curve(y, probs, title): 34 | brier_score = brier_score_loss(y, probs) 35 | prob_true, prob_pred = calibration_curve(y, probs, n_bins=10) 36 | plt.plot([0, 1], [0, 1], linestyle="--") 37 | plt.plot( 38 | prob_pred, 39 | prob_true, 40 | marker=".", 41 | color="orange", 42 | ) 43 | plt.title(f"{title}\nBrier score: {round(brier_score, 3)}") 44 | plt.ylabel("Fraction of positives") 45 | plt.xlabel("Mean predicted value") 46 | return prob_true, prob_pred 47 | 48 | 49 | def plot_fitted_calibrator(prob_true, prob_pred, prob_calibrated, title=None): 50 | plt.plot([0, 1], [0, 1], linestyle="--") 51 | plt.plot(prob_pred, prob_true, marker=".", color="orange") 52 | plt.plot(prob_pred, prob_calibrated, color="red") 53 | plt.title(title) 54 | plt.ylabel("Fraction of positives") 55 | plt.xlabel("Mean predicted value") 56 | 57 | 58 | def plot_calibration_details_for_models( 59 | models, X, y, calibrated=False, method="isotonic" 60 | ): 61 | plt.figure(figsize=(10, 10)) 62 | ax1 = plt.subplot2grid((3, 1), (0, 0), rowspan=2) 63 | ax2 = plt.subplot2grid((3, 1), (2, 0)) 64 | ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated") 65 | for model in models: 66 | name = model.name 67 | probabilities = ( 68 | model.predict(X) 69 | if not calibrated 70 | else model.predict_calibrated(X, method=method) 71 | ) 72 | prob_true, prob_pred = calibration_curve(y, probabilities, n_bins=10) 73 | brier_score = brier_score_loss(y, probabilities) 74 | 75 | ax1.plot( 76 | prob_pred, 77 | prob_true, 78 | marker=".", 79 | label=f"{name} (BS={round(brier_score, 3)})", 80 | ) 81 | 82 | ax2.hist( 83 | probabilities, range=(0, 1), bins=10, label=name, histtype="step", lw=2 84 | ) 85 | 86 | ax1.set_ylabel("Fraction of positives") 87 | ax1.set_ylim([-0.05, 1.05]) 88 | ax1.legend(loc="upper left") 89 | ax1.set_title("Calibration plots") 90 | 91 | ax2.set_xlabel("Mean predicted value") 92 | ax2.set_ylabel("Count") 93 | ax2.legend(loc="upper center", ncol=2) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.14.0 2 | argon2-cffi==20.1.0 3 | astunparse==1.6.3 4 | async-generator==1.10 5 | attrs==21.2.0 6 | backcall==0.2.0 7 | bleach==4.0.0 8 | cachetools==4.2.2 9 | certifi==2021.5.30 10 | cffi==1.14.6 11 | charset-normalizer==2.0.6 12 | clang==5.0 13 | colorama==0.4.4 14 | cycler==0.10.0 15 | debugpy==1.4.1 16 | decorator==5.0.9 17 | defusedxml==0.7.1 18 | entrypoints==0.3 19 | flatbuffers==1.12 20 | future==0.18.2 21 | gast==0.4.0 22 | google-auth==1.35.0 23 | google-auth-oauthlib==0.4.6 24 | google-pasta==0.2.0 25 | grpcio==1.40.0 26 | h2o==3.34.0.1 27 | h5py==3.1.0 28 | idna==3.2 29 | importlib-metadata==4.8.1 30 | ipykernel==6.2.0 31 | ipython==7.27.0 32 | ipython-genutils==0.2.0 33 | jedi==0.18.0 34 | Jinja2==3.0.1 35 | joblib==1.0.1 36 | jsonschema==3.2.0 37 | jupyter-client==7.0.1 38 | jupyter-core==4.7.1 39 | jupyterlab-pygments==0.1.2 40 | keras==2.6.0 41 | Keras-Preprocessing==1.1.2 42 | kiwisolver==1.3.2 43 | Markdown==3.3.4 44 | MarkupSafe==2.0.1 45 | matplotlib==3.4.3 46 | matplotlib-inline==0.1.2 47 | mistune==0.8.4 48 | nb-conda==2.2.1 49 | nb-conda-kernels==2.3.1 50 | nbclient==0.5.3 51 | nbconvert==6.1.0 52 | nbformat==5.1.3 53 | nest-asyncio==1.5.1 54 | notebook==6.4.3 55 | numpy==1.19.5 56 | oauthlib==3.1.1 57 | opt-einsum==3.3.0 58 | packaging==21.0 59 | pandas==1.3.3 60 | pandocfilters==1.4.3 61 | parso==0.8.2 62 | pickleshare==0.7.5 63 | Pillow==8.3.2 64 | pip==21.0.1 65 | prometheus-client==0.11.0 66 | prompt-toolkit==3.0.17 67 | protobuf==3.18.0 68 | pyasn1==0.4.8 69 | pyasn1-modules==0.2.8 70 | pycparser==2.20 71 | Pygments==2.10.0 72 | pyparsing==2.4.7 73 | pyrsistent==0.17.3 74 | python-dateutil==2.8.2 75 | pytz==2021.1 76 | pywin32==228 77 | pywinpty==0.5.7 78 | pyzmq==22.2.1 79 | requests==2.26.0 80 | requests-oauthlib==1.3.0 81 | rsa==4.7.2 82 | scikit-learn==0.24.2 83 | scipy==1.7.1 84 | Send2Trash==1.5.0 85 | setuptools==58.0.4 86 | six==1.15.0 87 | sklearn==0.0 88 | tabulate==0.8.9 89 | tensorboard==2.6.0 90 | tensorboard-data-server==0.6.1 91 | tensorboard-plugin-wit==1.8.0 92 | tensorflow==2.6.0 93 | tensorflow-estimator==2.6.0 94 | termcolor==1.1.0 95 | terminado==0.9.4 96 | testpath==0.5.0 97 | threadpoolctl==2.2.0 98 | tornado==6.1 99 | traitlets==5.0.5 100 | typing-extensions==3.7.4.3 101 | urllib3==1.26.6 102 | wcwidth==0.2.5 103 | webencodings==0.5.1 104 | Werkzeug==2.0.1 105 | wheel==0.37.0 106 | wincertstore==0.2 107 | wrapt==1.12.1 108 | zipp==3.5.0 109 | --------------------------------------------------------------------------------