{ "cells": [ { "cell_type": "markdown", "id": "62e70a2a", "metadata": {}, "source": [ "# Data\n", "\n", "For the illustration of the group fairness metrics in TrustyAI, two synthetic datasets were created with the same input features and outcome types. \n", "The outcome is whether a certain invidual reaches a 50k income threshold by using age, race and gender as categorical inputs and both datasets consist of $N=10000$ data points.\n", "The gender values are allocated with a proportion of 20% to `gender=0` and 80% to `gender=1`.\n", "\n", "Both datasets have an increasing likelihood (with uniform probability) of having a positive outcome with age, regardless of race or gender.\n", "The first dataset, deemed _unbiased_, simply allocates the income value with an uniform random value, regardless of race or gender.\n", "The second dataset, deemed _biased_, allocates a positive outcome to `gender=0` with a lower probability than `gender=1`." ] }, { "cell_type": "code", "execution_count": 1, "id": "6de2a925", "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 2, "id": "98cd9647", "metadata": {}, "outputs": [], "source": [ "df = pd.read_csv(\"data/income-unbiased.zip\", index_col=False)" ] }, { "cell_type": "code", "execution_count": 3, "id": "be16cc2e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ageracegenderincome
013000
165701
271610
338111
442001
...............
999520510
999634210
999725211
999873511
999958311
\n", "

10000 rows × 4 columns

\n", "
" ], "text/plain": [ " age race gender income\n", "0 13 0 0 0\n", "1 65 7 0 1\n", "2 71 6 1 0\n", "3 38 1 1 1\n", "4 42 0 0 1\n", "... ... ... ... ...\n", "9995 20 5 1 0\n", "9996 34 2 1 0\n", "9997 25 2 1 1\n", "9998 73 5 1 1\n", "9999 58 3 1 1\n", "\n", "[10000 rows x 4 columns]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "id": "20e2a6d7", "metadata": {}, "source": [ "# Demographic Parity\n", "\n", "\n", "_Demographic Parity_ provides a measure of imbalances in positive and negative outcomes between priveleged and unprivileged groups.\n", "\n", "Taking the previous data as an example, we would use Demographic Parity metrics to measure if (for instance), the `income` is predicted to be above or below $50k regardless of race or gender.\n", "\n", "\n", "## Statistical Parity Difference\n", "\n", "The _Statistical Parity Difference (SPD)_ is the difference in the probability of prediction between the privileged and unprivileged groups. Typically:\n", "\n", "- $SPD=0$ means that the model is behaving fairly in regards of the selected attribute (e.g. race, gender)\n", "- Values between $-0.1" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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bxowYIDatm2ryy+/XHPnztXp06eb54fy/3EGBgAMctnDhaGeQkj8c0F6qKfQIixevFjz58/XI488or/85S964IEHdMMNN6hnz546duyYbrjhBnXt2lWrV6+Wy+XSBx98oLq6OknSG2+8oalTp+qpp55Samqq1qxZowkTJqhbt24aNmyYtY/58+dryZIlWrJkiWbNmqW77rpLl19+uXJzc9W9e3dNnDhRWVlZWrt2rSTpvffe0/jx47V8+XJdf/31+uKLL6zvLZwzZ06z/SwIGAAADHHLLbfot7/9rSRp1qxZWrp0qd5991317NlTq1at0uHDh7Vz507rracePXpYr120aJHuvfde6/U5OTnatm2bFi1aFBQwEyZM0B133GHtw+12W1/MLElTp07VhAkTrPFz587Vww8/bN3Q9vLLL9f8+fM1c+bMZg0Y3kICAMAQffv2tf45LCws6OawpaWl6t+//w9eN/Ppp5/q2muvDVp27bXX6tNPP/3BfdR/jU+fPn2Clp06dUp+v1+S9OGHH2revHnq0KGD9Zg8ebIOHTqkEydOnMPRnh1nYAAAMERkZGTQ87CwMOstovrvGDqf+6i/Y25Dy+r3e+zYMc2dO1e33XbbGdtq6JNV5wtnYAAAaAX69u2r0tJSHTlypMH1vXv31pYtW4KWbdmy5YyvCGqsAQMGaO/everRo8cZj/Dw5ssMzsAAANAKjB07Vk888YRGjRqlvLw8xcfH6+9//7sSEhLkdrs1Y8YM3XHHHerfv79SU1P11ltv6a9//aveeeedc9rv7NmzNXLkSHXv3l233367wsPD9eGHH+rjjz/W448/fp6O7kycgQEAoBWIiorS22+/rbi4ON1yyy3q06ePFixYYH3b86hRo7Rs2TItWrRIV155pZ599lm9+OKLGjp06DntNy0tTWvWrNHbb7+tn//85xo8eLCWLl1qfU9ic+FOvABgED5G3br82J14W6vzcSdezsAAAADjEDAAAMA4BAwAADAOAQMAAIxDwAAAAOMQMAAAwDgEDAAAMA4BAwAAjEPAAAAA4/BdSAAAtFAX+s7LTb3j8YoVK/Tkk0/K6/WqX79++v3vf69rrrnmPM8uGGdgAABAk7366qvKycnRnDlz9MEHH6hfv35KS0tTRUVFs+6XgAEAAE22ZMkSTZ48WRMmTFBycrLy8/MVHR2tF154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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nobias.groupby(['gender', 'income'])['income'].count().unstack().plot.bar()" ] }, { "cell_type": "code", "execution_count": 7, "id": "2b2c678a", "metadata": {}, "outputs": [], "source": [ "from trustyai.metrics.fairness.group import statistical_parity_difference\n", "from trustyai.model import output\n", "\n", "nobias_privileged = nobias[nobias.gender == 1]\n", "nobias_unprivileged = nobias[nobias.gender == 0]\n", "favorable = output(\"income\", dtype=\"number\", value=1)\n", "score = statistical_parity_difference(privileged=nobias_privileged,\n", " unprivileged=nobias_unprivileged,\n", " favorable=[favorable])" ] }, { "cell_type": "code", "execution_count": 8, "id": "9e548018", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.0036255104824703954\n" ] } ], "source": [ "print(score)" ] }, { "cell_type": "markdown", "id": "a13a2ac3", "metadata": {}, "source": [ "We can see that the $SPD$ for this dataset is between the $[-0.1, 0.1]$ threshold, which classifies the model as _reasonably fair_." ] }, { "cell_type": "markdown", "id": "09bb7d45", "metadata": {}, "source": [ "### Biased dataset" ] }, { "cell_type": "code", "execution_count": 9, "id": "63b953c9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "gender income\n", "0 0 1772\n", " 1 242\n", "1 0 5775\n", " 1 2211\n", "Name: income, dtype: int64" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bias = pd.read_csv(\"data/income-biased.zip\", index_col=False)\n", "bias.groupby(['gender', 'income'])['income'].count()" ] }, { "cell_type": "code", "execution_count": 10, "id": "aed61b77", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGtCAYAAAAI4U5vAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAshklEQVR4nO3de1xVdb7/8TegbEXdm1BhY2rSWCrlBXDSneVoMpKD55GTTWVOOmo5erCTkJc4x7G0TngsNZ00uuPM5OlyTjUpDzUHUyvJC4V5KapJD5Ru0Iy9vQLC+v3Rj/Vwl5mguPni6/l4rMfDvb6ftdZnORLv+e51CbEsyxIAAIBBQoPdAAAAQF0RYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4zQLdgMNpaamRvv371ebNm0UEhIS7HYAAMA5sCxLR44cUYcOHRQaepZ5FquOvv76a2v06NFWVFSU1aJFC+vaa6+1tm3bZo/X1NRYf/rTnyy32221aNHCGjJkiPX5558H7OPbb7+17rrrLqtNmzaWy+Wyxo8fbx05ciSgZseOHdYNN9xgORwOq2PHjtZ//dd/1anPkpISSxILCwsLCwuLgUtJSclZf8/XaQbmu+++04ABAzR48GCtXr1a7du31xdffKHLLrvMrpk/f76WLFmi5cuXKy4uTn/605+UkpKiPXv2qEWLFpKk0aNH68CBA1q3bp2qqqo0btw4TZw4UStWrJAk+f1+DR06VMnJycrOztbOnTs1fvx4RUZGauLEiefUa5s2bSRJJSUlcjqddTlNAAAQJH6/X506dbJ/j/+kusxqzJw507rhhht+crympsZyu93W448/bq8rLy+3HA6H9d///d+WZVnWnj17LEkBszarV6+2QkJCrG+++cayLMtatmyZddlll1kVFRUBx+7Wrds59+rz+SxJls/nO+dtAABAcJ3r7+86XcT79ttvq2/fvvrd736n6OhoJSQk6LnnnrPH9+7dK6/Xq+TkZHudy+VSv379lJ+fL0nKz89XZGSk+vbta9ckJycrNDRUW7ZssWsGDhyo8PBwuyYlJUVFRUX67rvvzthbRUWF/H5/wAIAAJqmOgWYr776Sk8//bSuuuoqrV27VpMnT9a//du/afny5ZIkr9crSYqJiQnYLiYmxh7zer2Kjo4OGG/WrJmioqICas60j9OP8UNZWVlyuVz20qlTp7qcGgAAMEidAkxNTY0SExP12GOPKSEhQRMnTtS9996r7OzshurvnGVmZsrn89lLSUlJsFsCAAANpE4X8cbGxio+Pj5gXY8ePfS///u/kiS32y1JKi0tVWxsrF1TWlqqPn362DVlZWUB+zh16pQOHz5sb+92u1VaWhpQU/u5tuaHHA6HHA5HXU4HAIBGo7q6WlVVVcFuo8E1b95cYWFh572fOgWYAQMGqKioKGDd559/riuuuEKSFBcXJ7fbrby8PDuw+P1+bdmyRZMnT5YkeTwelZeXq6CgQElJSZKk9evXq6amRv369bNr/uM//kNVVVVq3ry5JGndunXq1q1bwB1PAACYzrIseb1elZeXB7uViyYyMlJut/u8ntNWpwCTnp6u66+/Xo899phuv/12bd26Vc8++6yeffZZSVJISIimTp2qRx99VFdddZV9G3WHDh00YsQISd/P2Nx88832V09VVVWaMmWK7rzzTnXo0EGSdNddd2nOnDmaMGGCZs6cqV27dmnx4sVatGhRvU8UAIDGqDa8REdHKyIiokk/fNWyLB0/ftz+Jub0b2vqs7M6WblypXXttddaDofD6t69u/Xss88GjNc+yC4mJsZyOBzWkCFDrKKiooCab7/91ho1apTVunVry+l0WuPGjTvrg+wuv/xya968eXXqk9uoAQCN3alTp6w9e/ZYhw4dCnYrF9WhQ4esPXv2WKdOnfrR2Ln+/g6xLMu6ILGqkfH7/XK5XPL5fDzIDgDQKJ08eVJ79+5Vly5d1LJly2C3c9GcOHFC+/btU1xcnP2Q21rn+vublzkCABBkTflrozO5EOdLgAEAAMYhwAAA0EgNGjRIU6dODXYbjVKd7kICAAAXzxtvvGE/TgSBCDAAADRSUVFRwW6h0eIrJAAAGqnTv0Lq0qWLHnvsMY0fP15t2rRR586d7eew1fr66681atQoRUVFqVWrVurbt6/9omRJevrpp/WLX/xC4eHh6tatm/76178GbB8SEqJnnnlGw4cPV0REhHr06KH8/Hx9+eWXGjRokFq1aqXrr79e//znPwO2+/vf/67ExES1aNFCV155pebMmaNTp041zF/K/0eAAQDAEAsWLFDfvn318ccf61//9V81efJk+wn5R48e1a9+9St98803evvtt7Vjxw7NmDFDNTU1kqQ333xT999/vx544AHt2rVLf/zjHzVu3Di9++67Acd45JFHNGbMGBUWFqp79+6666679Mc//lGZmZnavn27LMvSlClT7Pr33ntPY8aM0f333689e/bomWeeUU5Ojv7zP/+zQf8ueA4MABiky4O5wW4hKPbNSw12Cw2i9jkwZ3oeivT9DEyfPn305JNPqkuXLrrxxhvtWRPLsuR2uzVnzhxNmjRJzz77rKZNm6Z9+/ad8aunAQMG6JprrgmYtbn99tt17Ngx5eZ+/+8qJCREs2bN0iOPPCJJ+vDDD+XxePTCCy9o/PjxkqRXXnlF48aN04kTJyRJycnJGjJkiDIzM+39/u1vf9OMGTO0f//+Op83z4EBAKCJ6dWrl/3nkJCQgBckFxYWKiEh4Sevm/n00081YMCAgHUDBgzQp59++pPHiImJkST17NkzYN3Jkyfl9/slSTt27NDcuXPVunVre7n33nt14MABHT9+/DzO9uy4iBcAAEP88I6kkJAQ+yuiC/Uk39OPUfvAuTOtqz3u0aNHNWfOHN16660/2teZZpUuFGZgAABoAnr16qXCwkIdPnz4jOM9evTQBx98ELDugw8+UHx8/HkdNzExUUVFRerateuPltDQhosZzMAAANAEjBo1So899phGjBihrKwsxcbG6uOPP1aHDh3k8Xg0ffp03X777UpISFBycrJWrlypN954Q//4xz/O67izZ8/W8OHD1blzZ912220KDQ3Vjh07tGvXLj366KMX6Ox+jBkYAACagPDwcL3zzjuKjo7Wb37zG/Xs2VPz5s1TWFiYJGnEiBFavHixnnjiCV1zzTV65pln9NJLL2nQoEHnddyUlBStWrVK77zzjn75y1+qf//+WrRoka644ooLcFY/jbuQAMAg3IXUtPzcXUhNFXchAQCASxIBBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYh5c5AgDQSF3sV0fU95UNS5cu1eOPPy6v16vevXvrz3/+s6677roL3F0gZmAAAEC9vfrqq8rIyNBDDz2kjz76SL1791ZKSorKysoa9LgEGAAAUG8LFy7Uvffeq3Hjxik+Pl7Z2dmKiIjQiy++2KDHJcAAAIB6qaysVEFBgZKTk+11oaGhSk5OVn5+foMemwADAADq5dChQ6qurlZMTEzA+piYGHm93gY9NgEGAAAYhwADAADqpV27dgoLC1NpaWnA+tLSUrnd7gY9NgEGAADUS3h4uJKSkpSXl2evq6mpUV5enjweT4Mem+fAAACAesvIyNDYsWPVt29fXXfddXryySd17NgxjRs3rkGPS4ABAAD1dscdd+jgwYOaPXu2vF6v+vTpozVr1vzowt4LjQADAEAjVd8n415sU6ZM0ZQpUy7qMbkGBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMw6sEAABorB52XeTj+eq8yaZNm/T444+roKBABw4c0JtvvqkRI0Zc+N5+gBkYAABQb8eOHVPv3r21dOnSi3pcZmAAAEC9DRs2TMOGDbvox2UGBgAAGIcAAwAAjFOnAPPwww8rJCQkYOnevbs9fvLkSaWlpalt27Zq3bq1Ro4cqdLS0oB9FBcXKzU1VREREYqOjtb06dN16tSpgJoNGzYoMTFRDodDXbt2VU5OTv3PEAAANDl1noG55pprdODAAXt5//337bH09HStXLlSr7/+ujZu3Kj9+/fr1ltvtcerq6uVmpqqyspKbd68WcuXL1dOTo5mz55t1+zdu1epqakaPHiwCgsLNXXqVN1zzz1au3bteZ4qAABoKup8EW+zZs3kdrt/tN7n8+mFF17QihUrdNNNN0mSXnrpJfXo0UMffvih+vfvr3feeUd79uzRP/7xD8XExKhPnz565JFHNHPmTD388MMKDw9Xdna24uLitGDBAklSjx499P7772vRokVKSUk5z9MFAABNQZ1nYL744gt16NBBV155pUaPHq3i4mJJUkFBgaqqqpScnGzXdu/eXZ07d1Z+fr4kKT8/Xz179lRMTIxdk5KSIr/fr927d9s1p++jtqZ2Hz+loqJCfr8/YAEAAA3r6NGjKiwsVGFhoaTvv0kpLCy080FDqVOA6devn3JycrRmzRo9/fTT2rt3r2688UYdOXJEXq9X4eHhioyMDNgmJiZGXq9XkuT1egPCS+147djZavx+v06cOPGTvWVlZcnlctlLp06d6nJqAACgHrZv366EhAQlJCRIkjIyMpSQkBBweUhDqNNXSKff592rVy/169dPV1xxhV577TW1bNnygjdXF5mZmcrIyLA/+/1+QgwAwGz1eDLu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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "bias.groupby(['gender', 'income'])['income'].count().unstack().plot.bar()" ] }, { "cell_type": "code", "execution_count": 12, "id": "901e5720", "metadata": {}, "outputs": [], "source": [ "bias_privileged = bias[bias.gender == 1]\n", "bias_unprivileged = bias[bias.gender == 0]\n", "\n", "score = statistical_parity_difference(privileged=bias_privileged,\n", " unprivileged=bias_unprivileged,\n", " favorable=[favorable])" ] }, { "cell_type": "code", "execution_count": 13, "id": "7be544a7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.15670061634672994\n" ] } ], "source": [ "print(score)" ] }, { "cell_type": "markdown", "id": "8e3f2bd4", "metadata": {}, "source": [ "This dataset, as expected, is outside the $[-0.1, 0.1]$ threshold, which classifies the model as _unfair_.\n", "In addiction, the negative score indicates that the unprivileged group (in our example, `gender = 0`) is the one in disadvantage for this particular outcome." ] }, { "cell_type": "markdown", "id": "de0affcf", "metadata": {}, "source": [ "## Disparate impact ratio\n", "\n", "\n", "Similarly to the _Statistical Parity Difference_, the _Disparate Impact Ratio (DIR)_ measures imbalances in positive outcome predictions across privliged and unpriviliged groups.\n", "Instead of calculating the difference, this metric calculates the ration of such selection rates.Typically:\n", "\n", "- $DIR=1$ means that the model is fair with regards to the protected attribute.\n", "- $0.8 22\u001b[0m xgb \u001b[39m=\u001b[39m train(\u001b[39m\"\u001b[39;49m\u001b[39mdata/income-biased.zip\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n", "Cell \u001b[0;32mIn[48], line 19\u001b[0m, in \u001b[0;36mtrain\u001b[0;34m(dataset)\u001b[0m\n\u001b[1;32m 13\u001b[0m _y \u001b[39m=\u001b[39m df\u001b[39m.\u001b[39mincome\n\u001b[1;32m 15\u001b[0m clf \u001b[39m=\u001b[39m XGBClassifier(objective\u001b[39m=\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mbinary:logistic\u001b[39m\u001b[39m\"\u001b[39m, \n\u001b[1;32m 16\u001b[0m enable_categorical\u001b[39m=\u001b[39m\u001b[39mTrue\u001b[39;00m, \n\u001b[1;32m 17\u001b[0m use_label_encoder\u001b[39m=\u001b[39m\u001b[39mFalse\u001b[39;00m,\n\u001b[1;32m 18\u001b[0m eval_metric\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39mlogloss\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m---> 19\u001b[0m clf\u001b[39m.\u001b[39;49mfit(_X, _y)\n\u001b[1;32m 20\u001b[0m \u001b[39mreturn\u001b[39;00m clf\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/core.py:436\u001b[0m, in \u001b[0;36m_deprecate_positional_args..inner_f\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 434\u001b[0m \u001b[39mfor\u001b[39;00m k, arg \u001b[39min\u001b[39;00m \u001b[39mzip\u001b[39m(sig\u001b[39m.\u001b[39mparameters, args):\n\u001b[1;32m 435\u001b[0m kwargs[k] \u001b[39m=\u001b[39m arg\n\u001b[0;32m--> 436\u001b[0m \u001b[39mreturn\u001b[39;00m f(\u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/sklearn.py:1158\u001b[0m, in \u001b[0;36mXGBClassifier.fit\u001b[0;34m(self, X, y, sample_weight, base_margin, eval_set, eval_metric, early_stopping_rounds, verbose, xgb_model, sample_weight_eval_set, base_margin_eval_set, feature_weights, callbacks)\u001b[0m\n\u001b[1;32m 1153\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mlen\u001b[39m(X\u001b[39m.\u001b[39mshape) \u001b[39m!=\u001b[39m \u001b[39m2\u001b[39m:\n\u001b[1;32m 1154\u001b[0m \u001b[39m# Simply raise an error here since there might be many\u001b[39;00m\n\u001b[1;32m 1155\u001b[0m \u001b[39m# different ways of reshaping\u001b[39;00m\n\u001b[1;32m 1156\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mPlease reshape the input data X into 2-dimensional matrix.\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m-> 1158\u001b[0m train_dmatrix, evals \u001b[39m=\u001b[39m _wrap_evaluation_matrices(\n\u001b[1;32m 1159\u001b[0m missing\u001b[39m=\u001b[39;49m\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mmissing,\n\u001b[1;32m 1160\u001b[0m X\u001b[39m=\u001b[39;49mX,\n\u001b[1;32m 1161\u001b[0m y\u001b[39m=\u001b[39;49my,\n\u001b[1;32m 1162\u001b[0m group\u001b[39m=\u001b[39;49m\u001b[39mNone\u001b[39;49;00m,\n\u001b[1;32m 1163\u001b[0m qid\u001b[39m=\u001b[39;49m\u001b[39mNone\u001b[39;49;00m,\n\u001b[1;32m 1164\u001b[0m sample_weight\u001b[39m=\u001b[39;49msample_weight,\n\u001b[1;32m 1165\u001b[0m base_margin\u001b[39m=\u001b[39;49mbase_margin,\n\u001b[1;32m 1166\u001b[0m feature_weights\u001b[39m=\u001b[39;49mfeature_weights,\n\u001b[1;32m 1167\u001b[0m eval_set\u001b[39m=\u001b[39;49meval_set,\n\u001b[1;32m 1168\u001b[0m sample_weight_eval_set\u001b[39m=\u001b[39;49msample_weight_eval_set,\n\u001b[1;32m 1169\u001b[0m base_margin_eval_set\u001b[39m=\u001b[39;49mbase_margin_eval_set,\n\u001b[1;32m 1170\u001b[0m eval_group\u001b[39m=\u001b[39;49m\u001b[39mNone\u001b[39;49;00m,\n\u001b[1;32m 1171\u001b[0m eval_qid\u001b[39m=\u001b[39;49m\u001b[39mNone\u001b[39;49;00m,\n\u001b[1;32m 1172\u001b[0m create_dmatrix\u001b[39m=\u001b[39;49m\u001b[39mlambda\u001b[39;49;00m \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs: DMatrix(nthread\u001b[39m=\u001b[39;49m\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mn_jobs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs),\n\u001b[1;32m 1173\u001b[0m label_transform\u001b[39m=\u001b[39;49mlabel_transform,\n\u001b[1;32m 1174\u001b[0m )\n\u001b[1;32m 1176\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_Booster \u001b[39m=\u001b[39m train(\n\u001b[1;32m 1177\u001b[0m params,\n\u001b[1;32m 1178\u001b[0m train_dmatrix,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1187\u001b[0m callbacks\u001b[39m=\u001b[39mcallbacks,\n\u001b[1;32m 1188\u001b[0m )\n\u001b[1;32m 1190\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m callable(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mobjective):\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/sklearn.py:236\u001b[0m, in \u001b[0;36m_wrap_evaluation_matrices\u001b[0;34m(missing, X, y, group, qid, sample_weight, base_margin, feature_weights, eval_set, sample_weight_eval_set, base_margin_eval_set, eval_group, eval_qid, create_dmatrix, label_transform)\u001b[0m\n\u001b[1;32m 216\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_wrap_evaluation_matrices\u001b[39m(\n\u001b[1;32m 217\u001b[0m missing: \u001b[39mfloat\u001b[39m,\n\u001b[1;32m 218\u001b[0m X: Any,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 231\u001b[0m label_transform: Callable \u001b[39m=\u001b[39m \u001b[39mlambda\u001b[39;00m x: x,\n\u001b[1;32m 232\u001b[0m ) \u001b[39m-\u001b[39m\u001b[39m>\u001b[39m Tuple[Any, Optional[List[Tuple[Any, \u001b[39mstr\u001b[39m]]]]:\n\u001b[1;32m 233\u001b[0m \u001b[39m \u001b[39m\u001b[39m\"\"\"Convert array_like evaluation matrices into DMatrix. Perform validation on the way.\u001b[39;00m\n\u001b[1;32m 234\u001b[0m \n\u001b[1;32m 235\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 236\u001b[0m train_dmatrix \u001b[39m=\u001b[39m create_dmatrix(\n\u001b[1;32m 237\u001b[0m data\u001b[39m=\u001b[39;49mX,\n\u001b[1;32m 238\u001b[0m label\u001b[39m=\u001b[39;49mlabel_transform(y),\n\u001b[1;32m 239\u001b[0m group\u001b[39m=\u001b[39;49mgroup,\n\u001b[1;32m 240\u001b[0m qid\u001b[39m=\u001b[39;49mqid,\n\u001b[1;32m 241\u001b[0m weight\u001b[39m=\u001b[39;49msample_weight,\n\u001b[1;32m 242\u001b[0m base_margin\u001b[39m=\u001b[39;49mbase_margin,\n\u001b[1;32m 243\u001b[0m feature_weights\u001b[39m=\u001b[39;49mfeature_weights,\n\u001b[1;32m 244\u001b[0m missing\u001b[39m=\u001b[39;49mmissing,\n\u001b[1;32m 245\u001b[0m )\n\u001b[1;32m 247\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mvalidate_or_none\u001b[39m(meta: Optional[List], name: \u001b[39mstr\u001b[39m) \u001b[39m-\u001b[39m\u001b[39m>\u001b[39m List:\n\u001b[1;32m 248\u001b[0m \u001b[39mif\u001b[39;00m meta \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/sklearn.py:1172\u001b[0m, in \u001b[0;36mXGBClassifier.fit..\u001b[0;34m(**kwargs)\u001b[0m\n\u001b[1;32m 1153\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mlen\u001b[39m(X\u001b[39m.\u001b[39mshape) \u001b[39m!=\u001b[39m \u001b[39m2\u001b[39m:\n\u001b[1;32m 1154\u001b[0m \u001b[39m# Simply raise an error here since there might be many\u001b[39;00m\n\u001b[1;32m 1155\u001b[0m \u001b[39m# different ways of reshaping\u001b[39;00m\n\u001b[1;32m 1156\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mPlease reshape the input data X into 2-dimensional matrix.\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[1;32m 1158\u001b[0m train_dmatrix, evals \u001b[39m=\u001b[39m _wrap_evaluation_matrices(\n\u001b[1;32m 1159\u001b[0m missing\u001b[39m=\u001b[39m\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mmissing,\n\u001b[1;32m 1160\u001b[0m X\u001b[39m=\u001b[39mX,\n\u001b[1;32m 1161\u001b[0m y\u001b[39m=\u001b[39my,\n\u001b[1;32m 1162\u001b[0m group\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m 1163\u001b[0m qid\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m 1164\u001b[0m sample_weight\u001b[39m=\u001b[39msample_weight,\n\u001b[1;32m 1165\u001b[0m base_margin\u001b[39m=\u001b[39mbase_margin,\n\u001b[1;32m 1166\u001b[0m feature_weights\u001b[39m=\u001b[39mfeature_weights,\n\u001b[1;32m 1167\u001b[0m eval_set\u001b[39m=\u001b[39meval_set,\n\u001b[1;32m 1168\u001b[0m sample_weight_eval_set\u001b[39m=\u001b[39msample_weight_eval_set,\n\u001b[1;32m 1169\u001b[0m base_margin_eval_set\u001b[39m=\u001b[39mbase_margin_eval_set,\n\u001b[1;32m 1170\u001b[0m eval_group\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m 1171\u001b[0m eval_qid\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[0;32m-> 1172\u001b[0m create_dmatrix\u001b[39m=\u001b[39m\u001b[39mlambda\u001b[39;00m \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mkwargs: DMatrix(nthread\u001b[39m=\u001b[39;49m\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mn_jobs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs),\n\u001b[1;32m 1173\u001b[0m label_transform\u001b[39m=\u001b[39mlabel_transform,\n\u001b[1;32m 1174\u001b[0m )\n\u001b[1;32m 1176\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_Booster \u001b[39m=\u001b[39m train(\n\u001b[1;32m 1177\u001b[0m params,\n\u001b[1;32m 1178\u001b[0m train_dmatrix,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1187\u001b[0m callbacks\u001b[39m=\u001b[39mcallbacks,\n\u001b[1;32m 1188\u001b[0m )\n\u001b[1;32m 1190\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m callable(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mobjective):\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/core.py:436\u001b[0m, in \u001b[0;36m_deprecate_positional_args..inner_f\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 434\u001b[0m \u001b[39mfor\u001b[39;00m k, arg \u001b[39min\u001b[39;00m \u001b[39mzip\u001b[39m(sig\u001b[39m.\u001b[39mparameters, args):\n\u001b[1;32m 435\u001b[0m kwargs[k] \u001b[39m=\u001b[39m arg\n\u001b[0;32m--> 436\u001b[0m \u001b[39mreturn\u001b[39;00m f(\u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/core.py:541\u001b[0m, in \u001b[0;36mDMatrix.__init__\u001b[0;34m(self, data, label, weight, base_margin, missing, silent, feature_names, feature_types, nthread, group, qid, label_lower_bound, label_upper_bound, feature_weights, enable_categorical)\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[39mreturn\u001b[39;00m\n\u001b[1;32m 539\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39m.\u001b[39;00m\u001b[39mdata\u001b[39;00m \u001b[39mimport\u001b[39;00m dispatch_data_backend\n\u001b[0;32m--> 541\u001b[0m handle, feature_names, feature_types \u001b[39m=\u001b[39m dispatch_data_backend(\n\u001b[1;32m 542\u001b[0m data,\n\u001b[1;32m 543\u001b[0m missing\u001b[39m=\u001b[39;49m\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mmissing,\n\u001b[1;32m 544\u001b[0m threads\u001b[39m=\u001b[39;49m\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mnthread,\n\u001b[1;32m 545\u001b[0m feature_names\u001b[39m=\u001b[39;49mfeature_names,\n\u001b[1;32m 546\u001b[0m feature_types\u001b[39m=\u001b[39;49mfeature_types,\n\u001b[1;32m 547\u001b[0m enable_categorical\u001b[39m=\u001b[39;49menable_categorical,\n\u001b[1;32m 548\u001b[0m )\n\u001b[1;32m 549\u001b[0m \u001b[39massert\u001b[39;00m handle \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m\n\u001b[1;32m 550\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mhandle \u001b[39m=\u001b[39m handle\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/data.py:573\u001b[0m, in \u001b[0;36mdispatch_data_backend\u001b[0;34m(data, missing, threads, feature_names, feature_types, enable_categorical)\u001b[0m\n\u001b[1;32m 571\u001b[0m \u001b[39mreturn\u001b[39;00m _from_tuple(data, missing, feature_names, feature_types)\n\u001b[1;32m 572\u001b[0m \u001b[39mif\u001b[39;00m _is_pandas_df(data):\n\u001b[0;32m--> 573\u001b[0m \u001b[39mreturn\u001b[39;00m _from_pandas_df(data, enable_categorical, missing, threads,\n\u001b[1;32m 574\u001b[0m feature_names, feature_types)\n\u001b[1;32m 575\u001b[0m \u001b[39mif\u001b[39;00m _is_pandas_series(data):\n\u001b[1;32m 576\u001b[0m \u001b[39mreturn\u001b[39;00m _from_pandas_series(data, missing, threads, feature_names,\n\u001b[1;32m 577\u001b[0m feature_types)\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/data.py:258\u001b[0m, in \u001b[0;36m_from_pandas_df\u001b[0;34m(data, enable_categorical, missing, nthread, feature_names, feature_types)\u001b[0m\n\u001b[1;32m 256\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_from_pandas_df\u001b[39m(data, enable_categorical, missing, nthread,\n\u001b[1;32m 257\u001b[0m feature_names, feature_types):\n\u001b[0;32m--> 258\u001b[0m data, feature_names, feature_types \u001b[39m=\u001b[39m _transform_pandas_df(\n\u001b[1;32m 259\u001b[0m data, enable_categorical, feature_names, feature_types)\n\u001b[1;32m 260\u001b[0m \u001b[39mreturn\u001b[39;00m _from_numpy_array(data, missing, nthread, feature_names,\n\u001b[1;32m 261\u001b[0m feature_types)\n", "File \u001b[0;32m~/.virtualenvs/trustyai-explainability-python-examples/lib/python3.10/site-packages/xgboost/data.py:223\u001b[0m, in \u001b[0;36m_transform_pandas_df\u001b[0;34m(data, enable_categorical, feature_names, feature_types, meta, meta_type)\u001b[0m\n\u001b[1;32m 215\u001b[0m bad_fields \u001b[39m=\u001b[39m [\n\u001b[1;32m 216\u001b[0m \u001b[39mstr\u001b[39m(data\u001b[39m.\u001b[39mcolumns[i]) \u001b[39mfor\u001b[39;00m i, dtype \u001b[39min\u001b[39;00m \u001b[39menumerate\u001b[39m(data_dtypes)\n\u001b[1;32m 217\u001b[0m \u001b[39mif\u001b[39;00m dtype\u001b[39m.\u001b[39mname \u001b[39mnot\u001b[39;00m \u001b[39min\u001b[39;00m _pandas_dtype_mapper\n\u001b[1;32m 218\u001b[0m ]\n\u001b[1;32m 220\u001b[0m msg \u001b[39m=\u001b[39m \u001b[39m\"\"\"\u001b[39m\u001b[39mDataFrame.dtypes for data must be int, float, bool or categorical. When\u001b[39m\n\u001b[1;32m 221\u001b[0m \u001b[39m categorical type is supplied, DMatrix parameter\u001b[39m\n\u001b[1;32m 222\u001b[0m \u001b[39m `enable_categorical` must be set to `True`.\u001b[39m\u001b[39m\"\"\"\u001b[39m\n\u001b[0;32m--> 223\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(msg \u001b[39m+\u001b[39m \u001b[39m'\u001b[39m\u001b[39m, \u001b[39m\u001b[39m'\u001b[39m\u001b[39m.\u001b[39mjoin(bad_fields))\n\u001b[1;32m 225\u001b[0m \u001b[39mif\u001b[39;00m feature_names \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m meta \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[1;32m 226\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(data\u001b[39m.\u001b[39mcolumns, MultiIndex):\n", "\u001b[0;31mValueError\u001b[0m: DataFrame.dtypes for data must be int, float, bool or categorical. When\n categorical type is supplied, DMatrix parameter\n `enable_categorical` must be set to `True`.race, gender" ] } ], "source": [ "from xgboost import XGBClassifier\n", "\n", "\n", "def train(dataset):\n", " df = pd.read_csv(dataset)\n", "\n", " categories = ['race', 'gender', 'income']\n", " for f in categories:\n", " df[f] = df[f].astype('category')\n", " df['age'] = df['age'].astype('int')\n", "\n", " _X = df[[\"age\", \"race\", \"gender\"]]\n", " _y = df.income\n", "\n", " clf = XGBClassifier(objective=\"binary:logistic\", \n", " enable_categorical=True, \n", " use_label_encoder=False,\n", " eval_metric='logloss')\n", " clf.fit(_X, _y)\n", " return clf\n", "\n", "xgb = train(\"data/income-biased.zip\")\n" ] }, { "cell_type": "code", "execution_count": 46, "id": "2b027d0b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.06288176602997649\n" ] } ], "source": [ "from trustyai.model import Model\n", "from trustyai.metrics.fairness.group import statistical_parity_difference_model\n", "\n", "X = nobias[[\"age\", \"race\", \"gender\"]]\n", "\n", "model = Model(xgb.predict, dataframe_input=True, output_names=[\"approved\"])\n", "score = statistical_parity_difference_model(samples=X,\n", " model=model,\n", " privilege_columns=[\"gender\"],\n", " privilege_values=[1],\n", " favorable=[favorable])\n", "print(score)" ] }, { "cell_type": "markdown", "id": "daa3794e", "metadata": {}, "source": [ "## Disparate impact ratio" ] }, { "cell_type": "code", "execution_count": 43, "id": "7df08157", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.03798125763334818\n" ] } ], "source": [ "from trustyai.metrics.fairness.group import disparate_impact_ratio_model\n", "\n", "score = disparate_impact_ratio_model(samples=X,\n", " model=model,\n", " privilege_columns=[\"gender\"],\n", " privilege_values=[1],\n", " favorable=[favorable])\n", "print(score)" ] }, { "cell_type": "markdown", "id": "52a499d3", "metadata": {}, "source": [ "## Average Odds Difference" ] }, { "cell_type": "code", "execution_count": 44, "id": "18061c05", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9.581224702515101e-14\n" ] } ], "source": [ "from trustyai.metrics.fairness.group import average_odds_difference_model\n", "\n", "score = average_odds_difference_model(samples=X,\n", " model=model,\n", " privilege_columns=[\"gender\"],\n", " privilege_values=[1],\n", " positive_class=[1])\n", "print(score)" ] }, { "cell_type": "code", "execution_count": null, "id": "ad3d2363", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "trustyai-explainability-python-examples", "language": "python", "name": "trustyai-explainability-python-examples" }, "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.10.8" } }, "nbformat": 4, "nbformat_minor": 5 }