{ "cells": [ { "cell_type": "markdown", "id": "1418169d-4f14-4da5-ac5a-6e8362b19415", "metadata": { "tags": [] }, "source": [ "# Examples\n", "\n", "(C) Henrik Boström, 2024" ] }, { "cell_type": "code", "execution_count": 1, "id": "0f815ada-b5c4-49bd-bc65-572942a8d7e4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "xrf v. 0.1.1\n" ] } ], "source": [ "import xrf\n", "print(f\"xrf v. {xrf.__version__}\")" ] }, { "cell_type": "markdown", "id": "d844b8ae-5ec0-4454-bbf5-8746f8a4977e", "metadata": {}, "source": [ "## Classification forests" ] }, { "cell_type": "markdown", "id": "a1ef59fd-2e04-4ccd-91fe-3c2bc2d1deff", "metadata": {}, "source": [ "### Tic-tac-toe" ] }, { "cell_type": "markdown", "id": "9f0eed6e-7c44-4fb8-a5cf-776d69d62c6e", "metadata": {}, "source": [ "Let us start by importing the tic-tac-toe dataset from [openml.org](https://www.openml.org)." ] }, { "cell_type": "code", "execution_count": 2, "id": "5ab5510b-06b6-4fc7-bf57-878e5c68be31", "metadata": {}, "outputs": [], "source": [ "from sklearn.datasets import fetch_openml\n", "from sklearn.preprocessing import OneHotEncoder\n", "\n", "dataset = fetch_openml(name=\"tic-tac-toe\", parser=\"auto\")\n", "\n", "y = dataset.target.values\n", "\n", "X_orig = dataset.data.values\n", "X = OneHotEncoder().fit_transform(X_orig).toarray()" ] }, { "cell_type": "markdown", "id": "410d85d3-2967-4566-9136-eeba09ed71d7", "metadata": {}, "source": [ "Let us split the dataset into a training and a test set." ] }, { "cell_type": "code", "execution_count": 3, "id": "74133e0f-7588-42b8-a643-62183d19fe2a", "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "X_train, X_test, y_train, y_test, X_orig_train, X_orig_test = train_test_split(\n", " X, y, X_orig, test_size=0.75)" ] }, { "cell_type": "markdown", "id": "9a50ffb7-d2d7-4ca1-8e32-08f7d8b3d287", "metadata": {}, "source": [ "Let us first generate a standard random forest classifier and apply it to the test set." ] }, { "cell_type": "code", "execution_count": 4, "id": "17dc69dc-4b2f-4861-9649-ea6221cbc4bc", "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestClassifier\n", "import numpy as np\n", "\n", "np.random.seed(42)\n", "\n", "rf = RandomForestClassifier(n_jobs=-1, n_estimators=500)\n", "rf.fit(X_train, y_train)\n", "rf_predictions = rf.predict_proba(X_test)" ] }, { "cell_type": "markdown", "id": "9b7c1235-3aa2-42ac-b7c1-7342e56405ec", "metadata": {}, "source": [ "Similarly, we may generate and apply an explainable random forest classifier, here without constraining the number of training examples involved in the predictions." ] }, { "cell_type": "code", "execution_count": 5, "id": "83e4be4c-5394-403a-ad29-4d895e905bff", "metadata": {}, "outputs": [], "source": [ "from xrf import XRandomForestClassifier\n", "\n", "np.random.seed(42)\n", "\n", "rfx = XRandomForestClassifier(n_jobs=-1, n_estimators=500)\n", "rfx.fit(X_train, y_train)\n", "rfx_predictions = rfx.predict_proba(X_test)" ] }, { "cell_type": "markdown", "id": "580a7408-79d1-4fb6-854b-1584ddb77f33", "metadata": {}, "source": [ "Let us check that we indeed get the same predictions." ] }, { "cell_type": "code", "execution_count": 6, "id": "24960b71-6eca-427f-a62a-50e3396eb6db", "metadata": {}, "outputs": [], "source": [ "assert np.allclose(rf_predictions, rfx_predictions)" ] }, { "cell_type": "markdown", "id": "b50b0a8a-8a5d-4eb6-9c3b-35cbf98a3fea", "metadata": {}, "source": [ "We may now limit the number of examples involved in a prediction, e.g., to at most 5 (`k=5`)." ] }, { "cell_type": "code", "execution_count": 7, "id": "74138293-7e2d-4525-b767-02fb68646d83", "metadata": {}, "outputs": [], "source": [ "k=5\n", "\n", "rfx_predictions_k = rfx.predict_proba(X_test, k=k)" ] }, { "cell_type": "markdown", "id": "be29b264-0e1a-4c9c-8c86-0df0b12f7a6b", "metadata": {}, "source": [ "Let us compare the predictive performance of the original and the constrained predictions." ] }, { "cell_type": "code", "execution_count": 8, "id": "d1a46f27-395e-44c3-9517-54659c73df93", "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", "
AccuracyAUC
Original0.8760.974
k=50.9330.982
\n", "
" ], "text/plain": [ " Accuracy AUC\n", "Original 0.876 0.974\n", "k=5 0.933 0.982" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from sklearn.metrics import roc_auc_score, accuracy_score\n", "import pandas as pd\n", "\n", "accuracy_orig = accuracy_score(y_test==rf.classes_[1], \n", " np.round(rf_predictions[:,1]))\n", "auc_orig = roc_auc_score(y_test == rf.classes_[1], \n", " rf_predictions[:,1])\n", "\n", "accuracy_k = accuracy_score(y_test==rfx.classes_[1], \n", " np.round(rfx_predictions_k[:,1]))\n", "auc_k = roc_auc_score(y_test == rfx.classes_[1], \n", " rfx_predictions_k[:,1])\n", "\n", "df_result = pd.DataFrame([[accuracy_orig, auc_orig],[accuracy_k, auc_k]], \n", " index=[\"Original\", f\"k={k}\"], \n", " columns=[\"Accuracy\", \"AUC\"])\n", "\n", "display(df_result.round(3))" ] }, { "cell_type": "markdown", "id": "3b06a784-c1b5-43f6-97d4-47d16d45da93", "metadata": {}, "source": [ "Let us take a look at the example attribution for some prediction." ] }, { "cell_type": "code", "execution_count": 9, "id": "01554b12-27fd-4727-be51-216c2fc76381", "metadata": {}, "outputs": [], "source": [ "rfx_predictions_k, examples, weights = rfx.predict_proba(\n", " X_test, k=k, return_examples=True, return_weights=True)" ] }, { "cell_type": "code", "execution_count": 10, "id": "51b7251b-3609-4a43-82fe-d77c19026e08", "metadata": {}, "outputs": [], "source": [ "rf_predicted_labels = np.array([rf.classes_[p.argmax()] for p in rf_predictions])\n", "rfx_predicted_labels = np.array([rfx.classes_[p.argmax()] for p in rfx_predictions_k])" ] }, { "cell_type": "code", "execution_count": 11, "id": "780947c9-fef4-4eb1-a4cf-c3dcb1ddb024", "metadata": {}, "outputs": [], "source": [ "def display_board(squares, Caption, Styles):\n", " df = pd.DataFrame(squares.reshape(3,3), \n", " columns=[\"\",\"\",\"\"], \n", " index=[\"\",\"\",\"\"])\n", " display(df.style.set_caption(Caption).set_table_styles(Styles))" ] }, { "cell_type": "code", "execution_count": 12, "id": "7a3dba7b-d8eb-47d4-b202-b294e1d3c992", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Original prediction
 negativepositive
0.370.63
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Constrained prediction
 negativepositive
0.670.33
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Test example [negative]
 
xox
bxx
ooo
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Example #1 [negative, 0.32]
 
bbx
bxx
ooo
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Example #2 [positive, 0.21]
 
box
bxx
oox
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Example #3 [negative, 0.19]
 
xbx
bbx
ooo
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Example #4 [negative, 0.16]
 
xxb
bxb
ooo
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Example #5 [positive, 0.12]
 
xoo
bxx
obx
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "test_index = 0 # Select some test example\n", "\n", "props = [(\"color\", \"grey\"), (\"font-weight\", \"bold\")]\n", "Styles = [dict(selector = \"caption\", props = props)]\n", "props_b = [(\"caption-side\", \"bottom\")]\n", "Styles_b = [dict(selector = \"caption\", props = props_b)]\n", "\n", "df = pd.DataFrame([rf_predictions[test_index]], index = [\"\"], \n", " columns=rf.classes_).round(2)\n", "display(df.style.format(precision=2).set_caption(\"Original prediction\").set_table_styles(Styles))\n", "\n", "df = pd.DataFrame([rfx_predictions_k[test_index]], index = [\"\"], \n", " columns=rfx.classes_).round(2)\n", "display(df.style.format(precision=2).set_caption(\"Constrained prediction\").set_table_styles(Styles))\n", " \n", "display_board(X_orig_test[test_index],\n", " f\"Test example [{y_test[test_index]}]\",\n", " Styles_b)\n", "\n", "for i, e in enumerate(examples[test_index]):\n", " caption = f\"Example #{i+1} [{y_train[e]}, {weights[test_index][i]:.2f}]\" \n", " display_board(X_orig_train[examples[test_index][i]],\n", " caption, Styles_b)" ] }, { "cell_type": "markdown", "id": "2eb54947-8c0c-4d66-8f22-41e5ed4c00c7", "metadata": {}, "source": [ "Let us check how many training examples contribute to the predictions in the original forest." ] }, { "cell_type": "code", "execution_count": 13, "id": "cbff0f50-f4a2-4088-add1-9d8e831f1fd2", "metadata": {}, "outputs": [ { "data": { "image/png": "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+eWXNWDAAM2fP9/rBQIAAFSEx2Fn27ZtuvfeeyVJf//73xUWFqaDBw9q4cKFevXVV71eIAAAQEV4HHbOnj2roKAgSdLq1asVHx+vGjVqqH379jp48KDXCwQAAKgIj8NOkyZNtGzZMh0+fFirVq1Sz549JUk5OTkKDg72eoEAAAAV4XHY+dOf/qQJEyYoMjJSd999t+655x5JP8/ytG7d2usFAgAAVISvpwf85je/UadOnZSVlaVWrVq52rt166ZBgwZ5tTgAAICKuqrf2XE4HAoKClJqaqrOnTsnSWrbtq1atGjh1eIAAAAqyuOwc/z4cXXr1k3NmjVT3759lZWVJUl65JFHlJSU5PUCAQAAKsLjsDNu3Dj5+fnp0KFDqlWrlqt9yJAhWrlypVeLAwAAqCiP1+ysXr1aq1atUsOGDd3amzZtyqPnAACg2vF4ZufMmTNuMzoXHDt2THa73StFAQAAeIvHYadz586u10VIks1mU0lJiV566SV17drVq8UBAABUlMe3sV566SXFxsbq66+/VmFhoSZNmqRdu3bpxIkT+vLLLyujRgAAgKvm8czO7bffrh07dujuu+9Wjx49dObMGcXHx2v79u269dZbK6NGAACAq+bxzI708+/sPPvss96uBQAAwOvKFXZ27NhR7hPecccdV10MAACAt5Ur7Nx5552y2Wwyxly2n81mU3FxsVcKAwAA8IZyhZ3MzMzKrgMAAKBSlCvsREREVHYdAAAAleKqFijv2bNHr732mnbv3i2bzaYWLVooISFBzZs393Z9AAAAFeLxo+d///vfFRUVpfT0dLVq1Up33HGHtm3bpqioKP3tb3+rjBoBAACumsczO5MmTdKUKVP03HPPubVPmzZNTz75pH772996rTgAAICK8nhmJzs7Ww899FCp9gcffFDZ2dleKQoAAMBbPA47sbGx+uKLL0q1b9y4Uffee69XigIAAPAWj8NO//799eSTT2rs2LFatGiRFi1apLFjx2ry5MkaNGiQPv30U9fnSjZs2KC4uDg5nU7ZbDYtW7bMbf/IkSNls9ncPu3bt3frU1BQoISEBIWGhqp27drq37+/jhw54ullAQAAi/J4zc7jjz8uSZo3b57mzZtX5j6pfD8weObMGbVq1UqjRo3Sr3/96zL79O7dWwsWLHBt+/v7u+1PTEzUZ599piVLlqhevXpK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62cOHTpUBVdTPVxuTDMzM8vcJ8msW7fOdQ7G1N2V/p5e7OJHz41hTC9WnjF9++23TZMmTUzNmjVNq1atzLJly9zOwZi6u9KYZmVlmZEjRxqn02lq1qxpmjdvbl5++WVTUlLiOofVx9RmjDHXIFMBAABUCdbsAAAASyPsAAAASyPsAAAASyPsAAAASyPsAAAASyPsAAAASyPsAAAASyPsAAAASyPsAKg0sbGxSkxMLHf/AwcOyGazKSMjo9JqsgJPxxW40fFuLMCifvzxRzmdTuXm5rrefbV79241atTokseMHDlSp06d0rJly7xSw9KlS+Xn51fu/uHh4crKylJoaKhXvh8AJMIOYFn/+te/dOedd6pWrVr66quvXC8F9IaioqJyhZi6det6dF4fHx85HI6rLQsAysRtLMCiNm3apI4dO0qSNm7c6PrzpUyfPl3vvvuuPvnkE9lsNtlsNq1fv951a+nDDz9UbGysatasqUWLFun48eMaOnSoGjZsqFq1aik6Olrvv/++2zkvvt0SGRmpGTNm6OGHH1ZQUJAaNWqkN954w7X/4ttY69evl81m09q1axUTE6NatWqpQ4cO2rNnj9v3PP/886pfv76CgoL0yCOPaPLkybrzzjsve73fffed+vbtq8DAQIWFhWn48OE6duyY63v9/f31xRdfuPq//PLLCg0NVVZWliRp5cqV6tSpk371q1+pXr166tevn/bv31/qWj788EPde++9CggIUNu2bbV3715t3bpVMTExCgwMVO/evfXjjz+6jhs5cqQGDhyoZ599VvXr11dwcLAee+wxFRYWXvJaCgsLNWnSJN18882qXbu22rVr53pLuCQdPHhQcXFxqlOnjmrXrq2WLVtqxYoVlx0fwFKq+k2kALzn4MGDJiQkxISEhBg/Pz9Ts2ZNExISYvz9/Y3dbjchISHmP/7jP8o89vTp02bw4MGmd+/eJisry2RlZZmCggLXG9MjIyPNRx99ZP7973+bH374wRw5csS89NJLZvv27Wb//v3m1VdfNT4+Pmbz5s2uc3bp0sU88cQTru2IiAhTt25d8+c//9ns27fPJCcnmxo1apjdu3cbY4zru7Zv326M+f+3Obdr186sX7/e7Nq1y9x7772mQ4cOrnMuWrTI1KxZ0/z1r381e/bsMc8++6wJDg42rVq1uuQ4HT161ISGhpopU6aY3bt3m23btpkePXqYrl27uvpMnDjRREREmFOnTpmMjAxjt9vN0qVLXfv//ve/m48++sjs3bvXbN++3cTFxZno6GhTXFzsdi0tWrQwK1euNN99951p3769ueuuu0xsbKzZuHGj2bZtm2nSpIn5wx/+4DrviBEjTGBgoBkyZIjZuXOn+cc//mFuuukm89RTT11yXIcNG2Y6dOhgNmzYYL7//nvz0ksvGbvdbvbu3WuMMeb+++83PXr0MDt27DD79+83n332mUlLS7vk+ABWQ9gBLKSoqMhkZmaab775xvj5+ZmMjAzz/fffm8DAQJOWlmYyMzPNjz/+eMnjR4wYYQYMGODWduEf7ZSUlCt+f9++fU1SUpJru6yw8+CDD7q2S0pKTP369c38+fPdvuvisLNmzRrXMcuXLzeSzLlz54wxxrRr186MGTPGrY6OHTteNuxMnTrV9OzZ063t8OHDRpLZs2ePMcaYgoIC07p1azN48GDTsmVL88gjj1z22nNycowk8+2337pdy1tvveXq8/777xtJZu3ata625ORk07x5c9f2iBEjTN26dc2ZM2dcbfPnzzeBgYGuIPXLcf3++++NzWYzP/zwg1s93bp1M1OmTDHGGBMdHW2mT59+2foBK+M2FmAhvr6+ioyM1P/8z/+obdu2atWqlbKzsxUWFqbOnTsrMjLyqhf/xsTEuG0XFxfrhRde0B133KF69eopMDBQq1ev1qFDhy57njvuuMP1Z5vNJofDoZycnHIf06BBA0lyHbNnzx7dfffdbv0v3r5Yenq61q1bp8DAQNenRYsWkuS6FeXv769Fixbpo48+0rlz55SSkuJ2jv3792vYsGG65ZZbFBwcrMaNG0tSqev/Ze1hYWGSpOjoaLe2i6+/VatWqlWrlmv7nnvuUX5+vg4fPlzqWrZt2yZjjJo1a+Z2PWlpaa5r+eMf/6jnn39eHTt21LRp07Rjx47Ljg9gNSxQBiykZcuWOnjwoIqKilRSUqLAwECdP39e58+fV2BgoCIiIrRr166rOnft2rXdtl9++WXNmTNHKSkpio6OVu3atZWYmHjZtSWSSi1sttlsKikpKfcxNptNktyOudB2gTHmsucrKSlRXFycZs6cWWrfhTAl/bzuSZJOnDihEydOuI1BXFycwsPD9eabb8rpdKqkpERRUVGlrr+s2i9uu9L1X3z8xdfi4+Oj9PR0+fj4uO0LDAyUJD3yyCPq1auXli9frtWrVys5OVkvv/yyEhISyvW9wPWOmR3AQlasWKGMjAw5HA4tWrRIGRkZioqKUkpKijIyMq64KNXf31/FxcXl+q4vvvhCAwYM0IMPPqhWrVrplltu0b59+7xxGR5p3ry5tmzZ4tb29ddfX/aYu+66S7t27VJkZKSaNGni9rkQaPbv369x48bpzTffVPv27fXQQw+5Qsnx48e1e/duPfPMM+rWrZtuu+02nTx50mvX9M033+jcuXOu7c2bNyswMFANGzYs1bd169YqLi5WTk5OqWv55ZNt4eHh+sMf/qClS5cqKSlJb775ptfqBao7wg5gIREREQoMDNT//u//asCAAWrUqJG+++47xcfHq0mTJoqIiLjs8ZGRkdqxY4f27NmjY8eOqaio6JJ9mzRpotTUVG3atEm7d+/WY489puzsbG9f0hUlJCTo7bff1rvvvqt9+/bp+eef144dO8qcBblgzJgxOnHihIYOHaotW7bo3//+t1avXq2HH35YxcXFKi4u1vDhw9WzZ0+NGjVKCxYs0M6dO/Xyyy9LkurUqaN69erpjTfe0Pfff6/PP/9c48eP99o1FRYWavTo0fruu+/0z3/+U9OmTdPYsWNVo0bp/2Q3a9ZMv/vd7/TQQw9p6dKlyszM1NatWzVz5kxXuE1MTNSqVauUmZmpbdu26fPPP9dtt93mtXqB6o6wA1jM+vXr1bZtW9WsWVNfffWVbr75ZjmdznId++ijj6p58+aKiYnRTTfdpC+//PKSfadOnaq77rpLvXr1UmxsrBwOhwYOHOilqyi/3/3ud5oyZYomTJigu+66S5mZmRo5cqRq1qx5yWOcTqe+/PJLFRcXq1evXoqKitITTzyhkJAQ1ahRQy+88IIOHDjgeize4XDorbfe0jPPPKOMjAzVqFFDS5YsUXp6uqKiojRu3Di99NJLXrumbt26qWnTpurcubMGDx6suLg4TZ8+/ZL9FyxYoIceekhJSUlq3ry5+vfvr6+++krh4eGSfl5fNWbMGN12223q3bu3mjdvrnnz5nmtXqC6s5kr3dwGgOtMjx495HA49N5771V1KR7z9q9YA2CBMoDr3NmzZ/X666+rV69e8vHx0fvvv681a9YoNTW1qksDUE0QdgBc12w2m1asWKHnn39eBQUFat68uT766CN17969qksDUE1wGwsAAFgaC5QBAIClEXYAAIClEXYAAIClEXYAAIClEXYAAIClEXYAAIClEXYAAIClEXYAAICl/R+ZaCgbSYMgiwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "xrfc_predictions, all_non_zero_weights = rfx.predict_proba(X_test, c=1.0, return_weights=True)\n", "\n", "lengths = [len(w) for w in all_non_zero_weights]\n", "\n", "plt.hist(lengths, 10)\n", "plt.xlabel(\"# training examples\")\n", "plt.ylabel(\"# test examples\")\n", "plt.show()\n", "\n", "assert np.allclose(rf_predictions, xrfc_predictions)" ] }, { "cell_type": "markdown", "id": "4deb9aaa-80be-4485-a1b0-84e1817efed7", "metadata": {}, "source": [ "Rather than constraining the predictions to a fixed number by setting a value for `k`, we could set a limit on the cumulative sum of the highest weights, e.g., to 30% (`c=0.3`)." ] }, { "cell_type": "code", "execution_count": 14, "id": "4d659e12-c21e-4c61-b06e-f9c7d5469a28", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
AccuracyAUC
Original0.8760.974
k=50.9330.982
c=0.30.9320.985
\n", "
" ], "text/plain": [ " Accuracy AUC\n", "Original 0.876 0.974\n", "k=5 0.933 0.982\n", "c=0.3 0.932 0.985" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "xrfc_predictions_c, all_non_zero_weights = rfx.predict_proba(\n", " X_test, c=0.3, return_weights=True)\n", "\n", "lengths = [len(w) for w in all_non_zero_weights]\n", "\n", "plt.hist(lengths, 10)\n", "plt.xlabel(\"# training examples\")\n", "plt.ylabel(\"# test examples\")\n", "plt.show()\n", "\n", "accuracy_c = accuracy_score(y_test==rfx.classes_[1], \n", " np.round(xrfc_predictions_c[:,1]))\n", "auc_c = roc_auc_score(y_test == rfx.classes_[1], xrfc_predictions_c[:,1])\n", "\n", "df_result.loc[\"c=0.3\"] = [accuracy_c, auc_c]\n", "display(df_result.round(3))" ] }, { "cell_type": "markdown", "id": "2a8c7f26-c5c1-44ea-aec5-f7fa4187322b", "metadata": {}, "source": [ "### MNIST" ] }, { "cell_type": "markdown", "id": "4fd0baa1-ef2f-42b9-ace0-94a36c3c1742", "metadata": {}, "source": [ "Let us also consider the MNIST dataset at [openml.org](https://www.openml.org)." ] }, { "cell_type": "code", "execution_count": 15, "id": "2124dccd-effa-4a59-8761-0b75d2a42bda", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original dataset size: (70000, 784)\n" ] } ], "source": [ "dataset = fetch_openml(name=\"mnist_784\", parser=\"auto\")\n", "\n", "X = dataset.data.values.astype(float)\n", "y = dataset.target.values.astype(int)\n", "\n", "print(f\"Original dataset size: {X.shape}\")" ] }, { "cell_type": "markdown", "id": "5d769580-891a-4ae4-862f-1ea6dc40926f", "metadata": {}, "source": [ "Let us split the dataset into a training and a test set." ] }, { "cell_type": "code", "execution_count": 16, "id": "75f0d924-eaca-46c5-8972-c7fddbab585f", "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "X_train, X_test, y_train, y_test, = train_test_split(\n", " X, y, test_size=0.1)" ] }, { "cell_type": "markdown", "id": "cff4af6e-43e0-416b-a43e-871342383082", "metadata": {}, "source": [ "Let us first generate a standard random forest classifier and apply it to the test set." ] }, { "cell_type": "code", "execution_count": 17, "id": "e16b1b5a-df4c-4e8f-9a8e-3049c602d11f", "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestClassifier\n", "import numpy as np\n", "\n", "np.random.seed(42)\n", "\n", "rf = RandomForestClassifier(n_jobs=-1, n_estimators=200)\n", "rf.fit(X_train, y_train)\n", "rf_predictions = rf.predict_proba(X_test)" ] }, { "cell_type": "markdown", "id": "25cfd485-0c61-4a35-abab-eb2ca6b10d8a", "metadata": {}, "source": [ "Similarly, we may generate and apply an explainable random forest classifier, here without constraining the number of training examples involved in the predictions." ] }, { "cell_type": "code", "execution_count": 18, "id": "48d51c4b-b045-4972-9824-6b0e811fd607", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "XRandomForestClassifier(model=RandomForestClassifier(n_estimators=200, n_jobs=-1, oob_score=True)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from xrf import XRandomForestClassifier\n", "\n", "np.random.seed(42)\n", "\n", "rfx = XRandomForestClassifier(n_jobs=-1, n_estimators=200)\n", "rfx.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": 19, "id": "56cb32d7-c33d-42b3-84f0-6f903a7c024a", "metadata": {}, "outputs": [], "source": [ "rfx_predictions, all_non_zero_weights = rfx.predict_proba(X_test, c=1.0, return_weights=True)" ] }, { "cell_type": "markdown", "id": "fdaa2a11-f11e-455f-b929-4376f8914b3c", "metadata": {}, "source": [ "Let us check that we indeed get the same predictions." ] }, { "cell_type": "code", "execution_count": 20, "id": "0dfe070a-9252-499c-95de-59cbac479ffb", "metadata": {}, "outputs": [], "source": [ "assert np.allclose(rf_predictions, rfx_predictions)" ] }, { "cell_type": "markdown", "id": "0c283719-4316-4e29-acfb-e0782abbe19c", "metadata": {}, "source": [ "Let us check how many training examples contribute to the predictions." ] }, { "cell_type": "code", "execution_count": 21, "id": "af300108-97d5-4c66-8b16-b8e2544dde8f", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkoAAAGyCAYAAAAbCutwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABAJ0lEQVR4nO3de1hVdf7+/3vLyRPsBIINiWBlZkGmUqJ2wDTPWtmMlYZaZjWlZeqntMNoXSVWl+k0TVZmmmlZTXYaHRLzlHkMIkUdU0PFAjHFjagBwvv3Rz/Xty0udRe4IZ6P61rXxXqv11r7tViXcbdO22GMMQIAAEAl9XzdAAAAQE1FUAIAALBBUAIAALBBUAIAALBBUAIAALBBUAIAALBBUAIAALBBUAIAALBBUAIAALDh7+sGaouKigr99NNPCg4OlsPh8HU7AADgLBhjdPjwYUVHR6tevd9xfsj40KRJk0xiYqJp3LixOf/8881NN91k/ve//3nUVFRUmAkTJpioqChTv359c/3115vs7GyPml9++cWMGDHChIWFmYYNG5q+ffua3Nxcj5qDBw+aO++804SEhJiQkBBz5513msLCwrPuNTc310hiYmJiYmJiqoXTybngbDmM8d13vfXo0UO33367rrrqKh0/flxPPPGENm3apC1btqhRo0aSpOeff17PPfecZs+erUsuuUTPPvusVq5cqW3btik4OFiS9Le//U2ff/65Zs+erbCwMI0ZM0YHDx5URkaG/Pz8JEk9e/bU3r179cYbb0iS7r33XsXFxenzzz8/q17dbrfOO+885ebmKiQkpBp+GwAAoKoVFRUpJiZGhw4dktPp9H4DvyteVZOCggIjyaxYscIY8+vZJJfLZSZPnmzV/PLLL8bpdJrXXnvNGGPMoUOHTEBAgJk/f75V8+OPP5p69eqZtLQ0Y4wxW7ZsMZLM2rVrrZo1a9YYSZXOYNlxu91GknG73X94PwEAwLnxR/9+16ibud1utyQpNDRUkpSTk6P8/Hx169bNqgkKCtL111+v1atXS5IyMjJUVlbmURMdHa34+HirZs2aNXI6nWrfvr1Vk5SUJKfTadWcrKSkREVFRR4TAACoW2pMUDLGaPTo0brmmmsUHx8vScrPz5ckRUZGetRGRkZay/Lz8xUYGKgmTZqctiYiIqLSZ0ZERFg1J0tNTZXT6bSmmJiYP7aDAACg1qkxQWnEiBHauHGj3nvvvUrLTn7KzBhzxifPTq45Vf3ptjN+/Hi53W5rys3NPZvdAAAAfyI1IiiNHDlSn332mZYtW6amTZta4y6XS5IqnfUpKCiwzjK5XC6VlpaqsLDwtDX79u2r9Ln79++vdLbqhKCgIIWEhHhMAACgbvFpUDLGaMSIEVqwYIGWLl2q5s2beyxv3ry5XC6X0tPTrbHS0lKtWLFCHTt2lCS1a9dOAQEBHjV5eXnKzs62ajp06CC3263169dbNevWrZPb7bZqAAAATubTF04++OCDevfdd/Xpp58qODjYOnPkdDrVoEEDORwOjRo1SpMmTVKLFi3UokULTZo0SQ0bNtTAgQOt2mHDhmnMmDEKCwtTaGioxo4dq4SEBHXt2lWS1KpVK/Xo0UPDhw/X66+/LunX1wP06dNHLVu29M3OAwCAGs+nQWn69OmSpOTkZI/xWbNmaejQoZKkRx99VMeOHdMDDzygwsJCtW/fXosXL7beoSRJU6dOlb+/vwYMGKBjx46pS5cumj17tvUOJUmaN2+eHnroIevpuH79+umVV16p3h0EAAC1mk9fOFmbFBUVyel0yu12c78SAAC1xB/9+10jbuYGAACoiQhKAAAANghKAAAANghKAAAANghKAAAANghKAAAANghKAAAANnz6wkkAf05x4xb6ugWv7Zrc29ctAKiBOKMEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgg6AEAABgw6dBaeXKlerbt6+io6PlcDj0ySefeCx3OBynnF588UWrJjk5udLy22+/3WM7hYWFSklJkdPplNPpVEpKig4dOnQO9hAAANRmPg1KR44cUevWrfXKK6+ccnleXp7H9NZbb8nhcOjWW2/1qBs+fLhH3euvv+6xfODAgcrKylJaWprS0tKUlZWllJSUatsvAADw5+Dvyw/v2bOnevbsabvc5XJ5zH/66afq3LmzLrzwQo/xhg0bVqo9YevWrUpLS9PatWvVvn17SdKMGTPUoUMH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kjR8+HANHz5cP//8syoqKk75niIAAIDa7ncFpRPCw8Orqg8AAIAa53e9cBIAAKAuICgBAADYICgBAADY8DoozZkzRyUlJZXGS0tLNWfOnCppCgAAoCbwOijdddddcrvdlcYPHz6su+66q0qaAgAAqAm8DkrGGDkcjkrje/fuldPprJKmAAAAaoKzfj1AmzZt5HA45HA41KVLF/n7/79Vy8vLlZOTox49elRLkwAAAL5w1kHp5ptvliRlZWWpe/fuaty4sbUsMDBQcXFxuvXWW6u8QQAAAF8566A0YcIESVJcXJxuv/12BQUFVVtTAAAANYHX9yjdcMMN2r9/vzW/fv16jRo1Sm+88UaVNgYAAOBrXgelgQMHatmyZZKk/Px8de3aVevXr9fjjz+uZ555psobBAAA8BWvg1J2drauvvpqSdIHH3yghIQErV69Wu+++65mz55d1f0BAAD4jNdBqayszLo/acmSJerXr58k6dJLL1VeXl7VdgcAAOBDXgelyy+/XK+99pq++uorpaenW68E+OmnnxQWFlblDQIAAPiK10Hp+eef1+uvv67k5GTdcccdat26tSTps88+sy7JAQAA/Bmc9esBTkhOTtbPP/+soqIiNWnSxBq/99571bBhwyptDgAAwJe8PqMk/fo1JhkZGXr99dd1+PBhSb++dJKgBAAA/ky8PqO0e/du9ejRQ3v27FFJSYluvPFGBQcH64UXXtAvv/yi1157rTr6BAAAOOe8PqP08MMPKzExUYWFhWrQoIE1fsstt+jLL7+s0uYAAAB8yeszSqtWrdLXX3+twMBAj/HY2Fj9+OOPVdYYAACAr3l9RqmiokLl5eWVxvfu3avg4OAqaQoAAKAm8Doo3XjjjZo2bZo173A4VFxcrAkTJqhXr15V2RsAAIBPeX3pberUqercubMuu+wy/fLLLxo4cKC2b9+u8PBwvffee9XRIwAAgE94HZSio6OVlZWl+fPnKyMjQxUVFRo2bJgGDRrkcXM3AABAbed1UFq5cqU6duyou+66S3fddZc1fvz4ca1cuVLXXXddlTYIAADgK17fo9S5c2cdPHiw0rjb7Vbnzp2rpCkAAICawOugZIyRw+GoNH7gwAE1atSoSpoCAACoCc760lv//v0l/fqU29ChQxUUFGQtKy8v18aNG9WxY8eq7xAAAMBHzjooOZ1OSb+eUQoODva4cTswMFBJSUkaPnx41XcIVKG4cQt93QIAoBY566A0a9YsSVJcXJzGjh3LZTYAAPCn5/VTbxMmTKiOPgAAAGocr2/mBgAAqCtqfFCKi4uTw+GoND344IOSpKFDh1ZalpSU5LGNkpISjRw5UuHh4WrUqJH69eunvXv3+mJ3AABALVLjg9KGDRuUl5dnTenp6ZKkv/71r1ZNjx49PGoWLVrksY1Ro0bp448/1vz587Vq1SoVFxerT58+p/xyXwAAgBO8vkfpXDv//PM95idPnqyLLrpI119/vTUWFBQkl8t1yvXdbrdmzpypd955R127dpUkzZ07VzExMVqyZIm6d+9efc0DQDWqjU9x7prc29ctAF75XWeURowYccq3c1e30tJSzZ07V3fffbfHSy+XL1+uiIgIXXLJJRo+fLgKCgqsZRkZGSorK1O3bt2ssejoaMXHx2v16tW2n1VSUqKioiKPCQAA1C1nHZR+e0/Pu+++q+LiYklSQkKCcnNzq76zU/jkk0906NAhDR061Brr2bOn5s2bp6VLl2rKlCnasGGDbrjhBpWUlEiS8vPzFRgYqCZNmnhsKzIyUvn5+baflZqaKqfTaU0xMTHVsk8AAKDmOutLb5deeqnCwsLUqVMn/fLLL8rNzVWzZs20a9culZWVVWePlpkzZ6pnz56Kjo62xm677Tbr5/j4eCUmJio2NlYLFy603iZ+KnZfxXLC+PHjNXr0aGu+qKiIsAQAQB1z1meU3G63PvzwQ7Vr104VFRXq1auXLrnkEpWUlOiLL7447dmZqrB7924tWbJE99xzz2nroqKiFBsbq+3bt0uSXC6XSktLVVhY6FFXUFCgyMhI2+0EBQUpJCTEYwIAAHXLWQelsrIyXX311RozZowaNGigb7/9VrNmzZKfn5/eeustXXTRRWrZsmW1NTpr1ixFRESod+/T3wh44MAB5ebmKioqSpLUrl07BQQEWE/LSVJeXp6ys7P5bjoAAHBaZ33pLSQkRG3atFGnTp1UWlqqo0ePqlOnTvL399f777+vpk2bav369dXSZEVFhWbNmqUhQ4bI3///tVxcXKyJEyfq1ltvVVRUlHbt2qXHH39c4eHhuuWWWyT9+h11w4YN05gxYxQWFqbQ0FCNHTtWCQkJ1lNwAAAAp3LWQemnn37SmjVrtHr1ah0/flyJiYm66qqrVFpaqszMTMXExOiaa66pliaXLFmiPXv26O677/YY9/Pz06ZNmzRnzhwdOnRIUVFR6ty5s95//30FBwdbdVOnTpW/v78GDBigY8eOqUuXLpo9e7b8/PyqpV8AAPDn4DDGGG9XatKkiVauXKmtW7dq8ODBcrlc2rdvn66++mqtWLGiOvr0uaKiIjmdTrndbu5XqsVq43tngD8T3qOEc+2P/v3+3W/mdjqdGjBggAICArR06VLl5OTogQce+L2bAwAAqHF+15u5N27cqAsuuECSFBsbq4CAALlcLo9H9QEAAGq73xWUfvs+oezs7CprBgAAoCap8V+KCwAA4CsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABsEJQAAABs1OihNnDhRDofDY3K5XNZyY4wmTpyo6OhoNWjQQMnJydq8ebPHNkpKSjRy5EiFh4erUaNG6tevn/bu3XuudwUAANRCNTooSdLll1+uvLw8a9q0aZO17IUXXtBLL72kV155RRs2bJDL5dKNN96ow4cPWzWjRo3Sxx9/rPnz52vVqlUqLi5Wnz59VF5e7ovdAQAAtYi/rxs4E39/f4+zSCcYYzRt2jQ98cQT6t+/vyTp7bffVmRkpN59913dd999crvdmjlzpt555x117dpVkjR37lzFxMRoyZIl6t69+zndFwAAULvU+DNK27dvV3R0tJo3b67bb79dP/zwgyQpJydH+fn56tatm1UbFBSk66+/XqtXr5YkZWRkqKyszKMmOjpa8fHxVo2dkpISFRUVeUwAAKBuqdFBqX379pozZ46++OILzZgxQ/n5+erYsaMOHDig/Px8SVJkZKTHOpGRkday/Px8BQYGqkmTJrY1dlJTU+V0Oq0pJiamCvcMAADUBjU6KPXs2VO33nqrEhIS1LVrVy1cuFDSr5fYTnA4HB7rGGMqjZ3sbGrGjx8vt9ttTbm5ub9zLwAAQG1Vo4PSyRo1aqSEhARt377dum/p5DNDBQUF1lkml8ul0tJSFRYW2tbYCQoKUkhIiMcEAADqlloVlEpKSrR161ZFRUWpefPmcrlcSk9Pt5aXlpZqxYoV6tixoySpXbt2CggI8KjJy8tTdna2VQMAAGCnRj/1NnbsWPXt21fNmjVTQUGBnn32WRUVFWnIkCFyOBwaNWqUJk2apBYtWqhFixaaNGmSGjZsqIEDB0qSnE6nhg0bpjFjxigsLEyhoaEaO3asdSkPAADgdGp0UNq7d6/uuOMO/fzzzzr//POVlJSktWvXKjY2VpL06KOP6tixY3rggQdUWFio9u3ba/HixQoODra2MXXqVPn7+2vAgAE6duyYunTpotmzZ8vPz89XuwUAAGoJhzHG+LqJ2qCoqEhOp1Nut5v7lSTFjVvo6xYA1EK7Jvf2dQuoY/7o3+9adY8SAADAuURQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsEFQAgAAsFGjg1JqaqquuuoqBQcHKyIiQjfffLO2bdvmUTN06FA5HA6PKSkpyaOmpKREI0eOVHh4uBo1aqR+/fpp796953JXAABALVSjg9KKFSv04IMPau3atUpPT9fx48fVrVs3HTlyxKOuR48eysvLs6ZFixZ5LB81apQ+/vhjzZ8/X6tWrVJxcbH69Omj8vLyc7k7AACglvH3dQOnk5aW5jE/a9YsRUREKCMjQ9ddd501HhQUJJfLdcptuN1uzZw5U++88466du0qSZo7d65iYmK0ZMkSde/evfp2AAAA1Go1+ozSydxutyQpNDTUY3z58uWKiIjQJZdcouHDh6ugoMBalpGRobKyMnXr1s0ai46OVnx8vFavXm37WSUlJSoqKvKYAABA3VJrgpIxRqNHj9Y111yj+Ph4a7xnz56aN2+eli5dqilTpmjDhg264YYbVFJSIknKz89XYGCgmjRp4rG9yMhI5efn235eamqqnE6nNcXExFTPjgEAgBqrRl96+60RI0Zo48aNWrVqlcf4bbfdZv0cHx+vxMRExcbGauHCherfv7/t9owxcjgctsvHjx+v0aNHW/NFRUWEJQAA6phacUZp5MiR+uyzz7Rs2TI1bdr0tLVRUVGKjY3V9u3bJUkul0ulpaUqLCz0qCsoKFBkZKTtdoKCghQSEuIxAQCAuqVGByVjjEaMGKEFCxZo6dKlat68+RnXOXDggHJzcxUVFSVJateunQICApSenm7V5OXlKTs7Wx07dqy23gEAQO1Xoy+9Pfjgg3r33Xf16aefKjg42LqnyOl0qkGDBiouLtbEiRN16623KioqSrt27dLjjz+u8PBw3XLLLVbtsGHDNGbMGIWFhSk0NFRjx45VQkKC9RQcAADAqdTooDR9+nRJUnJyssf4rFmzNHToUPn5+WnTpk2aM2eODh06pKioKHXu3Fnvv/++goODrfqpU6fK399fAwYM0LFjx9SlSxfNnj1bfn5+53J3AABALeMwxhhfN1EbFBUVyel0yu12c7+SpLhxC33dAoBaaNfk3r5uAXXMH/37XaPvUQIAAPAlghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANf183AClu3EJftwAAAE6BM0oAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2CEoAAAA2/H3dAACg7ogbt9DXLXht1+Tevm4BPsQZJQAAABt1Kii9+uqrat68uerXr6927drpq6++8nVLAACgBqszl97ef/99jRo1Sq+++qo6deqk119/XT179tSWLVvUrFkzX7cHAKihuFxYt9WZM0ovvfSShg0bpnvuuUetWrXStGnTFBMTo+nTp/u6NQAAUEPViTNKpaWlysjI0Lhx4zzGu3XrptWrV59ynZKSEpWUlFjzbrdbklRUVFTl/VWUHK3ybQIA6q5mj3zo6xa8lv1092rZ7om/28aY37V+nQhKP//8s8rLyxUZGekxHhkZqfz8/FOuk5qaqqeffrrSeExMTLX0CABAXeacVr3bP3z4sJxOp9fr1YmgdILD4fCYN8ZU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SO3bt9fy5cut5bt371bfvn3VpEkTNWrUSJdffrkWLVp02t8PUCd4+V13AGq53bt3G6fTaZxOpwkICDD169c3TqfTBAYGmqCgION0Os3f/va3U657+PBhM2DAANOjRw+Tl5dn8vLyTElJicnJyTGSTFxcnPnoo4/MDz/8YH788Uezd+9e8+KLL5pvv/3W7Ny507z88svGz8/PrF271trmyV/uGxsba0JDQ82//vUvs337dpOammrq1atntm7daowx1md9++23xpj/9wWc7du3N8uXLzebN2821157renYsaO1zblz55r69eubt956y2zbts08/fTTJiQkxLRu3dr29/TTTz+Z8PBwM378eLN161aTmZlpbrzxRtO5c2er5v/+7/9MbGysOXTokMnKyjJBQUFmwYIF1vJ///vf5qOPPjLff/+9+fbbb03fvn1NQkKCKS8v99iXSy+91KSlpZktW7aYpKQk07ZtW5OcnGxWrVplMjMzzcUXX2zuv/9+a7tDhgwxjRs3NrfddpvJzs42//nPf8z5559vHn/8cdvf68CBA03Hjh3NypUrzY4dO8yLL75ogoKCzPfff2+MMaZ3797mxhtvNBs3bjQ7d+40n3/+uVmxYoXt7weoKwhKQB1TVlZmcnJyzHfffWcCAgJMVlaW2bFjh2ncuLFZsWKFycnJMfv377ddf8iQIeamm27yGDvxB3/atGln/PxevXqZMWPGWPOnCkp33nmnNV9RUWEiIiLM9OnTPT7r5KC0ZMkSa52FCxcaSebYsWPGGGPat29vHnzwQY8+OnXqdNqg9NRTT5lu3bp5jOXm5hpJZtu2bcYYY0pKSkybNm3MgAEDzOWXX27uueee0+57QUGBkWR9U/qJfXnzzTetmvfee89IMl9++aU1lpqaalq2bGnNDxkyxISGhpojR45YY9OnTzeNGze2Qthvf687duwwDofD/Pjjjx79dOnSxYwfP94YY0xCQoKZOHHiafsH6iIuvQF1jL+/v+Li4vS///1PV111lVq3bq38/HxFRkbquuuuU1xc3O++UToxMdFjvry8XM8995yuuOIKhYWFqXHjxlq8eLH27Nlz2u1cccUV1s8Oh0Mul0sFBQVnvU5UVJQkWets27ZNV199tUf9yfMny8jI0LJly9S4cWNruvTSSyXJunwWGBiouXPn6qOPPtKxY8c0bdo0j23s3LlTAwcO1IUXXqiQkBA1b95ckirt/297j4yMlCQlJCR4jJ28/61bt1bDhg2t+Q4dOqi4uFi5ubmV9iUzM1PGGF1yySUe+7NixQprXx566CE9++yz6tSpkyZMmKCNGzee9vcD1BXczA3UMZdffrl2796tsrIyVVRUqHHjxjp+/LiOHz+uxo0bKzY2Vps3b/5d227UqJHH/JQpUzR16lRNmzZNCQkJatSokUaNGnXae2kkVboJ3OFwqKKi4qzXcTgckuSxzomxE4wxp91eRUWF+vbtq+eff77SshNBTPr1Pi9JOnjwoA4ePOjxO+jbt69iYmI0Y8YMRUdHq6KiQvHx8ZX2/1S9nzx2pv0/ef2T98XPz08ZGRny8/PzWNa4cWNJ0j333KPu3btr4cKFWrx4sVJTUzVlyhSNHDnyrD4X+LPijBJQxyxatEhZWVlyuVyaO3eusrKyFB8fr2nTpikrK+uMN/AGBgaqvLz8rD7rq6++0k033aQ777xTrVu31oUXXqjt27dXxW54pWXLllq/fr3H2DfffHPaddq2bavNmzcrLi5OF198scd0Igzt3LlTjzzyiGbMmKGkpCQNHjzYCjQHDhzQ1q1b9eSTT6pLly5q1aqVCgsLq2yfvvvuOx07dsyaX7t2rRo3bqymTZtWqm3Tpo3Ky8tVUFBQaV9++wRhTEyM7r//fi1YsEBjxozRjBkzqqxfoLYiKAF1TGxsrBo3bqx9+/bppptuUrNmzbRlyxb1799fF198sWJjY0+7flxcnDZu3Kht27bp559/VllZmW3txRdfrPT0dK1evVpbt27Vfffdp/z8/KrepTMaOXKkZs6cqbffflvbt2/Xs88+q40bN57y7MsJDz74oA4ePKg77rhD69ev1w8//KDFixfr7rvvVnl5ucrLy5WSkqJu3brprrvu0qxZs5Sdna0pU6ZIkpo0aaKwsDC98cYb2rFjh5YuXarRo0dX2T6VlpZq2LBh2rJli/773/9qwoQJGjFihOrVq/yf9UsuuUSDBg3S4MGDtWDBAuXk5GjDhg16/vnnrWA8atQoffHFF8rJyVFmZqaWLl2qVq1aVVm/QG1FUALqoOXLl+uqq65S/fr1tW7dOl1wwQWKjo4+q3WHDx+uli1bKjExUeeff76+/vpr29qnnnpKbdu2Vffu3ZWcnCyXy6Wbb765ivbi7A0aNEjjx4/X2LFj1bZtW+Xk5Gjo0KGqX7++7TrR0dH6+uuvVV5eru7duys+Pl4PP/ywnE6n6tWrp+eee067du2yXl3gcrn05ptv6sknn1RWVpbq1aun+fPnKyMjQ/Hx8XrkkUf04osvVtk+denSRS1atNB1112nAQMGqG/fvpo4caJt/axZszR48GCNGTNGLVu2VL9+/bRu3TrFxMRI+vV+sgcffFCtWrVSjx491LJlS7366qtV1i9QWznMmS7UA8Cf0I033iiXy6V33nnH1614rarfjg7AHjdzA/jTO3r0qF577TV1795dfn5+eu+997RkyRKlp6f7ujUANRxBCcCfnsPh0KJFi/Tss8+qpKRELVu21EcffaSuXbv6ujUANRyX3gAAAGxwMzcAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAIANghIAAICN/w81J8q9Wto46QAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "lengths = [len(w) for w in all_non_zero_weights]\n", "\n", "plt.hist(lengths, 10)\n", "plt.xlabel(\"# training examples\")\n", "plt.ylabel(\"# test examples\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "934077d9-3391-4d37-92f7-19f85d0b37d7", "metadata": {}, "source": [ "We may now limit the number of examples involved in a prediction, e.g., to at most 10 (`k=10`) and request that the top-weighted examples and the corresponding weights are returned." ] }, { "cell_type": "code", "execution_count": 22, "id": "be0708d7-f4eb-41ab-88b9-c040ace2f326", "metadata": {}, "outputs": [], "source": [ "k=10\n", "\n", "rfx_predictions_k, examples, weights = rfx.predict_proba(X_test, \n", " k=k, \n", " return_examples=True, \n", " return_weights=True)" ] }, { "cell_type": "code", "execution_count": 23, "id": "0e40b556-e110-46fe-82d2-d2954aca9621", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAGwCAYAAABIC3rIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABAaElEQVR4nO3de3RU5b3/8c+Qy0ggGSGYDJEIiDGACYhEQ0KRWK4VCNZfCzUaUQH1SMEIFKXaA1obLh6BWo4U0YoiSusFayvGoJUolwAGUq7iLSBIhqCGSYCYYPL8/nCxT4cAZjDJJOz3a61Zi3n2d+/5PnupfHxm7z0OY4wRAACAjbUIdAMAAACBRiACAAC2RyACAAC2RyACAAC2RyACAAC2RyACAAC2RyACAAC2FxzoBpqLmpoaHTx4UOHh4XI4HIFuBwAA1IExRuXl5YqJiVGLFmdeByIQ1dHBgwcVGxsb6DYAAMA52L9/vzp06HDG7QSiOgoPD5f0/QmNiIgIcDcAAKAuysrKFBsba/09fiYEojo6+TVZREQEgQgAgGbmhy534aJqAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewQiAABgewENRJ06dZLD4aj1mjBhgiTJGKOZM2cqJiZGLVu2VFpamnbu3OlzjMrKSk2cOFHt2rVTq1atlJ6ergMHDvjUlJaWKjMzUy6XSy6XS5mZmTpy5EhjTRMAADRxAQ1EmzdvVnFxsfVavXq1JOmXv/ylJGnu3LmaN2+eFi5cqM2bN8vtdmvQoEEqLy+3jpGVlaWVK1dqxYoVWrt2rY4eParhw4erurraqsnIyFBhYaFycnKUk5OjwsJCZWZmNu5kAQBA02WakHvvvdd06dLF1NTUmJqaGuN2u83s2bOt7d9++61xuVzmz3/+szHGmCNHjpiQkBCzYsUKq+bLL780LVq0MDk5OcYYY3bt2mUkmfz8fKtmw4YNRpL56KOP6tyb1+s1kozX6/2x0wQAAI2krn9/N5lriKqqqvTCCy/ojjvukMPhUFFRkTwejwYPHmzVOJ1O9e/fX+vXr5ckFRQU6MSJEz41MTExSkhIsGo2bNggl8ul5ORkq6ZPnz5yuVxWzelUVlaqrKzM5wUAAM5PwYFu4KTXX39dR44c0W233SZJ8ng8kqTo6GifuujoaO3bt8+qCQ0NVZs2bWrVnNzf4/EoKiqq1udFRUVZNacza9YsPfzww+c8HwDNS6cH3gx0C37bO3tYoFsAzhtNZoXomWee0c9+9jPFxMT4jDscDp/3xphaY6c6teZ09T90nOnTp8vr9Vqv/fv312UaAACgGWoSgWjfvn165513NG7cOGvM7XZLUq1VnJKSEmvVyO12q6qqSqWlpWetOXToUK3PPHz4cK3Vp//kdDoVERHh8wIAAOenJhGInn32WUVFRWnYsP9b/u3cubPcbrd155n0/XVGeXl5Sk1NlST17t1bISEhPjXFxcXasWOHVZOSkiKv16tNmzZZNRs3bpTX67VqAACAvQX8GqKamho9++yzGjNmjIKD/68dh8OhrKwsZWdnKy4uTnFxccrOzlZYWJgyMjIkSS6XS2PHjtWUKVMUGRmptm3baurUqUpMTNTAgQMlSd26ddPQoUM1fvx4LV68WJJ05513avjw4YqPj2/8CQMAgCYn4IHonXfe0RdffKE77rij1rZp06apoqJC99xzj0pLS5WcnKzc3FyFh4dbNfPnz1dwcLBGjRqliooKDRgwQEuXLlVQUJBVs3z5ck2aNMm6Gy09PV0LFy5s+MkBAIBmwWGMMYFuojkoKyuTy+WS1+vleiLgPMRdZsD5qa5/fzeJa4gAAAACiUAEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsj0AEAABsL+CB6Msvv9Qtt9yiyMhIhYWF6corr1RBQYG13RijmTNnKiYmRi1btlRaWpp27tzpc4zKykpNnDhR7dq1U6tWrZSenq4DBw741JSWliozM1Mul0sul0uZmZk6cuRIY0wRAAA0cQENRKWlperbt69CQkL01ltvadeuXXr88cd14YUXWjVz587VvHnztHDhQm3evFlut1uDBg1SeXm5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1CkQdezYsaH7AAAACJhzuqh6z549+tOf/qTdu3fL4XCoa9eumjhxouLj4+u7PwAAgAbn9233r7zyihISElRQUKCePXuqR48e2rJlixISEvTyyy83RI8AAAANyu8VomnTpmn69Ol65JFHfMZnzJih+++/X7/85S/rrTkAAIDG4PcKkcfj0a233lpr/JZbbpHH46mXpgAAABqT34EoLS1NH3zwQa3xtWvXql+/fvXSFAAAQGPy+yuz9PR03X///SooKFCfPn0kSfn5+Xr55Zf18MMP64033vCpBQAAaOoc5oeetniKFi3qtqh0vj2ksaysTC6XS16vVxEREYFuB0A96/TAm4FuwW97Zw8LdAtAk1fXv7/9XiGqqan5UY0BAAA0NX5fQwQAAHC+OacHM27atElr1qxRSUlJrRWjefPm1UtjAAAAjcXvQJSdna2HHnpI8fHxio6OlsPhsLb9558BAACaC78D0R//+Ef95S9/0W233dYA7QAAADQ+v68hatGihfr27dsQvQAAAASE34Hovvvu0//+7/82RC8AAAAB4fdXZlOnTtWwYcPUpUsXde/eXSEhIT7bX3vttXprDgAAoDH4vUI0ceJEvffee7r88ssVGRkpl8vl8zpXs2bNksPhUFZWljVmjNHMmTMVExOjli1bKi0tTTt37vTZr7KyUhMnTlS7du3UqlUrpaen68CBAz41paWlyszMtHrMzMzUkSNHzrlXAABwfvF7hej555/Xq6++qmHD6u8JqZs3b9ZTTz2lHj16+IzPnTtX8+bN09KlS3X55Zfr0Ucf1aBBg7Rnzx6Fh4dLkrKysvSPf/xDK1asUGRkpKZMmaLhw4eroKBAQUFBkqSMjAwdOHBAOTk5kqQ777xTmZmZ+sc//lFvcwAAAM2X3ytEbdu2VZcuXeqtgaNHj+rmm2/WkiVL1KZNG2vcGKMFCxbowQcf1I033qiEhAQ999xzOn78uF588UVJktfr1TPPPKPHH39cAwcOVK9evfTCCy9o+/bteueddyRJu3fvVk5Ojp5++mmlpKQoJSVFS5Ys0T//+U/t2bOn3uYBAACaL78D0cyZMzVjxgwdP368XhqYMGGChg0bpoEDB/qMFxUVyePxaPDgwdaY0+lU//79tX79eklSQUGBTpw44VMTExOjhIQEq2bDhg1yuVxKTk62avr06SOXy2XVnE5lZaXKysp8XgAA4Pzk91dmTzzxhD777DNFR0erU6dOtS6q3rJlS52PtWLFCm3ZskWbN2+utc3j8UiSoqOjfcajo6O1b98+qyY0NNRnZelkzcn9PR6PoqKiah0/KirKqjmdWbNm6eGHH67zXAAAQPPldyC64YYb6uWD9+/fr3vvvVe5ubm64IILzlh36tOvjTE/+ETsU2tOV/9Dx5k+fbomT55svS8rK1NsbOxZPxcAADRPfgeiGTNm1MsHFxQUqKSkRL1797bGqqur9f7772vhwoXW9T0ej0ft27e3akpKSqxVI7fbraqqKpWWlvqsEpWUlCg1NdWqOXToUK3PP3z4cK3Vp//kdDrldDp/3CQBAECzELBfux8wYIC2b9+uwsJC65WUlKSbb75ZhYWFuvTSS+V2u7V69Wprn6qqKuXl5Vlhp3fv3goJCfGpKS4u1o4dO6yalJQUeb1ebdq0yarZuHGjvF6vVQMAAOzN7xWi6upqzZ8/X3/729/0xRdfqKqqymf7N998U6fjhIeHKyEhwWesVatWioyMtMazsrKUnZ2tuLg4xcXFKTs7W2FhYcrIyJAkuVwujR07VlOmTFFkZKTatm2rqVOnKjEx0bpIu1u3bho6dKjGjx+vxYsXS/r+tvvhw4crPj7e3+kDAIDzkN8rRA8//LDmzZunUaNGyev1avLkybrxxhvVokULzZw5s16bmzZtmrKysnTPPfcoKSlJX375pXJzc61nEEnS/PnzdcMNN2jUqFHq27evwsLC9I9//MN6BpEkLV++XImJiRo8eLAGDx6sHj16aNmyZfXaKwAAaL4cxhjjzw5dunTRE088oWHDhik8PFyFhYXWWH5+vvWMoPNNWVmZXC6XvF6vIiIiAt0OgHrW6YE3A92C3/bOrr8H5ALnq7r+/e33CpHH41FiYqIkqXXr1vJ6vZKk4cOH6803m99/UAAAAPwORB06dFBxcbEk6bLLLlNubq6k739+g7uyAABAc+R3IPr5z3+ud999V5J077336ne/+53i4uJ066236o477qj3BgEAABqa33eZzZ492/rzL37xC8XGxmrdunW67LLLlJ6eXq/NAQAANAa/A9GpkpOTrd8Jq8tTpAEAAJoav78yy8zM1NGjR2uN7927V9dee229NAUAANCY/A5Eu3btUmJiotatW2eNPffcc+rZs+dZfwoDAACg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knr37q2QkBCfmuLiYu3YscOqSUlJkdfr1aZNm6yajRs3yuv1WjUAAMC+AvqV2YQJE/Tiiy/q73//u8LDw62VIJfLpZYtW8rhcCgrK0vZ2dmKi4tTXFycsrOzFRYWpoyMDKt27NixmjJliiIjI9W2bVtNnTpViYmJGjhwoCSpW7duGjp0qMaPH6/FixdLku68804NHz78tHeYAQAAewloIFq0aJEkKS0tzWf82Wef1W233SZJmjZtmioqKnTPPfeotLRUycnJys3NVXh4uFU/f/58BQcHa9SoUaqoqNCAAQO0dOlSBQUFWTXLly/XpEmTrLvR0tPTtXDhwoadIAAAaBaa1HOImrK6PscAQPPEc4iA81OzfA4RAABAIBCIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7RGIAACA7QU0EL3//vsaMWKEYmJi5HA49Prrr/tsN8Zo5syZiomJUcuWLZWWlqadO3f61FRWVmrixIlq166dWrVqpfT0dB04cMCnprS0VJmZmXK5XHK5XMrMzNSRI0caeHYAAKC5CGggOnbsmHr27KmFCxeedvvcuXM1b948LVy4UJs3b5bb7dagQYNUXl5u1WRlZWnlypVasWKF1q5dq6NHj2r48OGqrq62ajIyMlRYWKicnBzl5OSosLBQmZmZDT4/AADQPDiMMSbQTUiSw+HQypUrdcMNN0j6fnUoJiZGWVlZuv/++yV9vxoUHR2tOXPm6K677pLX69VFF12kZcuWafTo0ZKkgwcPKjY2VqtWrdKQIUO0e/dude/eXfn5+UpOTpYk5efnKyUlRR999JHi4+NP209lZaUqKyut92VlZYqNjZXX61VEREQDngkAgdDpgTcD3YLf9s4eFugWgCavrKxMLpfrB//+brLXEBUVFcnj8Wjw4MHWmNPpVP/+/bV+/XpJUkFBgU6cOOFTExMTo4SEBKtmw4YNcrlcVhiSpD59+sjlclk1pzNr1izrKzaXy6XY2Nj6niIAAGgimmwg8ng8kqTo6Gif8ejoaGubx+NRaGio2rRpc9aaqKioWsePioqyak5n+vTp8nq91mv//v0/aj4AAKDpCg50Az/E4XD4vDfG1Bo71ak1p6v/oeM4nU45nU4/uwUAAM1Rk10hcrvdklRrFaekpMRaNXK73aqqqlJpaelZaw4dOlTr+IcPH661+gQAAOypyQaizp07y+12a/Xq1dZYVVWV8vLylJqaKknq3bu3QkJCfGqKi4u1Y8cOqyYlJUVer1ebNm2yajZu3Civ12vVAAAAewvoV2ZHjx7Vp59+ar0vKipSYWGh2rZtq0suuURZWVnKzs5WXFyc4uLilJ2drbCwMGVkZEiSXC6Xxo4dqylTpigyMlJt27bV1KlTlZiYqIEDB0qSunXrpqFDh2r8+PFavHixJOnOO+/U8OHDz3iHGQAAsJeABqIPP/xQ1113nfV+8uTJkqQxY8Zo6dKlmjZtmioqKnTPPfeotLRUycnJys3NVXh4uLXP/PnzFRwcrFGjRqmiokIDBgzQ0qVLFRQUZNUsX75ckyZNsu5GS09PP+OzjwAAgP00mecQNXV1fY4BgOaJ5xAB56dm/xwiAACAxkIgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtkcgAgAAtmerQPTkk0+qc+fOuuCCC9S7d2998MEHgW4JAAA0AbYJRH/961+VlZWlBx98UFu3blW/fv30s5/9TF988UWgWwMAAAFmm0A0b948jR07VuPGjVO3bt20YMECxcbGatGiRYFuDQAABFhwoBtoDFVVVSooKNADDzzgMz548GCtX7/+tPtUVlaqsrLSeu/1eiVJZWVlDdcogICpqTwe6Bb8xn+PgB928t8TY8xZ62wRiL766itVV1crOjraZzw6Oloej+e0+8yaNUsPP/xwrfHY2NgG6REA/OVaEOgOgOajvLxcLpfrjNttEYhOcjgcPu+NMbXGTpo+fbomT55sva+pqdE333yjyMjIM+5jF2VlZYqNjdX+/fsVERER6HbOa5zrxsF5bhyc58bBefZljFF5ebliYmLOWmeLQNSuXTsFBQXVWg0qKSmptWp0ktPplNPp9Bm78MILG6rFZikiIoJ/2RoJ57pxcJ4bB+e5cXCe/8/ZVoZOssVF1aGhoerdu7dWr17tM7569WqlpqYGqCsAANBU2GKFSJImT56szMxMJSUlKSUlRU899ZS++OIL3X333YFuDQAABJhtAtHo0aP19ddf65FHHlFxcbESEhK0atUqdezYMdCtNTtOp1MzZsyo9ZUi6h/nunFwnhsH57lxcJ7PjcP80H1oAAAA5zlbXEMEAABwNgQiAABgewQiAABgewQiAABgewQi1FJeXq6srCx17NhRLVu2VGpqqjZv3nzWfSorK/Xggw+qY8eOcjqd6tKli/7yl780UsfN07mc5+XLl6tnz54KCwtT+/btdfvtt+vrr79upI6bh/fff18jRoxQTEyMHA6HXn/9dZ/txhjNnDlTMTExatmypdLS0rRz584fPO6rr76q7t27y+l0qnv37lq5cmUDzaB5aIjzvGTJEvXr109t2rRRmzZtNHDgQG3atKkBZ9H0NdQ/zyetWLFCDodDN9xwQ/023gwRiFDLuHHjtHr1ai1btkzbt2/X4MGDNXDgQH355Zdn3GfUqFF699139cwzz2jPnj166aWX1LVr10bsuvnx9zyvXbtWt956q8aOHaudO3fq5Zdf1ubNmzVu3LhG7rxpO3bsmHr27KmFCxeedvvcuXM1b948LVy4UJs3b5bb7dagQYNUXl5+xmNu2LBBo0ePVmZmpv79738rMzNTo0aN0saNGxtqGk1eQ5znNWvW6KabbtJ7772nDRs26JJLLtHgwYPP+t+e811DnOeT9u3bp6lTp6pfv3713XbzZID/cPz4cRMUFGT++c9/+oz37NnTPPjgg6fd56233jIul8t8/fXXjdHieeFczvNjjz1mLr30Up+xJ554wnTo0KHB+mzuJJmVK1da72tqaozb7TazZ8+2xr799lvjcrnMn//85zMeZ9SoUWbo0KE+Y0OGDDG/+tWv6r3n5qi+zvOpvvvuOxMeHm6ee+65+my32arP8/zdd9+Zvn37mqefftqMGTPGjBw5soG6bj5YIYKP7777TtXV1brgggt8xlu2bKm1a9eedp833nhDSUlJmjt3ri6++GJdfvnlmjp1qioqKhqj5WbpXM5zamqqDhw4oFWrVskYo0OHDumVV17RsGHDGqPl80JRUZE8Ho8GDx5sjTmdTvXv31/r168/434bNmzw2UeShgwZctZ97Oxcz/Opjh8/rhMnTqht27YN0Waz92PO8yOPPKKLLrpIY8eObeg2mw0CEXyEh4crJSVFv//973Xw4EFVV1frhRde0MaNG1VcXHzafT7//HOtXbtWO3bs0MqVK7VgwQK98sormjBhQiN333ycy3lOTU3V8uXLNXr0aIWGhsrtduvCCy/Un/70p0buvvk6+QPPp/6oc3R0dK0ffz51P3/3sbNzPc+neuCBB3TxxRdr4MCB9drf+eJcz/O6dev0zDPPaMmSJQ3aX3NDIEIty5YtkzFGF198sZxOp5544gllZGQoKCjotPU1NTVyOBxavny5rrnmGl1//fWaN2+eli5dyirRWfh7nnft2qVJkybpv//7v1VQUKCcnBwVFRXxe3znwOFw+Lw3xtQaq4997O7HnLO5c+fqpZde0muvvVZrJRW+/DnP5eXluuWWW7RkyRK1a9euMdprNmzzW2aouy5duigvL0/Hjh1TWVmZ2rdvr9GjR6tz586nrW/fvr0uvvhiuVwua6xbt24yxujAgQOKi4trrNabFX/P86xZs9S3b1/95je/kST16NFDrVq1Ur9+/fToo4+qffv2jdl+s+R2uyV9/3/W/3m+SkpKav1f9qn7nfp/3D+0j52d63k+6X/+53+UnZ2td955Rz169GiwPpu7cznPn332mfbu3asRI0ZYYzU1NZKk4OBg7dmzR126dGnArpsuVohwRq1atVL79u1VWlqqt99+WyNHjjxtXd++fXXw4EEdPXrUGvv444/VokULdejQobHabbbqep6PHz+uFi18/5U9uZpk+EnCOuncubPcbrdWr15tjVVVVSkvL0+pqaln3C8lJcVnH0nKzc096z52dq7nWZIee+wx/f73v1dOTo6SkpIautVm7VzOc9euXbV9+3YVFhZar/T0dF133XUqLCxUbGxsY7Xf9ATscm40WTk5Oeatt94yn3/+ucnNzTU9e/Y011xzjamqqjLGGPPAAw+YzMxMq768vNx06NDB/OIXvzA7d+40eXl5Ji4uzowbNy5QU2gW/D3Pzz77rAkODjZPPvmk+eyzz8zatWtNUlKSueaaawI1hSapvLzcbN261WzdutVIMvPmzTNbt241+/btM8YYM3v2bONyucxrr71mtm/fbm666SbTvn17U1ZWZh0jMzPTPPDAA9b7devWmaCgIDN79myze/duM3v2bBMcHGzy8/MbfX5NRUOc5zlz5pjQ0FDzyiuvmOLiYutVXl7e6PNrKhriPJ+Ku8y+RyBCLX/961/NpZdeakJDQ43b7TYTJkwwR44csbaPGTPG9O/f32ef3bt3m4EDB5qWLVuaDh06mMmTJ5vjx483cufNy7mc5yeeeMJ0797dtGzZ0rRv397cfPPN5sCBA43cedP23nvvGUm1XmPGjDHGfH+r8owZM4zb7TZOp9Nce+21Zvv27T7H6N+/v1V/0ssvv2zi4+NNSEiI6dq1q3n11VcbaUZNU0Oc544dO572mDNmzGi8iTUxDfXP838iEH3PYQxr7QAAwN64hggAANgegQgAANgegQgAANgegQgAANgegQgAANgegQgAANgegQgAANgegQgAANgegQhAQKWlpSkrK6vO9Xv37pXD4VBhYWGD9XQ+8Pe8AnbHr90DNnb48GHFxMTI6/UqNDRULpdLu3fv1iWXXHLGfW677TYdOXJEr7/+er308NprrykkJKTO9bGxsSouLla7du3q5fMBQCIQAba2YcMGXXnllQoLC9PGjRvVtm3bs4Yhf5w4caJOQadt27Z+HTcoKEhut/tc2wKA0+IrM8DG1q9fr759+0qS1q5da/35TGbOnKnnnntOf//73+VwOORwOLRmzRrra6y//e1vSktL0wUXXKAXXnhBX3/9tW666SZ16NBBYWFhSkxM1EsvveRzzFO/2unUqZOys7N1xx13KDw8XJdccomeeuopa/upX5mtWbNGDodD7777rpKSkhQWFqbU1FTt2bPH53MeffRRRUVFKTw8XOPGjdMDDzygK6+88qzz3bVrl66//nq1bt1a0dHRyszM1FdffWV9bmhoqD744AOr/vHHH1e7du1UXFwsScrJydFPfvITXXjhhYqMjNTw4cP12Wef1ZrL3/72N/Xr108tW7bU1VdfrY8//libN29WUlKSWrduraFDh+rw4cPWfrfddptuuOEGPfzww4qKilJERITuuusuVVVVnXEuVVVVmjZtmi6++GK1atVKycnJWrNmjbV93759GjFihNq0aaNWrVrpiiuu0KpVq856foDzSqB/XRZA49q3b59xuVzG5XKZkJAQc8EFFxiXy2VCQ0ON0+k0LpfL/Nd//ddp9y0vLzejRo0yQ4cONcXFxaa4uNhUVlaaoqIiI8l06tTJvPrqq+bzzz83X375pTlw4IB57LHHzNatW81nn31mnnjiCRMUFGTy8/OtY/bv39/ce++91vuOHTuatm3bmv/93/81n3zyiZk1a5Zp0aKF2b17tzHGWJ+1detWY8z//Rp4cnKyWbNmjdm5c6fp16+fSU1NtY75wgsvmAsuuMD85S9/MXv27DEPP/ywiYiIMD179jzjeTp48KBp166dmT59utm9e7fZsmWLGTRokLnuuuusmt/85jemY8eO5siRI6awsNA4nU7z2muvWdtfeeUV8+qrr5qPP/7YbN261YwYMcIkJiaa6upqn7l07drV5OTkmF27dpk+ffqYq666yqSlpZm1a9eaLVu2mMsuu8zcfffd1nHHjBljWrdubUaPHm127Nhh/vnPf5qLLrrI/Pa3vz3jec3IyDCpqanm/fffN59++ql57LHHjNPpNB9//LExxphhw4aZQYMGmW3btpnPPvvM/OMf/zB5eXlnPD/A+YZABNjMiRMnTFFRkfn3v/9tQkJCTGFhofn0009N69atTV5enikqKjKHDx8+4/5jxowxI0eO9Bk7+Rf7ggULfvDzr7/+ejNlyhTr/ekC0S233GK9r6mpMVFRUWbRokU+n3VqIHrnnXesfd58800jyVRUVBhjjElOTjYTJkzw6aNv375nDUS/+93vzODBg33G9u/fbySZPXv2GGOMqaysNL169TKjRo0yV1xxhRk3btxZ515SUmIkme3bt/vM5emnn7ZqXnrpJSPJvPvuu9bYrFmzTHx8vPV+zJgxpm3btubYsWPW2KJFi0zr1q2tsPWf5/XTTz81DofDfPnllz79DBgwwEyfPt0YY0xiYqKZOXPmWfsHzmd8ZQbYTHBwsDp16qSPPvpIV199tXr27CmPx6Po6Ghde+216tSp0zlfsJyUlOTzvrq6Wn/4wx/Uo0cPRUZGqnXr1srNzdUXX3xx1uP06NHD+rPD4ZDb7VZJSUmd92nfvr0kWfvs2bNH11xzjU/9qe9PVVBQoPfee0+tW7e2Xl27dpUk62uv0NBQvfDCC3r11VdVUVGhBQsW+Bzjs88+U0ZGhi699FJFRESoc+fOklRr/v/Ze3R0tCQpMTHRZ+zU+ffs2VNhYWHW+5SUFB09elT79++vNZctW7bIGKPLL7/cZz55eXnWXCZNmqRHH31Uffv21YwZM7Rt27aznh/gfMNF1YDNXHHFFdq3b59OnDihmpoatW7dWt99952+++47tW7dWh07dtTOnTvP6ditWrXyef/4449r/vz5WrBggRITE9WqVStlZWWd9VoXSbUuxnY4HKqpqanzPg6HQ5J89jk5dpIx5qzHq6mp0YgRIzRnzpxa204GLun767Ak6ZtvvtE333zjcw5GjBih2NhYLVmyRDExMaqpqVFCQkKt+Z+u91PHfmj+p+5/6lyCgoJUUFCgoKAgn22tW7eWJI0bN05DhgzRm2++qdzcXM2aNUuPP/64Jk6cWKfPBZo7VogAm1m1apUKCwvldrv1wgsvqLCwUAkJCVqwYIEKCwt/8ELa0NBQVVdX1+mzPvjgA40cOVK33HKLevbsqUsvvVSffPJJfUzDL/Hx8dq0aZPP2IcffnjWfa666irt3LlTnTp10mWXXebzOhl6PvvsM913331asmSJ+vTpo1tvvdUKLl9//bV2796thx56SAMGDFC3bt1UWlpab3P697//rYqKCut9fn6+WrdurQ4dOtSq7dWrl6qrq1VSUlJrLv95x15sbKzuvvtuvfbaa5oyZYqWLFlSb/0CTR2BCLCZjh07qnXr1jp06JBGjhypSy65RLt27dKNN96oyy67TB07djzr/p06ddK2bdu0Z88effXVVzpx4sQZay+77DKtXr1a69ev1+7du3XXXXfJ4/HU95R+0MSJE/XMM8/oueee0yeffKJHH31U27ZtO+1qykkTJkzQN998o5tuukmbNm3S559/rtzcXN1xxx2qrq5WdXW1MjMzNXjwYN1+++169tlntWPHDj3++OOSpDZt2igyMlJPPfWUPv30U/3rX//S5MmT621OVVVVGjt2rHbt2qW33npLM2bM0K9//Wu1aFH7P+uXX365br75Zt1666167bXXVFRUpM2bN2vOnDlWAM7KytLbb7+toqIibdmyRf/617/UrVu3eusXaOoIRIANrVmzRldffbUuuOACbdy4URdffLFiYmLqtO/48eMVHx+vpKQkXXTRRVq3bt0Za3/3u9/pqquu0pAhQ5SWlia3260bbrihnmZRdzfffLOmT5+uqVOn6qqrrlJRUZFuu+02XXDBBWfcJyYmRuvWrVN1dbWGDBmihIQE3XvvvXK5XGrRooX+8Ic/aO/evdYjAdxut55++mk99NBDKiwsVIsWLbRixQoVFBQoISFB9913nx577LF6m9OAAQMUFxena6+9VqNGjdKIESM0c+bMM9Y/++yzuvXWWzVlyhTFx8crPT1dGzduVGxsrKTvr/eaMGGCunXrpqFDhyo+Pl5PPvlkvfULNHUO80NfpAPAeWjQoEFyu91atmxZoFvxW30/LRwAF1UDsIHjx4/rz3/+s4YMGaKgoCC99NJLeuedd7R69epAtwagiSAQATjvORwOrVq1So8++qgqKysVHx+vV199VQMHDgx0awCaCL4yAwAAtsdF1QAAwPYIRAAAwPYIRAAAwPYIRAAAwPYIRAAAwPYIRAAAwPYIRAAAwPYIRAAAwPb+P+kWOA/xufRRAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lengths = [len(w) for w in weights]\n", "\n", "plt.hist(lengths, 10)\n", "plt.xlabel(\"# training examples\")\n", "plt.ylabel(\"# test examples\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "0a0cee7d-19f9-478a-a274-33c0db85690d", "metadata": {}, "source": [ "Let us compare the predictive performance of the original and the constrained predictions." ] }, { "cell_type": "code", "execution_count": 24, "id": "18b415d4-1ecf-4864-a17b-266748786e61", "metadata": {}, "outputs": [], "source": [ "rf_predicted_labels = np.array([rf.classes_[p.argmax()] for p in rf_predictions])\n", "rfx_predicted_labels = np.array([rfx.classes_[p.argmax()] for p in rfx_predictions_k])" ] }, { "cell_type": "code", "execution_count": 25, "id": "74871887-5c44-4f94-9874-18b3a6c3f6d5", "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", "
AccuracyAUC
Original0.9650.999
k=100.9320.999
\n", "
" ], "text/plain": [ " Accuracy AUC\n", "Original 0.965 0.999\n", "k=10 0.932 0.999" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from sklearn.metrics import roc_auc_score, accuracy_score\n", "\n", "accuracy_orig = accuracy_score(y_test, rf_predicted_labels)\n", "auc_orig = roc_auc_score(y_test, rf_predictions, average='weighted',\n", " multi_class='ovr', labels=rf.classes_)\n", "\n", "roc_auc_score(y_test == rf.classes_[1], \n", " rf_predictions[:,1])\n", "\n", "accuracy_k = accuracy_score(y_test, rfx_predicted_labels)\n", "auc_k = roc_auc_score(y_test, rfx_predictions, average='weighted',\n", " multi_class='ovr', labels=rfx.classes_)\n", "\n", "df_result = pd.DataFrame([[accuracy_orig, auc_orig],[accuracy_k, auc_k]], \n", " index=[\"Original\", f\"k={k}\"], \n", " columns=[\"Accuracy\", \"AUC\"])\n", "\n", "display(df_result.round(3))" ] }, { "cell_type": "markdown", "id": "b58948f8-2dbd-4bcd-90e8-5c592bd67c7e", "metadata": {}, "source": [ "Let us take a look at the training examples that are used for some prediction." ] }, { "cell_type": "code", "execution_count": 26, "id": "b7260842-cd64-44cd-8fd8-2dc35119dc54", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test example:\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Original prediction
 0123456789
0.030.010.580.030.080.030.170.010.060.01
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "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", "
Constrained prediction
 0123456789
0.000.000.470.100.090.090.160.000.080.00
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training examples:\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxsAAAFICAYAAAA4W+O5AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABJ7klEQVR4nO3dZ3hU1drG8WfSEwgJJZQgXaU3qQpIFwQUFFHxqAiCiAhiOYgoIioWOChSFAFRUBBFBAsIIXTp2CiCdJAOoYeSBNb7wQPv2Xk2mWEyOzMJ/9915cO6WXvPGvJkZ1Zm1l4uY4wRAAAAAPCxIH8PAAAAAEDOxGQDAAAAgCOYbAAAAABwBJMNAAAAAI5gsgEAAADAEUw2AAAAADiCyQYAAAAARzDZAAAAAOAIJhsAAAAAHJHtJxtbtmyRF154QWrUqCGxsbGSL18+qVevnnzzzTf+HlqmpaamyqBBg6RkyZISHh4u5cqVk5EjR3p07OnTp6Vv375yxx13SFxcnLhcLnnttdcyfKz33ntPKleuLJGRkRIbGyu33XabLF++3EfPJmei/ux5Wn8XL16U9957T1q2bCk33HCDREVFSfny5aVfv35y4sQJ3z6hHCo5OVkefPBBKVu2rERHR0uuXLmkYsWK8uabb0pycrK/h5cpWXkN/PXXX6VZs2aSO3duiY2NlXvvvVd27Njho2eSc3ENtEf9+ceff/4p4eHh4nK5ZO3atf4eTqZkpv5ERM6cOSN9+vSR+Ph4iYiIkGrVqsnUqVNVP2OMjBgxQsqVKyfh4eFSpEgR6dGjhxw/ftx3T8ZkcyNHjjTlypUzgwcPNgkJCWb27NmmU6dORkTMoEGD/D28TOnatasJDw83Q4YMMQsXLjT9+vUzLpfLDB482O2xO3fuNDExMeb22283Xbt2NSJiBg4caNs3LS3NtG7d2sTExJjBgwebhQsXmh9//NEMGjTIJCQk+PhZ5SzUnz1P6+/06dMmOjraPPHEE2batGlm4cKFZtiwYSZv3rymQoUK5uzZsw48s5zl+PHj5v777zdjxowxc+fONfPmzTMDBgwwoaGhpmnTpv4eXqZk1TVw06ZNJjo62jRo0MDMmjXLTJ8+3VSsWNHEx8ebw4cP+/hZ5SxcA+1Rf1kvLS3N1KlTx8THxxsRMWvWrPH3kDIlM/VnjDHNmzc3sbGxZsyYMWbBggVX6nDy5MmWfs8995wJCgoyffv2NQkJCWb48OEmT548pkaNGiYlJcUnzyXbTzaOHDliLl26pPLWrVubqKgoc/78eT+MKvM2bNhgXC6Xeeuttyx5t27dTGRkpElKSsrw+EuXLl35fzly5EiGF7r333/fBAUFmRUrVvhk7NcT6s+ep/WXlpZmjh49qvJp06YZETGff/6590/iOte3b18jImb79u3+HopXsvIa2KFDB1OgQAFz8uTJK9muXbtMaGio6du3b+aeSA7HNdAe9Zf1hg4daooWLWo++OCDbD/ZyGz9zZo1y4iImTJliiVv3ry5iY+PN2lpacYYY/bu3WuCg4NNr169LP2mTJliRMSMHTvWB8/GGK8+RrV06VJxuVzy5Zdfqn+bNGmSuFwuWbNmjTenvmYFChQQl8ul8tq1a8vZs2fl2LFjVz321KlTEhISIkOHDr2SHT16VIKCgiQmJkbS0tKu5L1795a4uDgxxvj2CVzFzJkzxRgjnTt3tuSdO3eWc+fOyZw5czI83uVy2f6/2Pnggw/k9ttvl7p163o93qxE/Tkvq+ovODhY8ufPr/LatWuLiMjff/99DaPOOoFUg1cTFxcnIiIhISFX7UMNiqSlpcmPP/4o7du3lzx58lzJS5QoIY0bN5YZM2Z49wQcFEj1xzXQHvWXtde/rVu3yquvvioffvih5f8xIzm5/mbMmCG5c+eWDh06qOP3798vq1atEhGRlStXysWLF6VVq1aWfm3atBERkenTp2f2qYiIl2s2GjRoINWrV5fRo0erfxs1apTUqlVLatWqleE50tLSPPry9hu7cOFCiYuLk4IFC161T548eaRWrVqSmJh4JZs/f76Eh4fL6dOnZfXq1VfyxMREadKkSYYXD2OMx8/LnQ0bNkhcXJwULlzYklepUuXKv/vC33//Lbt27ZLKlStL//79pVChQhISEiIVK1aUiRMn+uQxfI36s5cd6+9qFixYICIiFStWdPRxvBWINXj5+3/q1CmZM2eODBs2TDp27CjFixe/6jHUoMj27dvl3LlzV86b/rG2bdsm58+f98lj+Uog1l96XAM9Q/1lvv6MMdK1a1dp06aN3H333R4/j5xcfxs2bJDy5curPzalPz4lJUVERMLDwy39QkNDxeVyybp169yO1RNeLxDv3bu3LFu2TH7//fcr2Zo1a2TNmjXy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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "test_index = 5 # Select any test example\n", "\n", "print(\"Test example:\")\n", "test_pixels = X_test[test_index].reshape((28, 28))\n", "\n", "plt.figure(figsize=(2,2))\n", "plt.imshow(test_pixels, cmap='Blues')\n", "plt.axis('off')\n", "plt.text(0.1, 0.1, r\"$\\hat{y}$\" +f\" = {rfx_predicted_labels[test_index]} y = {y_test[test_index]}\", \n", " fontsize = 12)\n", "plt.show()\n", "\n", "df = pd.DataFrame([rf_predictions[test_index]], index = [\"\"], columns=rf.classes_)\n", "display(df.style.format(precision=2).set_caption(\"Original prediction\").set_table_styles(Styles))\n", "\n", "df = pd.DataFrame([rfx_predictions_k[test_index]], index = [\"\"], columns=rfx.classes_)\n", "display(df.style.format(precision=2).set_caption(\"Constrained prediction\").set_table_styles(Styles))\n", " \n", "print(\"Training examples:\")\n", "\n", "no_rows = 2\n", "no_cols = 5\n", "\n", "fig, axs = plt.subplots(no_rows, no_cols, figsize=(10, 4))\n", "\n", "for i, train_ind in enumerate(examples[test_index]):\n", " pixels = X_train[train_ind].reshape((28, 28))\n", " row = i // no_cols\n", " col = i % no_cols\n", " axs[row, col].imshow(pixels, cmap='Blues')\n", " axs[row, col].axis('off')\n", " axs[row, col].text(0.1, 0.5, f\"y = {y_train[train_ind]} w = {weights[test_index][i]:.2f}\", fontsize = 12)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "29cca630-4862-4c67-9382-82a956ee9d7a", "metadata": {}, "source": [ "## Regression forests" ] }, { "cell_type": "markdown", "id": "a45a8c60-1702-4443-b62e-d7aecb32a299", "metadata": {}, "source": [ "### Miami housing" ] }, { "cell_type": "markdown", "id": "a652da4e-eb5b-4e81-a8cd-af48fbe3431b", "metadata": {}, "source": [ "Let us import the Miami housing dataset from [openml.org](https://www.openml.org)." ] }, { "cell_type": "code", "execution_count": 27, "id": "60704d14-44e9-4309-a0d0-5cbafea0878a", "metadata": {}, "outputs": [], "source": [ "from sklearn.datasets import fetch_openml\n", "from sklearn.preprocessing import OneHotEncoder\n", "\n", "dataset = fetch_openml(name=\"miami_housing\", parser=\"auto\")\n", "\n", "y = dataset.target.values\n", "X = dataset.data.values" ] }, { "cell_type": "markdown", "id": "29ad9c8f-b4dc-4003-9db6-fc7cfef37fe9", "metadata": {}, "source": [ "Let us split the dataset into a training and a test set." ] }, { "cell_type": "code", "execution_count": 28, "id": "ae2e940e-4ac9-43fd-b322-f0cc0cc8014a", "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.75)" ] }, { "cell_type": "markdown", "id": "ee952923-e822-4f50-abc7-b39f6011967e", "metadata": {}, "source": [ "Let us first generate a standard random forest regressor and apply it to the test set." ] }, { "cell_type": "code", "execution_count": 29, "id": "8eddddef-ec92-4a00-b859-3bed50a36680", "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestRegressor\n", "import numpy as np\n", "\n", "np.random.seed(42)\n", "\n", "rf = RandomForestRegressor(n_jobs=-1, n_estimators=500)\n", "rf.fit(X_train, y_train)\n", "rf_predictions = rf.predict(X_test)" ] }, { "cell_type": "markdown", "id": "36c11805-9e43-4f09-9287-9171c2aa1296", "metadata": {}, "source": [ "Similarly, we may generate and apply an explainable random forest regressor, here without constraining the number of training examples involved in the predictions." ] }, { "cell_type": "code", "execution_count": 30, "id": "4b5d4c65-ee99-454e-bf94-2a3e941c180c", "metadata": {}, "outputs": [], "source": [ "from xrf import XRandomForestRegressor\n", "\n", "np.random.seed(42)\n", "\n", "rfx = XRandomForestRegressor(n_jobs=-1, n_estimators=500)\n", "rfx.fit(X_train, y_train)\n", "rfx_predictions = rfx.predict(X_test)" ] }, { "cell_type": "markdown", "id": "cfb2b391-1b5a-46af-9016-e6455aa4b979", "metadata": {}, "source": [ "Let us check that we indeed get the same predictions." ] }, { "cell_type": "code", "execution_count": 31, "id": "a0bccef9-c0cf-4c8c-8585-6d089fc5bdb5", "metadata": {}, "outputs": [], "source": [ "assert np.allclose(rf_predictions, rfx_predictions)" ] }, { "cell_type": "markdown", "id": "96925512-8924-4541-8dd2-9c6f0f35dd84", "metadata": {}, "source": [ "We may now limit the number of examples involved in a prediction, e.g., to at most 5 (`k=5`)." ] }, { "cell_type": "code", "execution_count": 32, "id": "77718b0a-fffe-4f52-8c9c-6ee9205376df", "metadata": {}, "outputs": [], "source": [ "k=5\n", "\n", "rfx_predictions_k, examples, weights = rfx.predict(X_test, \n", " k=k,\n", " return_examples=True, \n", " return_weights=True)" ] }, { "cell_type": "markdown", "id": "3b44b5ef-f414-490b-8151-b78c3cfe7ddf", "metadata": {}, "source": [ "Let us compare the correctness of the constrained and original predictions." ] }, { "cell_type": "code", "execution_count": 33, "id": "c9798013-e5e0-438b-b722-56d263437fa0", "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", "
RMSECORR
Original111896.5710.941
k=5113617.6110.936
\n", "
" ], "text/plain": [ " RMSE CORR\n", "Original 111896.571 0.941\n", "k=5 113617.611 0.936" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from sklearn.metrics import mean_squared_error\n", "\n", "rmse_orig = np.sqrt(mean_squared_error(y_test, rf_predictions))\n", "corr_orig = np.corrcoef(y_test, rf_predictions)[0,1]\n", "\n", "rmse_k = np.sqrt(mean_squared_error(y_test, rfx_predictions_k))\n", "corr_k = np.corrcoef(y_test, rfx_predictions_k)[0,1]\n", "\n", "df_result = pd.DataFrame([[rmse_orig, corr_orig],[rmse_k, corr_k]], \n", " index=[\"Original\", f\"k={k}\"], \n", " columns=[\"RMSE\", \"CORR\"])\n", "\n", "display(df_result.round(3))" ] }, { "cell_type": "markdown", "id": "7f08010e-2752-41df-afa9-14e74e652c82", "metadata": {}, "source": [ "Let us take a look at the training examples that are used for some prediction." ] }, { "cell_type": "code", "execution_count": 34, "id": "7242bd67-e2bc-4134-85ab-252266d12b60", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original prediction: 137202.8\n", "Constrained prediction: 128643.4\n" ] }, { "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", " \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", "
 Test#1#2#3#4#5
Target133 000.00168 000.00115 000.00115 000.00120 000.0081 500.00
Weight 0.330.200.190.150.14
LATITUDE25.8925.9025.8925.8925.8825.86
LONGITUDE-80.23-80.23-80.24-80.23-80.23-80.23
LND_SQFOOT7 575.008 925.007 200.008 100.005 300.008 025.00
TOT_LVG_AREA1 176.001 251.001 170.00884.001 264.001 178.00
SPEC_FEAT_VAL1 512.001 176.003 088.000.000.002 197.00
RAIL_DIST4 979.205 150.202 972.905 511.107 500.905 401.80
OCEAN_DIST35 765.4035 205.0037 758.6035 228.3035 436.7035 229.30
WATER_DIST2 692.602 457.80497.703 187.402 060.703 323.60
CNTR_DIST43 454.6044 715.8043 128.1043 460.0037 986.1030 764.50
SUBCNTR_DI43 454.6044 715.8043 128.1043 460.0037 986.1030 764.50
HWY_DIST6 964.906 394.708 940.206 429.306 332.905 949.80
age63.0063.0055.0063.0076.0059.00
avno60plus0.000.000.000.000.000.00
month_sold3.002.001.0010.003.003.00
structure_quality4.004.004.004.004.004.00
\n" ], "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test_index = 0 # Select any test example\n", "#test_index = np.argwhere(rfx_predicted_labels != y_test)[1,0] # Select a misclassified test example\n", "#test_index = np.argwhere(rfx_predicted_labels != rf_predicted_labels)[2,0] # Select a test example on which there is disagreement\n", "\n", "import pandas as pd\n", "\n", "print(f\"Original prediction: {rf_predictions[test_index]:.1f}\")\n", "print(f\"Constrained prediction: {rfx_predictions_k[test_index]:.1f}\")\n", "\n", "df = pd.DataFrame(np.hstack((np.vstack((y_test[test_index], np.nan, X_test[test_index].reshape(-1,1))),\n", " np.hstack((y_train[examples[test_index]].reshape(k,1),\n", " weights[test_index].reshape(k,1),\n", " X_train[examples[test_index]])).T)),\n", " index = [\"Target\", \"Weight\"]+dataset.feature_names, \n", " columns=[\"Test\"]+[\"#\"+str(i+1) for i in range(k)])\n", "\n", "df.apply(pd.to_numeric).style.format(precision=2, thousands=\" \", na_rep=\" \").\\\n", " background_gradient(cmap=\"Reds\", axis=1)" ] }, { "cell_type": "markdown", "id": "11cbe77c-fa9e-4fa6-b7a5-65c2eb83362e", "metadata": { "tags": [] }, "source": [ "### Lipophilicty" ] }, { "cell_type": "code", "execution_count": 35, "id": "39bc24a7-b9a6-4486-a160-f90760162c6a", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(4200, 1024)\n" ] } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "import rdkit\n", "from rdkit.Chem import AllChem\n", "\n", "url = (\"https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/\"\n", " \"Lipophilicity.csv\")\n", "\n", "df = pd.read_csv(url)\n", "\n", "y = df[\"exp\"].values\n", "\n", "molecules = [rdkit.Chem.MolFromSmiles(s) for s in df[\"smiles\"]]\n", "\n", "fpgen = AllChem.GetMorganGenerator(radius=2, fpSize=1024)\n", "\n", "X = np.array([fpgen.GetFingerprint(m) for m in molecules])\n", "\n", "print(X.shape)" ] }, { "cell_type": "markdown", "id": "2b6040ee-adf1-4f42-9caf-4cc561091280", "metadata": {}, "source": [ "Let us split the dataset into a training and a test set." ] }, { "cell_type": "code", "execution_count": 36, "id": "a194e8a6-eebc-4b08-8ae5-ebe25c72d70a", "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "X_train, X_test, y_train, y_test, molecules_train, molecules_test = \\\n", " train_test_split(X, y, molecules, test_size=0.75)" ] }, { "cell_type": "markdown", "id": "fe0fba43-ad21-4c69-b9d6-cb6e0b6e83ff", "metadata": {}, "source": [ "Let us first generate a standard random forest regressor and apply it to the test set." ] }, { "cell_type": "code", "execution_count": 37, "id": "65f44d6a-f313-426e-b35d-21b39ebcd480", "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestRegressor\n", "import numpy as np\n", "\n", "np.random.seed(42)\n", "\n", "rf = RandomForestRegressor(n_estimators=500, n_jobs=-1)\n", "rf.fit(X_train, y_train)\n", "rf_predictions = rf.predict(X_test)" ] }, { "cell_type": "markdown", "id": "ef93690d-af0f-4a90-a807-d9a86abbf2f1", "metadata": {}, "source": [ "Similarly, we may generate and apply an explainable random forest regressor, here without constraining the number of training examples involved in the predictions." ] }, { "cell_type": "code", "execution_count": 38, "id": "b32db676-2247-4741-bdb3-2f9ae27648c9", "metadata": {}, "outputs": [], "source": [ "from xrf import XRandomForestRegressor\n", "\n", "np.random.seed(42)\n", "\n", "rfx = XRandomForestRegressor(n_estimators=500, n_jobs=-1)\n", "rfx.fit(X_train, y_train)\n", "rfx_predictions = rfx.predict(X_test)" ] }, { "cell_type": "markdown", "id": "0438fb0f-7d30-4917-be06-2e68fcb5671d", "metadata": {}, "source": [ "Let us check that we indeed get the same predictions." ] }, { "cell_type": "code", "execution_count": 39, "id": "1a9863bf-3b2f-4d36-b9aa-a973c8efbd93", "metadata": {}, "outputs": [], "source": [ "assert np.allclose(rf_predictions, rfx_predictions)" ] }, { "cell_type": "markdown", "id": "7fd1c815-68c4-4909-932d-55fcf3eeef94", "metadata": {}, "source": [ "We may now limit the number of examples involved in a prediction, e.g., to at most 10 (`k=10`)." ] }, { "cell_type": "code", "execution_count": 40, "id": "ae78175e-fb31-4adf-9e97-a9dcd5525acc", "metadata": {}, "outputs": [], "source": [ "k=10\n", "\n", "rfx_predictions_k, examples, weights = rfx.predict(X_test, \n", " k=k,\n", " return_examples=True, \n", " return_weights=True)" ] }, { "cell_type": "markdown", "id": "da09313b-be84-4aa0-9ce1-055d0311cdd9", "metadata": {}, "source": [ "Let us compare the correctness of the constrained and original predictions." ] }, { "cell_type": "code", "execution_count": 41, "id": "63723f51-ceea-4b8a-b627-4d16e76f3448", "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", "
RMSECORR
Original0.9690.602
k=101.0130.567
\n", "
" ], "text/plain": [ " RMSE CORR\n", "Original 0.969 0.602\n", "k=10 1.013 0.567" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from sklearn.metrics import mean_squared_error\n", "\n", "rmse_orig = np.sqrt(mean_squared_error(y_test, rf_predictions))\n", "corr_orig = np.corrcoef(y_test, rf_predictions)[0,1]\n", "\n", "rmse_k = np.sqrt(mean_squared_error(y_test, rfx_predictions_k))\n", "corr_k = np.corrcoef(y_test, rfx_predictions_k)[0,1]\n", "\n", "df_result = pd.DataFrame([[rmse_orig, corr_orig],[rmse_k, corr_k]], \n", " index=[\"Original\", f\"k={k}\"], \n", " columns=[\"RMSE\", \"CORR\"])\n", "\n", "display(df_result.round(3))" ] }, { "cell_type": "markdown", "id": "208ae1a6-5855-447d-9183-4227bd88ca6b", "metadata": {}, "source": [ "Let us take a look at some test example and the training examples that are used for the prediction." ] }, { "cell_type": "code", "execution_count": 42, "id": "ac7da1c7-3506-4abf-a38b-cabdb748029b", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "from rdkit import Chem\n", "from rdkit.Chem.Draw import IPythonConsole\n", "from rdkit.Chem import Draw\n", "from rdkit.Chem import rdFMCS\n", "from rdkit.Chem.Draw import rdDepictor\n", "\n", "IPythonConsole.ipython_useSVG=False\n", "IPythonConsole.drawOptions.minFontSize=20\n", "\n", "rdDepictor.SetPreferCoordGen(True)\n", "\n", "def show_difference(mol1, w, y, mol2):\n", " mcs = rdFMCS.FindMCS([mol1,mol2])\n", " mcs_mol = Chem.MolFromSmarts(mcs.smartsString)\n", " match1 = mol1.GetSubstructMatch(mcs_mol)\n", " target_atm1 = []\n", " for atom in mol1.GetAtoms():\n", " if atom.GetIdx() not in match1:\n", " target_atm1.append(atom.GetIdx())\n", " return Draw.MolsToGridImage([mol1],\n", " highlightAtomLists=[target_atm1], \n", " useSVG=True)" ] }, { "cell_type": "code", "execution_count": 43, "id": "3a1e8668-3b29-49e6-9d1b-9e2e94483679", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test molecule:\n" ] }, { "data": { "image/svg+xml": [ "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "True target: 1.42\n", "Original prediction: 2.28\n", "Constrained prediction: 2.58\n", "\n", "Training example 1 [2.5, weight: 0.22]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 2 [3.77, weight: 0.19]\n" ] }, { "data": { "image/svg+xml": [ "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 3 [2.7, weight: 0.11]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 4 [1.85, weight: 0.08]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 5 [2.8, weight: 0.08]\n" ] }, { "data": { "image/svg+xml": [ "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 6 [2.39, weight: 0.07]\n" ] }, { "data": { "image/svg+xml": [ "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 7 [3.4, weight: 0.07]\n" ] }, { "data": { "image/svg+xml": [ "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 8 [1.4, weight: 0.06]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 9 [1.09, weight: 0.05]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\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", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Training example 10 [1.3, weight: 0.05]\n" ] }, { "data": { "image/svg+xml": [ "\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", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "test_index = 5 # Select any test example\n", "\n", "print(\"Test molecule:\")\n", "test_mol = molecules_test[test_index]\n", "test_mol_fig = Draw.MolsToGridImage([test_mol], useSVG=True)\n", "display(test_mol_fig)\n", "print(f\"True target: {y_test[test_index]:.2f}\")\n", "print(f\"Original prediction: {rf_predictions[test_index]:.2f}\")\n", "print(f\"Constrained prediction: {rfx_predictions_k[test_index]:.2f}\\n\")\n", "\n", "for i, training_index in enumerate(examples[test_index]):\n", " print(f\"Training example {i+1} \"\n", " f\"[{y_train[training_index]}, \" \n", " f\"weight: {weights[test_index][i]:.2f}]\") \n", " training_mol = molecules_train[training_index]\n", " train_mol_fig = show_difference(training_mol, weights[test_index][i], \n", " y_train[training_index], test_mol)\n", " display(train_mol_fig)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.5" } }, "nbformat": 4, "nbformat_minor": 5 }