{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "373fd5ec", "metadata": { "cell_id": "dc6f466fd2994dbc80cf4e4da3be362f", "deepnote_cell_height": 83.5, "deepnote_cell_type": "markdown", "tags": [] }, "source": [ "# `RobustOCT` Examples" ] }, { "attachments": {}, "cell_type": "markdown", "id": "65b403f6", "metadata": { "cell_id": "00001-5aa34266-f09d-41a6-aea8-7d1b5d36257a", "deepnote_cell_height": 144.796875, "deepnote_cell_type": "markdown", "owner_user_id": "3c75c737-6c37-465a-aa9b-4b298c75816b" }, "source": [ "\n", "\n", "## Example 1: Synthetic Data Without Specified Shifts\n", "If costs and/or budget is not specified, then we will produce the same result as an optimal strong classification tree.\n", "\n", "As an example, say that we are given this training set:" ] }, { "cell_type": "code", "execution_count": 27, "id": "22254eb6", "metadata": { "cell_id": "00002-ec1b8b46-8347-44be-88eb-d2c0ff104528", "deepnote_cell_height": 508, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 1198, "execution_start": 1664769662078, "source_hash": "986acf91" }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from odtlearn.robust_oct import RobustOCT\n", "\n", "\"\"\"\n", " X2\n", " | |\n", " | |\n", " 1 + + | -\n", " | | \n", " |---------------|-------------\n", " | |\n", " 0 - - - - | + + +\n", " | - - - |\n", " |______0________|_______1_______X1\n", "\"\"\"\n", "X = np.array(\n", " [\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [1, 0],\n", " [1, 0],\n", " [1, 0],\n", " [1, 1],\n", " [0, 1],\n", " [0, 1],\n", " ]\n", ")\n", "X = pd.DataFrame(X, columns=[\"X1\", \"X2\"])\n", "\n", "y = np.array([0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1])" ] }, { "attachments": {}, "cell_type": "markdown", "id": "87b66e70", "metadata": { "cell_id": "f5d869ce3ae0415ca6b86aab044f6460", "deepnote_cell_height": 74.796875, "deepnote_cell_type": "markdown", "owner_user_id": "2bc00ffa-8da0-4406-b26d-9986ca85f208", "tags": [] }, "source": [ "If either `costs` or `budget` is not specified, the optimal classification tree will be produced (i.e., a tree that does not account for distribution shifts)." ] }, { "cell_type": "code", "execution_count": 28, "id": "bccf620c", "metadata": { "cell_id": "00003-ba6613f0-07d0-4855-badb-8ab0fcfd487c", "deepnote_cell_height": 250.6875, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 565, "execution_start": 1664769682643, "scrolled": true, "source_hash": "7db50d93" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2024-06-27\n", "Set parameter TimeLimit to value 100\n", "Set parameter NodeLimit to value 1073741824\n", "Set parameter SolutionLimit to value 1073741824\n", "Set parameter LazyConstraints to value 1\n", "Set parameter IntFeasTol to value 1e-06\n", "Set parameter Method to value 3\n", "Gurobi Optimizer version 10.0.2 build v10.0.2rc0 (mac64[arm])\n", "\n", "CPU model: Apple M1 Pro\n", "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 7 rows, 33 columns and 20 nonzeros\n", "Model fingerprint: 0x78ba3dea\n", "Variable types: 13 continuous, 20 integer (20 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [2e-01, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n", "Presolve removed 4 rows and 4 columns\n", "Presolve time: 0.01s\n", "Presolved: 3 rows, 29 columns, 12 nonzeros\n", "Variable types: 13 continuous, 16 integer (16 binary)\n", "Root relaxation presolved: 12 rows, 29 columns, 65 nonzeros\n", "\n", "\n", "Root relaxation: objective 1.300000e+01, 5 iterations, 0.00 seconds (0.00 work units)\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 13.00000 0 - - 13.00000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.50000 0 6 - 12.50000 - - 0s\n", "H 0 0 7.2500000 12.50000 72.4% - 0s\n", "H 0 0 10.5000000 12.50000 19.0% - 0s\n", " 0 0 12.38889 0 5 10.50000 12.38889 18.0% - 0s\n", " 0 0 12.25000 0 7 10.50000 12.25000 16.7% - 0s\n", " 0 0 12.25000 0 - 10.50000 12.25000 16.7% - 0s\n", "* 0 0 0 12.2500000 12.25000 0.00% - 0s\n", "\n", "Cutting planes:\n", " Gomory: 1\n", " MIR: 3\n", " Lazy constraints: 44\n", "\n", "Explored 1 nodes (32 simplex iterations) in 0.06 seconds (0.00 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 3: 12.25 10.5 7.25 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 1.225000000000e+01, best bound 1.225000000000e+01, gap 0.0000%\n", "\n", "User-callback calls 170, time in user-callback 0.02 sec\n" ] } ], "source": [ "from odtlearn.robust_oct import RobustOCT\n", " \n", "robust_classifier = RobustOCT(\n", " solver=\"gurobi\",\n", " depth = 2, \n", " time_limit = 100,\n", " )\n", "robust_classifier.fit(X, y)\n", "predictions = robust_classifier.predict(X)\n" ] }, { "cell_type": "code", "execution_count": 29, "id": "4f7e4e06", "metadata": { "cell_id": "8504ebdbd679412689f83492cd8f7a4f", "deepnote_cell_height": 362.734375, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 357, "execution_start": 1664769689116, "source_hash": "a3f1115a", "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#########node 1\n", "Feature: X2 , Cutoff: 0\n", "#########node 2\n", "Feature: X1 , Cutoff: 0\n", "#########node 3\n", "Feature: X1 , Cutoff: 0\n", "#########node 4\n", "leaf 0\n", "#########node 5\n", "leaf 1\n", "#########node 6\n", "leaf 1\n", "#########node 7\n", "leaf 0\n" ] } ], "source": [ "robust_classifier.print_tree()" ] }, { "cell_type": "code", "execution_count": 30, "id": "95997b6a", "metadata": { "cell_id": "272908eee5d346a3b82cf3a0aa62c4e1", "deepnote_cell_height": 552, "deepnote_cell_type": "code", "deepnote_output_heights": [ 406 ], "deepnote_to_be_reexecuted": false, "execution_millis": 1265, "execution_start": 1664769691141, "source_hash": "f06c109e", "tags": [] }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(10, 5))\n", "robust_classifier.plot_tree()\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "b73ea5f5", "metadata": { "cell_id": "00004-c066bdea-caf9-4089-9fa1-ee2e8d323ad6", "deepnote_cell_height": 231.984375, "deepnote_cell_type": "markdown" }, "source": [ "## Example 2: synthetic data with specified shifts\n", "\n", "We take the same synthetic data from Example 1, but now add distribution shifts with the following schema:\n", "- For 5 samples at $[0,0]$, pay a cost of 1 to perturb $X_1$ and get $[1,0]$\n", "- For the 1 sample at $[1,1]$, pay a cost of 1 to perturb $X_2$ to get $[1,0]$\n", "- All other perturbations are not allowed\n", "\n", "First, define these costs, which have the same shape and features as your input sample." ] }, { "cell_type": "code", "execution_count": 31, "id": "5816b3a0", "metadata": { "cell_id": "00005-ec8f4aac-e1c1-486b-a079-6d46a8a9ef3b", "deepnote_cell_height": 166, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 1, "execution_start": 1664769701276, "source_hash": "92e9e3b9" }, "outputs": [], "source": [ "# Note: 10 is a proxy for infinite cost, as it is over the allowed budgets we will specify\n", "costs = np.array([[1,10],[1,10],[1,10],[1,10],[1,10],[10,10],[10,10],\n", " [10,10],[10,10],[10,10],\n", " [10,1],\n", " [10,10],[10,10]])\n", "costs = pd.DataFrame(costs, columns=['X1', 'X2'])" ] }, { "attachments": {}, "cell_type": "markdown", "id": "e7a8b62b", "metadata": { "cell_id": "00006-17d04a3f-d99a-4770-8dd8-6a188182b3cb", "deepnote_cell_height": 74.796875, "deepnote_cell_type": "markdown" }, "source": [ "\n", "When the budget is 2 (corresponding to the variable ε), we don't see a change in the tree from Example 1 since for this dataset, the budget is small and thus the level of robustness is small." ] }, { "cell_type": "code", "execution_count": 32, "id": "1a79ac9d", "metadata": { "cell_id": "00007-e8bcdb8a-f74b-45a4-acd3-a7cb8592fb0a", "deepnote_cell_height": 400, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 308, "execution_start": 1664769713072, "scrolled": true, "source_hash": "9face3f" }, "outputs": [], "source": [ "# Same data as Example 1\n", "X = np.array(\n", " [\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [0, 0],\n", " [1, 0],\n", " [1, 0],\n", " [1, 0],\n", " [1, 1],\n", " [0, 1],\n", " [0, 1],\n", " ]\n", ")\n", "X = pd.DataFrame(X, columns=[\"X1\", \"X2\"])\n", "\n", "y = np.array([0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1])\n" ] }, { "cell_type": "code", "execution_count": 33, "id": "326b256a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2024-06-27\n", "Set parameter TimeLimit to value 100\n", "Set parameter NodeLimit to value 1073741824\n", "Set parameter SolutionLimit to value 1073741824\n", "Set parameter LazyConstraints to value 1\n", "Set parameter IntFeasTol to value 1e-06\n", "Set parameter Method to value 3\n", "Gurobi Optimizer version 10.0.2 build v10.0.2rc0 (mac64[arm])\n", "\n", "CPU model: Apple M1 Pro\n", "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 7 rows, 33 columns and 20 nonzeros\n", "Model fingerprint: 0x78ba3dea\n", "Variable types: 13 continuous, 20 integer (20 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [2e-01, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n", "Presolve removed 4 rows and 4 columns\n", "Presolve time: 0.00s\n", "Presolved: 3 rows, 29 columns, 12 nonzeros\n", "Variable types: 13 continuous, 16 integer (16 binary)\n", "Root relaxation presolved: 12 rows, 29 columns, 65 nonzeros\n", "\n", "\n", "Root relaxation: objective 1.300000e+01, 5 iterations, 0.00 seconds (0.00 work units)\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 13.00000 0 - - 13.00000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.50000 0 6 - 12.50000 - - 0s\n", "H 0 0 7.2500000 12.50000 72.4% - 0s\n", "H 0 0 8.5000000 12.50000 47.1% - 0s\n", " 0 0 12.38889 0 5 8.50000 12.38889 45.8% - 0s\n", " 0 0 12.27513 0 11 8.50000 12.27513 44.4% - 0s\n", " 0 0 12.25000 0 9 8.50000 12.25000 44.1% - 0s\n", "H 0 0 9.2500000 12.25000 32.4% - 0s\n", "H 0 0 9.5000000 12.25000 28.9% - 0s\n", " 0 0 12.25000 0 6 9.50000 12.25000 28.9% - 0s\n", " 0 0 12.25000 0 - 9.50000 12.25000 28.9% - 0s\n", " 0 0 12.23554 0 13 9.50000 12.23554 28.8% - 0s\n", " 0 0 12.22893 0 11 9.50000 12.22893 28.7% - 0s\n", "H 0 0 10.2500000 12.22893 19.3% - 0s\n", " 0 0 12.21106 0 11 10.25000 12.21106 19.1% - 0s\n", " 0 0 12.19909 0 11 10.25000 12.19909 19.0% - 0s\n", " 0 0 12.19909 0 11 10.25000 12.19909 19.0% - 0s\n", " 0 0 12.19909 0 11 10.25000 12.19909 19.0% - 0s\n", " 0 2 12.19909 0 11 10.25000 12.19909 19.0% - 0s\n", "\n", "Cutting planes:\n", " MIR: 5\n", " Lazy constraints: 61\n", "\n", "Explored 21 nodes (130 simplex iterations) in 0.05 seconds (0.01 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 5: 10.25 9.5 9.25 ... 7.25\n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 1.025000000000e+01, best bound 1.025000000000e+01, gap 0.0000%\n", "\n", "User-callback calls 257, time in user-callback 0.03 sec\n" ] } ], "source": [ "\n", "robust_classifier = RobustOCT(\n", " solver=\"gurobi\",\n", " depth=2,\n", " time_limit=100\n", ")\n", "robust_classifier.fit(X, y, costs=costs, budget=2)\n", "predictions = robust_classifier.predict(X)" ] }, { "cell_type": "code", "execution_count": 34, "id": "f92977d3", "metadata": { "cell_id": "9116a32b75b94436bfeedf91c1f77815", "deepnote_cell_height": 362.734375, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 2, "execution_start": 1664769714733, "source_hash": "a3f1115a", "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#########node 1\n", "Feature: X2 , Cutoff: 0\n", "#########node 2\n", "Feature: X1 , Cutoff: 0\n", "#########node 3\n", "Feature: X1 , Cutoff: 0\n", "#########node 4\n", "leaf 0\n", "#########node 5\n", "leaf 1\n", "#########node 6\n", "leaf 1\n", "#########node 7\n", "leaf 0\n" ] } ], "source": [ "robust_classifier.print_tree()" ] }, { "cell_type": "code", "execution_count": 35, "id": "0d6acd42", "metadata": { "cell_id": "4da674ada20e4400a2a3511f53d341b0", "deepnote_cell_height": 534, "deepnote_cell_type": "code", "deepnote_output_heights": [ 406 ], "deepnote_to_be_reexecuted": false, "execution_millis": 983, "execution_start": 1664769715734, "source_hash": "fbc9df0d", "tags": [] }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(10, 5)) \n", "robust_classifier.plot_tree()\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "0905099c", "metadata": { "cell_id": "00008-73938505-0bb7-4f8e-a9ef-b6b4e57515e0", "deepnote_cell_height": 52.390625, "deepnote_cell_type": "markdown" }, "source": [ "\n", "\n", "But when the budget is increased to 5 (adding more robustness), we see a change in the tree." ] }, { "cell_type": "code", "execution_count": 36, "id": "f8d8aa20", "metadata": { "cell_id": "00009-84267e8d-61ab-4b67-96a3-267ef2c17411", "deepnote_cell_height": 112, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 246, "execution_start": 1664769729224, "scrolled": true, "source_hash": "99f32af8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2024-06-27\n", "Set parameter TimeLimit to value 100\n", "Set parameter NodeLimit to value 1073741824\n", "Set parameter SolutionLimit to value 1073741824\n", "Set parameter LazyConstraints to value 1\n", "Set parameter IntFeasTol to value 1e-06\n", "Set parameter Method to value 3\n", "Gurobi Optimizer version 10.0.2 build v10.0.2rc0 (mac64[arm])\n", "\n", "CPU model: Apple M1 Pro\n", "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 7 rows, 33 columns and 20 nonzeros\n", "Model fingerprint: 0x78ba3dea\n", "Variable types: 13 continuous, 20 integer (20 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [2e-01, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n", "Presolve removed 4 rows and 4 columns\n", "Presolve time: 0.00s\n", "Presolved: 3 rows, 29 columns, 12 nonzeros\n", "Variable types: 13 continuous, 16 integer (16 binary)\n", "Root relaxation presolved: 12 rows, 29 columns, 65 nonzeros\n", "\n", "\n", "Root relaxation: objective 1.300000e+01, 5 iterations, 0.00 seconds (0.00 work units)\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 13.00000 0 - - 13.00000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.75000 0 - - 12.75000 - - 0s\n", " 0 0 12.50000 0 6 - 12.50000 - - 0s\n", "H 0 0 7.2500000 12.50000 72.4% - 0s\n", "H 0 0 8.0000000 12.50000 56.2% - 0s\n", " 0 0 12.38889 0 5 8.00000 12.38889 54.9% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 12.25000 0 9 8.00000 12.25000 53.1% - 0s\n", " 0 0 12.25000 0 6 8.00000 12.25000 53.1% - 0s\n", " 0 0 12.25000 0 - 8.00000 12.25000 53.1% - 0s\n", " 0 0 12.25000 0 7 8.00000 12.25000 53.1% - 0s\n", " 0 0 12.25000 0 7 8.00000 12.25000 53.1% - 0s\n", " 0 2 12.25000 0 7 8.00000 12.25000 53.1% - 0s\n", "* 10 5 3 9.5000000 11.25000 18.4% 6.2 0s\n", "\n", "Cutting planes:\n", " MIR: 7\n", " Lazy constraints: 69\n", "\n", "Explored 24 nodes (153 simplex iterations) in 0.04 seconds (0.00 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 3: 9.5 8 7.25 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 9.500000000000e+00, best bound 9.500000000000e+00, gap 0.0000%\n", "\n", "User-callback calls 236, time in user-callback 0.02 sec\n" ] } ], "source": [ "robust_classifier = RobustOCT(\n", " solver=\"gurobi\",\n", " depth=2,\n", " time_limit=100\n", ")\n", "robust_classifier.fit(X, y, costs=costs, budget=5)\n", "predictions = robust_classifier.predict(X)" ] }, { "cell_type": "code", "execution_count": 37, "id": "66797dea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#########node 1\n", "Feature: X2 , Cutoff: 0\n", "#########node 2\n", "leaf 0\n", "#########node 3\n", "Feature: X1 , Cutoff: 0\n", "#########node 4\n", "pruned\n", "#########node 5\n", "pruned\n", "#########node 6\n", "leaf 1\n", "#########node 7\n", "leaf 0\n" ] } ], "source": [ "robust_classifier.print_tree()" ] }, { "cell_type": "code", "execution_count": 38, "id": "7dbda0fa", "metadata": {}, "outputs": [ { "data": { "image/png": "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JSgoyGOFp556ipdeeoklS5YwZcoUSktLGT9+PLt372bs2LGMHDkSi8XC8uXLqaioYMmSJVx//fUA1NTUMGjQILKysrjyyisZMmQINpuNQ4cOsXr1anbs2EHfvn0b7koGxLadBlfgufTSS7n66qtZs2YNl156KQMGDCAtLY2vv/6aPn36sGvXLsxmMwAfffQRN998M/7+/kybNo24uDi+/PJL0tLSGDNmDGvWrCEgIKDx/chrJIRoX1prucilIy5aa61ffvllDej58+frxurr63ViYqKOi4vTNptNa631rbfeqgE9d+5cj3ULCgp0SkqKjo2N1bW1tVprrVesWKEBPXPmTH2iyspKbbVaG9/k7efibL5orbVes2aNxhV+9KJFizye7zvuuEMDeuHChVprrS0Wi46IiNABAQF6x44d7vUcDoeeNm2aBvRzzz13wqvm9ccpF7nIxccu0qUlOtTdd9+Nv78/8+bN87j9008/JS8vjzvvvBM/Pz+Ki4tZvHgxl112Gffcc4/HunFxccyaNYuioiJWr17tsayhRaGxkJCQE1sPRDsZP34806ZN87ht+vTpAGzduhWAZcuWUV5ezvTp0xkyZIh7PYPBwCuvvILJZGL+/PkdVrMQomsyebsA0bXExsZyww03sGjRIvbt20dqaiqAOwA1hJutW7ficDioq6tj9uzZTfaTnp4OwL59+7jmmmsYP348iYmJvPTSS6SlpXHttdcybtw4Bg8ejOu8oeJMGD58eJPbkpNdZ6AoLy8HIC0tDYBLLrmkybrdu3end+/eHDhwgMrKSkJDQ89YrUKIrk0Cj+hw999/P4sWLWLevHnMmTOH3NxcPv/8cy6++GL69+8PQGlpKQAbNmxgw4YNLe6rutp1tojw8HA2bdrEH//4R1auXMmqVasA14/vU0891eJAafHThIeHN7nNZHJ9rTgcDgAsFgsA8fHxze4jMTGRAwcOYLFYJPAIIc4Y6dISHe6SSy4hNTWVf/3rX9hsNt5//30cDgf33nuve52wsDAAHn300ZP2yT7zzDPubbp37878+fMpKioiLS2Nl19+Ga01Dz30EAsXLuzwxylcGl7LgoKCZpfn5+d7rCeEEGeCBB7hFffddx9FRUUsW7aMf/zjH0RGRnLjjTe6l48cORKlFN99991p79tgMHDeeefx+OOPu4POihUr2q12cXqGDRsGuI7sOlF2djYHDx6kd+/e0rojhDijJPAIr7jzzjsxm83MnDmTzMxM7rjjDo8BxwkJCdx0001s3LiRV199Fa2bTp+wefNm9xwuu3fvbrYFoeG2wMDAM/RIxKlMnjyZ8PBw3n//fXbv3u2+XWvNE088gd1u56677vJegUKILkHG8AiviIqKYurUqSxYsADAozurwdtvv83+/ft5/PHHWbBgAWPGjCEiIoLs7Gy2bdtGeno6eXl5BAUF8dVXXzFr1izGjh1L//79iY6OJjMzkxUrVhAYGMhDDz3U0Q9RHBMWFsbcuXO55ZZbuOCCC5g2bRqxsbGsXr2a77//nlGjRjFr1ixvlymE8HESeITX3HnnnSxYsIDRo0czaNCgJsujoqLYuHEjb731FosXL+Y///kPTqeThIQEhg4dytNPP01MTAwAEyZMICsri7Vr17J06VKqqqpISkpi2rRpPP7445x77rkd/fBEI1OnTiUhIYEXX3yRpUuXUlNTQ8+ePXn66ad54oknmp1OQAgh2pPMtCw6SpM32pw5c5g1axbvvfeee+6WDiLHqbddR31hyGskhGhXEnhER/F4o1mtVlJTU7FYLOTk5DQ5zcQZJj+mbSeBRwhxVpIuLdGh1q9fz7fffssXX3zB4cOHefHFFzs67AghhOiCJPCIDrV69Wr+9Kc/ERMTw8yZM3nssce8XZIQQoguQLq0REfpTG806S5puw55HZVSBi1fTkKIdiTz8Ih2p5RKVUrNOfFm1yIVoJR6Tyn1o1KqZ8PtHXwRbXdGXxulVLJSahvwb6VUs5MnKaWeV0qdd4YenxDCR0ngEWfCLKD8xBuVUnHA/4BoYKzW+nAH1yU6Oa31UWA8ru+mb5VS3ZpZrQR4skMLE0Kc9STwiHZ1LNTcAPzthNuHAJuBb4EbtdZVXihPnAW01rXArcByYLNSasQJq7wHXKmU6t7hxQkhzloSeER7+xWwRGtd3HCDUmoyrpad32ut/6C1dnqtOnFW0C4vAA8DnyulpjVaZgH+CfzaW/UJIc4+MmhZtBullBnIAi7TWu9RSilcXQ8PAT/XWm/1Zn3i7KSUGoqrtedfwGyttVMp1QvYCvSU1kIhRGtIC49oT7cA24+FHTOwAFf31gUSdkRbaa13AKOAy4AlSqlgrfUhXN2jd3mzNiHE2UMCj2gXx1pzZgKvKaUScf0YmYCLjw1EFaLNtNaFwM8AC7D+2Pid14AZSin5HhNCnJJ8UYj2chlgBIpxDU5eCdyita5pWEEplaiUutBL9YmzjFJqtFIqueG61roOmA78G9gEOHAdDXiNVwoUQpxVZAyPaBdKqU+AHOBG4H5gGTAAGAeMPfZvBPAFcKtMKidORSn1HjAZqAI2AOuP/bsbmADMBz4EBmitL/VSmUKIs4QEHvGTKaVSge1ABbAY6A1cCJTi+oFq+LHaJ0doidNxrKv0HFyhuSE4xwHfAQeAKUAkME5r/YO36hRCdH4SeMRPppT6DJgIpOEau7MB2KC1zvdqYcInHZvr6UJc4edi4Hxc77eLvFqYEKJTk8AjfjKlVBiuqVMqvV2L6HqUUsGAn9a63Nu1CCE6Lwk8QgghhPB5Jm8X0J6MAYZ8p03He7sO0TkY/FWBo86Z4O06TsXoH5jvrLfK+1aIDmDwMxc4bLWd/ntBtD+fauFRSunJy4Z5uwzRSSy/Pg2tdac/O7pSSo9dUHzqFYUQP9mGO2LOiu8F0f5kHh4hhBBC+DwJPEIIIYTweRJ4hBBCCOHzJPAIIYQQwudJ4BFCCCGEz5PAI4QQQgifJ4FHCCGEED5PAo8QQgghfJ5PzbR8phXvrGTD0xkAyASHwpsc1iqyP55DyfefUleai66vA0AmMBRCiOZJ4BFeV1dRT/pHBeRvtVBbYsMUYCC8dxC9roohcXSEt8vrlPa9cTflO9cAYAgIxhQe7uWKwFp0hMJ1CwHofsMTXq7mzLBVFJL25DjsVaUkXP5L+tz5covrVuzbyK4/Twat6ffAO8SNnXp8P+UFWPZ/R1XmdqqydlCV9SOOmgoAzv/LD5hju5/xx3I2sBZmkfPJG5TvXIOtohBTUDihfUfQbcL9hA8Y6+3yxFlGAo/wKsuRWjY+nUFdhR0AU6CB+moHRTsqKdpRSe9rYhl8T7KXq+xcao7ud4ed1IfnEz3yGi9X5FJXfITsj18FfDfw+IfH0fuOP3PgnQfI/98/iLlgMuGpFzZZz1FXQ8bcGaA1UcMneoQdgPyv57ufK9G88j3r2Pva7Tit1QAYA0OptxRR+v1nlP7wOT1vnk3S1Q95uUpxNpExPMJrHPVONr+QSV2FndDuZi557RwmLRzK1QuHknpbIijI/KSIw/8r8XapnUpNzl4ATCFRnSbsdCWxF04havhE0JqMeTNw2GqbrHP4g+exFh7CFBxBn7vnNLMXRUB0MlEjJtF9yu/odfufz3zhZxFbRRH7/noXTms1YQPGMnzOVka/e4gL3skg8Yp7QWuyFs2mfPdab5cqziISeITXHP6ihJoCG8YAA6Of7kN4ryAATAEGzpmaQK+rYgDY9588nHbfOcntT+W0WQEwmoO9XEnX1efuOZiCI7AWHOLIkhc8lln2byLvq3kA9Lr9Bfwjmp6YO+X6Rxnx+nYGzPgnKZN/S1jqmA6p+2ScNitF3y31dhkAHP30DRw1FfhHJjBg5r8JjO8FgCk4nN6/eJHI864ArTn8wXNerlScTbp8l1Z1Xh0HPymiaEcltcU2AAJj/IjsF0zSRZHEDw9r1X6cdk3B9xXkb6mgIrOW2tJ67NUO/MNMRPYPotekWGIHh7a4fcmeKjI/KaJ0fzV1FXaMfgr/MBMhSWbihofS84oYjAGe+TR/awVZXxRTfrAGm8WOyWzEP9xEWHczccPD6HFFNEp13pMCZ39bCkDSRZEExfo3Wd735/Ec+rwYa2k9xTsriRvWutfCVx1Z+rJHN0hdcTYb7ohxX+9775vEj7/FfV07HRSuXUjRpqVUH9mNo8aCKSSS0H4j6XblvYQPGNfs/VjSt1KydSWV6VupKz1KvaUYozmY4JSBxI6dStxFN6MMRo9tts0cRl1xtvt647oAUn4+y93NtfOF67Ds2+hx24lOtk7Dvgf9bhnm+D7krPgLZT9+ja0sj6Bu/TnvhW/c6zpsteT/bz4lW1dSm3sAR10NfuGxhKdeSLeJvyKk55Bm7/9U/CMS6HXb86S/+2tyv3iX6FGTCes3EoetlvS5vwHtJHLo5cSNm9bs9ic+f95kObCFwvWLKN68DEeNhdgxN3i1Hq01RRs/AiDhsrsxBTb93ky+ZgZl27+iKjON2rwMAhP7dnSZ4izUpQNP1pfF/PhuDvpY64HBX2H0N1B1tI6qnDryNlcw6b+t+0Is3VvFlhcPua4oMAUaUQawltaTt6mCvE0VDLg9kf5Tmv61d/irEra/fQSONWIY/V0hpabARk2BjcIfLMSfH05IYoB7m73/zePAB/nu60azAaddU51bR3VuHXmbKuj+s2hU5/le9WCvdVCeUQNA/PDmg2BQrD+hyWYqs60U/SiBxxgQjF94HE5bLY7aSlAG/MKOBwuDv9n9f1tFEXtfu52qg9+7blAKozmE+opCSrd9Sum2T0m5/jG63/hkk/vZ+exVx/dpDsbgb8ZeVUbF3vVU7F1PybZPGPDIApTx+NeHX2g0jtpK7NXlruvhcU1qb2+1eQfZ9+YvsVeWYPAPQhn9PJcXZLJnzs1Y8zOPPRgjBn8ztpKjFG1YQtF3S+lz16skXPqLNt1/3EU3U7x5GWU7VpMx72HOe/4bV1dWwSGMQWH0mf7aT32IZ0xdcQ6F6xdTuGHx8ecHMMf19F5Rx9Qe3U99RSEAEUMua3ad0H4jMQaG4qitpHz3Wgk8olW6bODJ21TOjrddf5HGnx9G6m2JRPR2danU1zoo2VlFzrrSVu/PGGCg51UxJI2NIKJvECazK2nUFtk4uLKQgyuK2PufPGKGhBLV//iXv73Oyc73ckBDymVRpN6cSFCcq7WjvtpBRWYN2d+WYTQdb6mpKajjwIeusNP3hjj6XhdHQITry95msVN2oJrsb0rpvG07UJljdQe80O6BLa4X2t0VeCqzrR1UWeeVNOnXJE36NQVrF5Ix9zcERCcx4rW0Jutph519f72TqoPfE9Z/NN2nPElo35EY/AKoryojf/U/yF42h+xlcwhKOZeYUdd5bB81/Crixk0jLHUMfqHRANhrLBRt/JDDi5+lbPtXHF31DsmTfuPeZuizq6nYu55df74egFFv7TlzT8Qxhxb+EXNsDwY8soCw/qMAV8gBsNdWsufVaVgLDhE1fCIp1z9GcPdBKKOJurI8jn76Fnlf/J2D82cRnDKQ0L7nt6mGPtNfI+2psdTmprPvzemUbf8KgF63PkdAVGL7PNB24rBWU7LtEwrXLaJi73rQrg+gMSicmFHXuV7zc0Z7uUrXoPwGQcmpza6jDEYCE/tRlfkDtbkHOqo0cZbrkoHHadeukAEkjApn1JO9UIbj8cAv0EjCqHASRrX+UN/I/sFE9m/6V2xgrD+Dpidjr3Vy+KsSslYVewSeysO1OKxOjGYDwx7qjjI2qiPYSMzgUGJO6AorS68BJ4QkBTDwF0key/zDTMSPCCd+xOkfpvzDXw+Tvab1Ia+xlEujGD6jR6vXt5bZ3f83R/m1uF7DMmtZfZvq6ooKNyyhMn0LIb2HM/CJDz1afvxCIkm5/lGU0cThD54je9mcJoFnwMwFTfZpCgoj8fLpGANDSf/br8hf/b5H4PEGZTAx8IkP8W/UmhQY3xuA3M/fdoWd868mdcY/Pbp2AyIT6X37CzjrrRR8/U+yV/yFc3/7nzbVEBCVSK9bniXjvUcoS/sCgIjBlxF/8W0/4ZG1H601ln0bKFy7iOJtK91HPCmjHxFDLiNu7E1EDZ+IwS/gpPtp6GJsi5N1XTbHVl4AgCk4AqN/y38M+UcmeKwvxKl0ycBTvLOS2qJ6UDBoepJH2DlT4s8P4/BXJZTuq/a43RTkagnSdo2t0u5uqTmZhm3qaxzY65yYAtpn7LlfsJGAiLa9JfyCT6/vzFHrcP//xLFJjTUss9c621RXV1S41vXjnXjlPR5hp7HYC6dw+IPnqMneg628AP+I+FbtO+q8KwHXIeh1ZXkERHqvFSNu3DSPsNNYwdr/ApB01YMtjmOLvXAKBV//k4o969FOR5vH1cReOIVDC/+Io8YCQO9fvNim/bSn2oJMCtcvpmj9Bx5jq0J6nUfsuGnEjrnB3XrXGqaQyCbdlK11ut2ZjjrXd6ThJGGn8XKHtapNdYmup0sGnobQEZJkJjjh5H/ZnA5bpZ1DnxVT8IOFqlwr9moH+oTfaWupZ0tFSGIAwd0CqM6tY+0TB+h1VQxxw8MITTG3+EUd2T8Iv1AjdWV21j2xn54TY4kbGkpw4k97LIPvSZY5b85y2umgMtPVzXXo338ga+HsU25TV3LUI/Boh53CdYso3rKC6iO7sFeXo+22JtvZyvK9GnhC+45o9va60lxsJUcB1wSNtPA50k5X6HbWVVNfWYp/eGyb6jjy8avusANQuHYhPW76Q5v21R4sB7aw87mr3dcDopOJvXAKseOmEdStX5v2OWDGP9urPCG8pksGnoZJ7oLiTt2a0lqW7GMT6JUf76oxmg2u1hfl6karr3LgsHomIGVUnP/bnmx5MZOaAhu75+eye34upiAjMYNCSLookqQLIzy6uvxDTJz/SA++f/0wliwrP/7N9Recf7iJ2CEhpFwc1aYurY5kDDz+17SjzokhqPm/rh11rufLFCgzKLSGvarMfZoJe1Xruiedthr3/x3WKna/chOV6Vvctxn8zBhDo90tIA0DSp11NXhT4wHbjdnKjw/mr7cUtWpfzmbm0mmNysw0jn72FgARQ35G+Y//4+hnbxE96ro2HwH2U2nH8XCq/AKIHnUdMaN/3uaw09EaWoRO9Zo0LDeaQ854TcI3dMnAcyakvXGEunI75mg/htyXTMygUI9unqIdlWx8JqPZbSP7BnH5O+eSt7mCou0WSvZWU51bR/4W12HuB1cEMfa5vu6B0ADx54dzxd8HkruxnKIdlZTuq6K2qJ6j68o5uq6c+BFhXPC73h3SXdcWjcftWEvr8Wsh8DS0iJkj2y+c+rKGVguAIc+sarEVpCXZy/6PyvQtKKMfPW99lugR13gMvtVOBxvvbGgN8u7cSMrQQgh2Hv+jYuSbu1vdXXe6nHYbGXMfBqeDiMGXce6jC9n15+uw7N9ExrwZDP3TVx5HsnWU4J5D6XnzbArXL6YmZy+5n79N7udvE5QykLixU4m58EavtsydSsPYHHt1OQ5bbYvjeGxlrmB7pl5f4Xu6ZOBpGKdSU9g+A2FrimyUp7v+2h3+SI9m59upKz/5fRn9DSRfFEnyRZEA1BbbyF5Tyr7F+ZSn17B/UT4D7/IcoOwXZKTH5dH0uNzVF1+VayVrVTEHVxRRsM1C1qpiel3d+mb6nfNyOLq+rNXrN5Y0LvK0usNCkwJAARoqj1gJTW5+rEnD0VmhKc0vF55MIVFgMILTQV1JzmkHnuItKwBIvnYG3a68t8ly27HWnZ+iIQQ4j7VENcdRW9nm/fuFHX/Pn9hd156yl/8fNTl7MZpD6Dv9LyiDgb73/JXtv7+E6sM7yfn0TVKum3lG7vtkTIGh7iP6qg5tp3DdIoq+W0pN9m6yFu0ma/GzRAwcT+zYm4gecXWrWkj2/vVOKtO3tqmepKseJGnSr1u9flDSOe7/1x7dT0iv85qso51OavPSAQjs1r9NdYmup0v2E0Sd42oyrTpqpTq/5S/d1rKWHG9Cjuwb1Ow6xbtOb2BdYIw//acm0PNKV5gp3n3q7UO6mRk0PZn4EWFtus/6agd15fY2XeqrHae+g0ZMgUYi+7meq8I0S7Pr1Bbb3IEndkjLkzaK4wwmP0J7DwOgNO3L097eVpoLQMixfZyoYs/6ljdWx79OtG659ccUFOFxXydyWKup+QmHGpvjergH2JZu/6LN+zmZqsM7ObryDQB63PwMATGusB+Y0Md9RFL2sjnU5KafkftvrZBe59H7Fy8x8s3dpM74J1HDJ6IMRsp3fUP63x9ky0PncuCdByj78WuP1sET2avKqK8obNOlYRByawV264/fsZBa9uPXza5TmbHVHYojBo4/rf2LrqtLtvDEDAklMNaP2qJ6dv3jaJPD0k+XqVF3TOXRuiahpzLH6p5V+ETOeicGv5McpeRvcK932tuc5ukYhs/ocVqHlv9UyeOjKDtQQ866Ms65KYHAE2ZbTv+4ELSr++vEQ/NFy+LG30plxjaKN31MwmV3ueeoaY69uhxTcIT7ujEoDHtlCbW56TBsgse6DlstOStankzP2GhGXEdNhcd+GwtKGUDJ1hWU7/wGp83a5Eiy3FV/c49Daqv4i28jZ8Vr5H05l7hx09yHqzfnxOfgVLTDTsbch9GOesIHjCPhsrs8lne76lcUb1lOVWYaGfNmMPgPn7Tc/dZBDCY/okdMInrEJOotxRRt/JDC9YupPryToo0fUrTxQ/zC44gdcwO9bnu+yfaDf7+iw2pVShE75gZyP3+H/K/nk3jlvU1mWz766ZuAK5jLpIOitbpkC4/BqBj0S9dfZPlbKtj850wqMo8PwLTXOji6oYzNL2a2tAsPoclmzNGuMSbb3zqCJcs1mE47NPlbK9j4TEaLh47nrCtj/e8OcPirEmqKjrcUOeqd5HxbyqFVxQDENTrFRfrSAjY9f5CctaUe89PU1zrI/KSIvE3lTbbpjHpMiCYo3h+H1cmmFw5Scex5c9Q5OfBRPoc+cw04Tb0tEYOpc45F6ozix99KWP/RaEc9u1+dSu4X71JfeTxw26vLKU37gn1v/ZL9/8+z2ypi0MUAZK94jdLtX6KPjYepOryT3S9Pod5S3OL9Bib0cc923HBYeHNiRk0GpaivLObA3x/CVuF6ne01FrKX/4UjH7+CMeinDbpPuuZhzAl9cNRY2PncNRSuW4S9UTeZraKI4s3L2P3qNLIWzT6tfeesfJ3qwzsx+AfR957XmxxNqQxG+t7zBsroR2X6Fvd5tRrTTif1lSXui6Omwr3MXl3usUw723dKBr+wGLpNfIDznl/DeS98S7eJD+AXFkt9RSG5q/7WrvfVVkmTHsYYFI6tNJd9r92BtTALcL1HMv/9e0p/WAVK0eOmp71bqDirdMkWHoBuoyMYcl8yO+flULDNQsE2C0Z/hSHAQH2VA7Rny83JKINi8L3JbH3lEJasWtY8sg+j2YB2aJz1msBYPwb9MpkfXj/cdGMNJXuqKdnjavY9sQaAyHOCOGfq8VNSaCfumsF1NJjBqDy6lRJGhdPzitbPs+ENRj8DF/y+NxufzsCSZeWbR/ZhCjLgsDrdh/P3mhRLj5917sfR2SijidSZC9j/5nQq9qzj0L9/x6H//B5jYBg4HR7zloQPvNhj2x5Tfkf5rm+xV5aw9/9uRZn8MZj8cVirMPgHkvrIv9jzytRm79cYEETshVMoXLeQrP/+kSMfvYxfaBQA3SbcT7eJDwAQlNSfpKse4uhnb1GyZTklW5ZjDAp3dVFoJ92n/p7ynWvaPNEduMaxDHziQ/a9dgfVR3aR/u6vYe7DmILDcdbbcDbqZom/5PZW77c6ey/Zy/8CQI+pv2vxVAzBKQNIvm4m2R+/wuElLxA1fCLm2O7u5XUlOXz/2+HNbrvjac/TKZz/lx88tm1Pwd0H0uu25+l582zKdqymcP3iM3I/p8s/PJbUGfPZ+9rtVOxdz/ePjsAYFIajtsr1BagUPW+eLd1Z4rR02cAD0OvqWGKGhJK5spCiH6uoLbGhHZqQJDNR5wSRND6y1fvqNjqCsc/25cCSAsoOVON0aAJj/UkcFU6/G+PdrT4nShgVzrCHu1O8s4qKzBqsZXbqq+34hxgJ6xFI0kWRdL88GkOjw9J7TIjBHOVH0Y5KLEes1JXVY7c6CIgwEd47iJRLo0gaF9GpTxzaIKx7IJf+NZX0pQXkb7VQW2zDFGwkoncQva6KIXF0hLdLPCv5hUQy8MmllG77lMINH1CV+QP1laUoZcAc15Pg7oOIGHwJMRdc77GdOa4nQ2d/yZGlL1G+8xvs1eUYA0OJGj6R5GsfaXGq/wZ97noV/+hulGz9hLrCw+5J7+yNWjAAet4yG3NCb/K/nk/t0QOAJix1DElXPUjUsAmU71zzk58Dc0wKQ/70FUUbl1C8eTnVWT9iry5DmQIITOxLcM+hRA79GdHnT2rV/rTTQcbc36DtNkL7jSLxyvtOun7ydTMp2fYJNdl7yHhvJoOe/OgnP6YzRRlNRA2fSNTwid4uxS3i3IsY9sK35Kz8K+U712CrKMQvNJrQviPoNvEBwgeM9XaJ4iyjTja48GyjlNKTlzU/2FJ0PcuvT0Nr3elTn1JKj13QcleREKL9bLgj5qz4XhDtr0uO4RFCCCFE1yKBRwghhBA+TwKPEEIIIXyeBB4hhBBC+DwJPEIIIYTweRJ4hBBCCOHzJPAIIYQQwudJ4BFCCCGEz5PAI4QQQgifJ4FHCCGEED5PAo8QQgghfJ4EHiGEEEL4PAk8QgghhPB5EniEEEII4fOU1trbNbQbY4Ah32nT8d6uQ3QOBn9V4KhzJni7jlMx+gfmO+ut8r4VogMY/MwFDlttp/9eEO3PpwKPEKJrUEpFAu8D3YBpWutDXi6pwyilhgFLgK+AmVprq5dLEuKsIF1aQoizilJqJPADkAWM60phB0BrnQacD0QDG5VSfb1ckhBnBQk8QoizgnJ5GPgU+K3W+hGttc3bdXmD1roCmAa8hyv0TPVySUJ0etKlJYTo9JRSEbh+3HsAN2mtM71bUeehlDof+AD4HHhUa13n5ZKE6JSkhUcI0akd+0H/HsgFxkrY8aS1/h5XF1cisEEp1dvLJQnRKUngEUJ0Sse6sB7C1XLxhNb6N9J60TytdTkwBfgXsEkpdYN3KxKi85EuLSFEp6OUCgfmAn1xdWFleLmks4ZSahSwGFgBzOqq45yEOJG08AghOpVjh11vA4qBCyXsnB6t9RZgOK7xTuuVUj29W5EQnYMEHiFEp3CsC+sB4AvgD1rrB2WOmbbRWpcBPwcWApuVUpO9XJIQXiddWkIIr1NKhQLvAgOAqVrrdC+X5DOUUqOBRcBS4Enp4hJdlbTwCCG8Sik1FNdRWBXAGAk77UtrvQlXF1dfYK1SqoeXSxLCKyTwCCG84lgX1n3AamC21voBrXWtt+vyRVrrUmAyrlNSbFFKXevlkoTocNKlJYTobF8CytsF+DKl1Bhgkda6e0fdZQfdjxAnJYFHCNHZvgTkB/IMU0pFa62LO+ruOuh+hDgpCTxCiM72JSA/kB2jo153eT1FpyBjeIQQQgjh8yTwCCGEEMLnSeARQgCwevVqlFI8+OCDzS4/ePAgBoOBCRMmuG+rrKzkmWeeYeDAgQQGBhIREcGECRNYv359k+3z8vKYMWMG/fr1IzAwkKioKAYPHsyvfvUrKioqztjjEif3zTffoJRi9uzZbNu2jSuuuILQ0FDCw8P5+c9/TlZWVpNtNm7cyKRJk4iKisJsNpOamsrs2bOpqanp+AcgRCvJGB4hhAbQWtOvXz+Ki4vJzc0lKCjIY6WnnnqKl156iSVLljBlyhRKS0sZP348u3fvZuzYsYwcORKLxcLy5cupqKhgyZIlXH/99QDU1NQwaNAgsrKyuPLKKxkyZAg2m41Dhw6xevVqduzYQd++fRvuSsZ8dAwNrsBz6aWXcvXVV7NmzRouvfRSBgwYQFpaGl9//TV9+vRh165dmM1mAD766CNuvvlm/P39mTZtGnFxcXz55ZekpaUxZswY1qxZQ0BAQOP7kddTdA5aa7nIRS5d++L28ssva0DPnz+/8c26vr5eJyYm6ri4OG2z2bTWWt96660a0HPnzvVYt6CgQKekpOjY2FhdW1urtdZ6xYoVGtAzZ87UJ6qsrNRWq7XxTd5+PrrKRWut9Zo1azSu8KMXLVrk8drccccdGtALFy7UWmttsVh0RESEDggI0Dt27HCv53A49LRp0zSgn3vuOX0Cbz9OucgFrbV0aQkhjrv77rvx9/dn3rx5Hrd/+umn5OXlceedd+Ln50dxcTGLFy/msssu45577vFYNy4ujlmzZlFUVMTq1as9ljW0EjQWEhJyYouA8ILx48czbdo0j9umT58OwNatWwFYtmwZ5eXlTJ8+nSFDhrjXMxgMvPLKK5hMJubPn99hNQtxOkzeLkAI0XnExsZyww03sGjRIvbt20dqaiqAOwA1hJutW7ficDioq6tj9uzZTfaTnu46O8S+ffu45pprGD9+PImJibz00kukpaVx7bXXMm7cOAYPHoxS0uPRGQwfPrzJbcnJyQCUl5cDkJaWBsAll1zSZN3u3bvTu3dvDhw4QGVlJaGhoWesViHaQgKPEMLD/fffz6JFi5g3bx5z5swhNzeXzz//nIsvvpj+/fsDUFpaCsCGDRvYsGFDi/uqrq4GIDw8nE2bNvHHP/6RlStXsmrVKsD1g/rUU0+1OFBadJzw8PAmt5lMrp8Ih8MBgMViASA+Pr7ZfSQmJnLgwAEsFosEHtHpSJeWEMLDJZdcQmpqKv/617+w2Wy8//77OBwO7r33Xvc6YWFhADz66KMn7TN/5pln3Nt0796d+fPnU1RURFpaGi+//DJaax566CEWLlzY4Y9TnL6G172goKDZ5fn5+R7rCdGZSOARQjRx3333UVRUxLJly/jHP/5BZGQkN954o3v5yJEjUUrx3Xffnfa+DQYD5513Ho8//rg76KxYsaLdahdnzrBhwwDXkV0nys7O5uDBg/Tu3Vtad0SnJIFHCNHEnXfeidlsZubMmWRmZnLHHXd4DDhOSEjgpptuYuPGjbz66qto3XR6i82bN7vnZdm9e3ezrQINtwUGBp6hRyLa0+TJkwkPD+f9999n9+7d7tu11jzxxBPY7Xbuuusu7xUoxEnIGB4hRBNRUVFMnTqVBQsWAHh0ZzV4++232b9/P48//jgLFixgzJgxREREkJ2dzbZt20hPTycvL4+goCC++uorZs2axdixY+nfvz/R0dFkZmayYsUKAgMDeeihhzr6IYo2CAsLY+7cudxyyy1ccMEFTJs2jdjYWFavXs3333/PqFGjmDVrlrfLFKJZEniEEM268847WbBgAaNHj2bQoEFNlkdFRbFx40beeustFi9ezH/+8x+cTicJCQkMHTqUp59+mpiYGAAmTJhAVlYWa9euZenSpVRVVZGUlMS0adN4/PHHOffcczv64Yk2mjp1KgkJCbz44ossXbqUmpoaevbsydNPP80TTzzR7NQDQnQGMtOyEKLZL4E5c+Ywa9Ys3nvvPfd8LB1EjlPvGHK2dNGlSOARQjT5ErBaraSmpmKxWMjJyWlymokzTH4gO4YEHtGlSJeWEMJt/fr1fPvtt3zxxRccPnyYF198saPDjhBCnBESeIQQbqtXr+ZPf/oTMTExzJw5k8cee8zbJYmznFIqVmtd5O06hJAuLSFEZ/sSkC6QjtEhr7tSKge4RWu9viPuT4iWyDw8QnQRSqmZSqlbm1+kApRSbyilspRSF+AKHd66iI7RUa/n/cCHSqknlFLN/uYopZ5USt3Y3DIh2ou08AjRBSilIoAM4AKt9cETlvUEPgBygbu11mUdXqDwaUqpFGAxUAb8QmtdcsLyS4C5wACttb3DCxRdgrTwCNE1PAKsbCbsTAY2A/8Ffi5hR5wJWuts4GJgN/CDUurCE5Z/gytwN9cCKUS7kBYeIXxco9ad0VrrjGO3+QMvATcA07TWm71XoehKlFLXAvOAV4H/08d+hJRSlwF/A86VVh5xJkgLjxC+72Hgk0ZhpwewFugLDJewIzqS1nolMAqYAixXSkUdW7QGyAdu9lZtwrdJ4BHChymlwnEFnheOXb8W2AIsASZrrUu9WJ7oorTWh4HxQDquLq7Rx1p6/gQ8rZQyerVA4ZMk8Ajh2x4GPgOylFKvAm8B12ut3V0JQniD1tqmtX4UmIGrpee3wNdAEdLKI84AGcMjhI861rqTAdyIa7xOS0fIhADVEoDEmXas5SZAa11zwu09cR3FlQfMx/V+Hai1dnR0jcJ3SQuPEL7rN8CPuA45XwZcB0QopW5QSv1JKbVMKXUI17iJMd4rU3QhU4ASpdR+pdRipdTvlFKTADtwEZAFvAbUAdO8V6bwRdLCI4QPUkpF4jrMtx5YDcQBQ4AKYMcJlwz5S1p0FKWUH5AKDD3hYsL1fqwCrgAsQDd5b4r2IufSEsI3XQnUAF/gGqS8A9ghg5SFt2mt64Gdxy7/brhdKZXA8fCjcc3bMwDY5YUyhQ+SFh4hhBBC+DwZwyOEEEIInyddWqLdBZr88q0Oe7y36xCdg9loKqi11yd4uw7ResYAQ77TpuUzLAAw+KsCR53zrP8MS5eWaHdKKV3zyEveLkN0EkGvP4nWWs6CfhZRSunJy4Z5uwzRSSy/Ps0nPsPSpSWEEEIInyeBRwghhBA+TwKPEEIIIXyeBB4hhBBC+DwJPEIIIYTweRJ4hBBCCOHzJPAIIYQQwudJ4BFCCCGEz5PAI85Ka7MPEvT6kwS9/qS3SxFCtEHxzkqWX5/G8uvTvF2K6CLk1BJCCMqsNazLOURa4VHSCo+yvfAohTVVAKy68V7Gp/TxcoVCiNaoq6gn/aMC8rdaqC2xYQowEN47iF5XxZA4OsLb5XmVBB4hBJ8c3MP9X33o7TKEED+B5UgtG5/OoK7CDoAp0EB9tYOiHZUU7aik9zWxDL4n2ctVeo8EHiEEAPFBoQyLT2JYXBL9ImOYvmqxt0sSQrSSo97J5hcyqauwE9rdzPkzexDeKwh7nZODKwrZ9988Mj8pIqxXID1+Fu3tcr1CAo8QglsHDOeOgSPc18uttV6sRghxug5/UUJNgQ1jgIHRT/chKNYfAFOAgXOmJlBXVs+hz4rZ9588Ui6OwmA6688Fetok8IhOI7O8hP+3fQNrjmSQU1mOBpJDwhmRkMLUc4ZyZc9zWrWfeoeDVVn7+DRzL9sLj5JXZaHCZiXaHMyoxBQeGHohF59kTMrGo1m8vX0Dm/OOUFhThdlkIiYwmH6RsVzZoz93Dx5FoMnPY5vPMvfy3s7N/FBwlBJrNSF+/sQEhjAwJp4repzD3YNGolTn/YIxGuT4BfHTVefVcfCTIop2VFJbbAMgMMaPyH7BJF0USfzwsFbtx2nXFHxfQf6WCioya6ktrcde7cA/zERk/yB6TYoldnBoi9uX7Kki85MiSvdXU1dhx+in8A8zEZJkJm54KD2viMEY4Pmez99aQdYXxZQfrMFmsWMyG/EPNxHW3Uzc8DB6XBHdqT/D2d+WApB0UaQ77DTW9+fxHPq8GGtpPcU7K4kb1rrXwpdI4BGdwj92bmHmmuXUOx0AmI0mAk1+HCgrZn9ZEZ8c3EPeg7Nbta/vcrOYtnIBAApFmH8ARmUgr9rC8ozdLM/YzZ8unMCsUZc22Xb+rq08tHopGg3gDjaHKko5VFHKl1n7mdDrHPpExLi3efa7L3lp89fu68F+/tgcDjLKi8koL2Z5xm5+MfB8TMrYpudGiLNB1pfF/PhuDtru+uwY/BVGfwNVR+uoyqkjb3MFk/47pFX7Kt1bxZYXD7muKDAFGlEGsJbWk7epgrxNFQy4PZH+UxKabHv4qxK2v32EYx9hjP6ukFJTYKOmwEbhDxbizw8nJDHAvc3e/+Zx4IN893Wj2YDTrqnOraM6t468TRV0/1k0nfUjbK91UJ5RA0D88OaDYFCsP6HJZiqzrRT9KIFHCK9YkbGbX/9vKQATep7DMxdeyXlxSQBU2upYm3OQD/btaPX+Av38uW/IaG7sP4Th8ckE+7n+2smpLOettPW88cN6Zm/8kotT+jAqsbt7u5p6G49/uxKN5vZzz+cPoy+ne1gkABV1VnYUHmXhvjQCjMc/NocrSnllyxoAHh1xMb8ZfhFxQSEAlNRWszU/m//u/QFF5/3LUIifKm9TOTvezgYg/vwwUm9LJKJ3EAD1tQ5KdlaRs6601fszBhjoeVUMSWMjiOgbhMnsShq1RTYOrizk4Ioi9v4nj5ghoUT1D3ZvZ69zsvO9HNCQclkUqTcnEhTn+vzXVzuoyKwh+9syjI26c2oK6jjwoSvs9L0hjr7XxREQ4fpDx2axU3agmuxvSjv1J7gyx+oOeKHdA1tcL7S7K/BUZls7qLLORQKP8Kp6h4NZ364E4Jre57Lo2tsxqONNzaH+AUzqfS6Tep/b6n2OTEhhZEJKk9uTQyN4afw1WGx1zN+1lXk7N3sEnt0lBVTV2wj28+edy2/06OYJDzAzPqVPk8OztxXk4NSa/pGxPDfuKo9l0YHBTOyVysReqa2uvcF9X3zAv/f+cNrbAdw+YDjvTripTdsKcbqcdu0KGUDCqHBGPdkLZTgeD/wCjSSMCidhVHir9xnZP5jIRkGmQWCsP4OmJ2OvdXL4qxKyVhV7BJ7Kw7U4rE6MZgPDHuqOMjaqI9hIzOBQYk7oCitLrwEnhCQFMPAXSR7L/MNMxI8IJ35E62tv8MNfD5O9pvUhr7GUS6MYPqNHq9e3ltnd/zdH+bW4XsMya1l9m+o620ngEV71TfZBsivLUShevniSR9g5Uyb2TGX+rq1syj3scXuYv6uJu97poMRa426pOZnQY9tYbFZq6m0E+TXtO2+LsABzq+6/pW2F6CjFOyupLaoHBYOmJ3mEnTMl/vwwDn9VQum+ao/bTUGuliBt19gq7e6WmpNp2Ka+xoG9zokpoH2+g/yCjQREtO0n1i/49PrOHLUO9/9PHJvUWMMye62zTXWd7STwCK/anOcKHedExdIrvP0OlSy11vD3Hd/xZdZ+0suKqaiz4tCeH/K8aovH9b4RMfSNiCGjvJhLFr3N/UNHc0XPcxgQFdfiYMWRCSlEmYPIr67k0sVvc8+Q0fysez96R/y0xzLnkuuYc8l1P2kfQnSEhtARkmQmOCHgFGu3nq3SzqHPiin4wUJVrhV7tYMTPsJYSz1bKkISAwjuFkB1bh1rnzhAr6tiiBseRmiKucXPcGT/IPxCjdSV2Vn3xH56TowlbmgowYk/7bEMvie5S8950xlJ4BFe1TCbb0poRLvtc29JAVd9NNe9b4AQP39360u9w0FZXS3V9TaP7YwGA+9fdTM3r1xAlqWUp9Z9xlPrPiPc38xFyb2Zes5Qbug32KOrK9IcxHsTpvHLLxazszifGV8vAyA2MJhLUvpyy4BhberSEuJs0TDJXVDcqVtTWsuSfWwCvfLjXTVGs8HV+qJc3Wj1VQ4cVs8EpIyK83/bky0vZlJTYGP3/Fx2z8/FFGQkZlAISRdFknRhhEdXl3+IifMf6cH3rx/GkmXlx7+5xiL5h5uIHRJCysVRberS6kjGwOMtQo46J4ag5luIHHWu58sU2DWPypTAI3zO/V9+SGFNFd1Cwnjt0smMT+5DeKNunjVHMpi0dF6z254fn8zOux5j5cE9rD58gO9yD5NRXswnmXv4JHMPb/ywjlVT7nMPhAaY0Osc9tz9OB9n7GTNkQy+yz1MdmU5Sw7sYMmBHVzVK5Ul1/2iQ7rrhPAFaW8coa7cjjnajyH3JRMzKNSjm6doRyUbn8lodtvIvkFc/s655G2uoGi7hZK91VTn1pG/xXWY+8EVQYx9rq97IDRA/PnhXPH3geRuLKdoRyWl+6qoLarn6Lpyjq4rJ35EGBf8rneHdNe1ReNxO9bSevxaCDwNLWLmyPYLp2cTCTzCq+KDXQMIsyvL22V/2ZZythW4/kJ7b8K0Zufbadzy0xyzyY+p5wxl6jlDAciprOC/e3/ghU2r+b4ghz9vWs0LF13tsU1YgJk7B47kzoEjAcgoK2bezk288cN6Pj+0j7k/bub+oWNa/Tge+2YFHx74sdXrNzal/xDpDhMdpmGcSk1h+wyErSmyUZ7uOsR6+CM9mp1vp6785Pdl9DeQfFEkyRe5jrKsLbaRvaaUfYvzKU+vYf+ifAbe5TlA2S/ISI/Lo+lxuas7uirXStaqYg6uKKJgm4WsVcX0ujq21Y9j57wcjq4va/X6jSWNizyt7rDQpABQgIbKI1ZCk5sfx9dwdFZoStcc5yeBR3jVBceOktpfWsShipKfPI7naFWF+//nxzf/hfFtzsHT2mdyaDiPj7qU/GoLf9vxHWtzMk+5Td/IGF4afw3pZcV8fmgf63IyTyvwWOqspwxmJ9tWiI4SdY7rKKmqo1aq8+t+8jgea8nxrubIvkHNrlO86/Q+G4Ex/vSfmoD12GzDxbtPvX1INzODpidTlVtHwTYLxbuqTivw1Fc7PLrkTkd9tePUKzViCjQS2S+IsgM1FKZZ6HZhRJN1aott7sATO6TlSRt9mQQe4VWXpPQhJTSC7Mpynvj20yaHpZ+uxkco7S8rahJ69pcWsmhvWrPb2hx2/I0tfyQaJiG0OY5/ibV2mzrH6X3xvTvhJjm0XJwVYoaEEhjrR21RPbv+cbTJYemny9SoO6byaF2T0FOZY3XPKnwiZ70Tg99JjlLyN7jXO+1tjk2o2FrDZ/Q4rUPLf6rk8VGUHaghZ10Z59yUQOAJsy2nf1wI2tX9deKh+V2FDCoQXmUyGHnl4msA+CRzD1NW/Isdhbnu5VW2OpYe+JFpK//Vqv2lRsWSFOIaYPjgVx+xq9g1oZjD6eSzzL1MWjrPY/xNYx/s38EVS/7G/F1bybaUu2+vs9tZvG877/64CcDjFBdztn7DDcvn88G+7eRXV7pvr7TV8c72DSzP2N1km86quLbafSmrq3HfXmGzeiyrd5zeX5/CtxmMikG/dP1hkb+lgs1/zqQi8/j7x17r4OiGMja/eOqWUYDQZDPmaNcfCtvfOoIly3VeN+3Q5G+tYOMzGS0eOp6zroz1vzvA4a9KqCk63lLkqHeS820ph1YVAxDX6BQX6UsL2PT8QXLWlnrMT1Nf6yDzkyLyNpU32aYz6jEhmqB4fxxWJ5teOEjFsefNUefkwEf5HPqsCIDU2xK75Hm0QFp4RCcwue8gXrt0Mo99s5JVh/ax6tA+Ak1+BJr8KLPWotGE+7euz9mgDMy55Fpu+/Q/7CzOY9S/XyfEz596p5M6h52U0AheufhafvlF0zOBa63ZcDSLDUezAJrUADAqoTtPjLrMvY1Ta3fN4DqthJ/BQHmjbqVrep/L9EGj2vr0dJjuf3+u2dsbTtPRYNWN9zaZgFF0bd1GRzDkvmR2zsuhYJuFgm0WjP4KQ4CB+ioHaM+Wm5NRBsXge5PZ+sohLFm1rHlkH0azAe3QOOs1gbF+DPplMj+8frjpxhpK9lRTssd1qPyJNQBEnhPEOVOPn5JCO3HXDK6jwQxG5dGtlDAqnJ5XdO4zjBv9DFzw+95sfDoDS5aVbx7ZhynIgMPqdB/O32tSbJc9UzpI4BGdxP1Dx3BJSh/eStvAN9kZHK2swO50cE5ULCMTUpiWel6r9zW57yA+v/FeXtmyhi35R6h3OEgJjeCaPufy2MhL2FWU1+x2k/qcy7tqKt9mH2RHUS751ZWU19USZQ5kYEwCU/oP5a5BIzAZjn9xTx98AQnBYXyTncGekgLyqy1U1duICwrhvLgkbhswnCn9h3Tqkw4K0R56XR1LzJBQMlcWUvRjFbUlNrRDE5JkJuqcIJLGR7Z6X91GRzD22b4cWFJA2YFqnA5NYKw/iaPC6XdjvLvV50QJo8IZ9nB3indWUZFZg7XMTn21Hf8QI2E9Akm6KJLul0djaHRYeo8JMZij/CjaUYnliJW6snrsVgcBESbCeweRcmkUSeMizorPcFj3QC79ayrpSwvI32qhttiGKdhIRO8gel0VQ+LoCG+X6FVK69PrlxTiVJRSuuaRl7xdhugkgl5/Eq115/+1EG5KKT152TBvlyE6ieXXp/nEZ1jG8AghhBDC50ngEUIIIYTPk8AjhBBCCJ8ngUcIIYQQPk8CjxBCCCF8ngQeIYQQQvg8CTxCCCGE8HkSeIQQQgjh8yTwCCGEEMLnSeARQgghhM+TwCOEEEIInyeBRwghhBA+TwKPEEIIIXyenC1dtLtAk1++1WGP93YdonMwG00Ftfb6BG/XIVrPGGDId9q0fIYFAAZ/VeCoc571n2EJPEIIIYTwedKlJYQQQgifJ4FHCCGEED5PAo8QQgghfJ4EHiGEEEL4PAk8QgghhPB5EniEEEII4fMk8AghhBDC50ngEUIIIYTPk8AjhBBCCJ8ngUcIIYQQPk8CjxBCCCF8ngQeIYQQQvg8CTxCCCGE8HkSeIQQQgjh8yTwCCGEEMLnSeARQgghhM+TwCOEEEIInyeBRwghhBA+TwKPEEIIIXyeBB4hhBBC+DwJPEIIIYTweRJ4hBBCCOHzJPAIIYQQwudJ4BFCCCGEz5PAI4QQQgifJ4FHCCGEED5PAo8QQgghfJ4EHiGEEEL4PAk8QgghhPB5/x8mjJGm1aECYQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(10, 5)) \n", "robust_classifier.plot_tree()\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "d451b6c3", "metadata": { "cell_id": "00010-a64753d8-356d-4c57-8ad0-03c7c908edf9", "deepnote_cell_height": 130.796875, "deepnote_cell_type": "markdown" }, "source": [ "## Example 3: UCI data example\n", "Here, we'll see the benefits of using robust optimization by perturbing the test set. We will use the MONK's Problems dataset from the UCI Machine Learning Repository.\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 39, "id": "d670f9e1", "metadata": { "cell_id": "00011-e6a08559-7fd6-4a5b-94d9-b9390eeccd3e", "deepnote_cell_height": 76, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 1, "execution_start": 1664769742991, "source_hash": "746a4dbc" }, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "from odtlearn.datasets import robust_example" ] }, { "attachments": {}, "cell_type": "markdown", "id": "d8632b13", "metadata": { "cell_id": "41f21d35d18f40339ee6a1475ca5b04d", "deepnote_cell_height": 52.390625, "deepnote_cell_type": "markdown", "tags": [] }, "source": [ "Fetch data and split to train and test" ] }, { "cell_type": "code", "execution_count": 40, "id": "44b9d106", "metadata": { "cell_id": "00012-ca63f712-e49e-423a-97e6-ef5b95341980", "deepnote_cell_height": 268.6875, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 508, "execution_start": 1664769746611, "scrolled": true, "source_hash": "6f3fb272" }, "outputs": [], "source": [ "\"\"\"Fetch data and split to train and test\"\"\"\n", "data, y = robust_example()\n", "\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " data, y, test_size=0.25, random_state=2\n", ")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "cc714a7c", "metadata": { "cell_id": "00013-6684517e-c0ae-464f-8632-05eacb7895eb", "deepnote_cell_height": 52.390625, "deepnote_cell_type": "markdown" }, "source": [ "For sake of comparison, train a classification tree that does not consider the scenario where there is a distribution shift:" ] }, { "cell_type": "code", "execution_count": 41, "id": "bdf7635f", "metadata": { "cell_id": "00014-6bf44759-2856-4316-81b4-1f9491d09c83", "deepnote_cell_height": 950.1875, "deepnote_cell_type": "code", "deepnote_output_heights": [ null, 20.1875 ], "deepnote_to_be_reexecuted": false, "execution_millis": 17487, "execution_start": 1664769775115, "scrolled": true, "source_hash": "ec914ba0" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2024-06-27\n", "Set parameter TimeLimit to value 300\n", "Set parameter NodeLimit to value 1073741824\n", "Set parameter SolutionLimit to value 1073741824\n", "Set parameter LazyConstraints to value 1\n", "Set parameter IntFeasTol to value 1e-06\n", "Set parameter Method to value 3\n", "Gurobi Optimizer version 10.0.2 build v10.0.2rc0 (mac64[arm])\n", "\n", "CPU model: Apple M1 Pro\n", "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 7 rows, 173 columns and 47 nonzeros\n", "Model fingerprint: 0xafd32360\n", "Variable types: 126 continuous, 47 integer (47 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [2e-01, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n", "Presolve removed 4 rows and 4 columns\n", "Presolve time: 0.00s\n", "Presolved: 3 rows, 169 columns, 39 nonzeros\n", "Variable types: 126 continuous, 43 integer (43 binary)\n", "Root relaxation presolved: 82 rows, 169 columns, 1072 nonzeros\n", "\n", "\n", "Root relaxation: objective 1.260000e+02, 5 iterations, 0.00 seconds (0.00 work units)\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 126.00000 0 - - 126.00000 - - 0s\n", " 0 0 125.75000 0 - - 125.75000 - - 0s\n", " 0 0 125.75000 0 7 - 125.75000 - - 0s\n", "H 0 0 77.2500000 125.75000 62.8% - 0s\n", "H 0 0 78.0000000 125.75000 61.2% - 0s\n", " 0 0 125.55000 0 13 78.00000 125.55000 61.0% - 0s\n", " 0 0 125.54167 0 14 78.00000 125.54167 61.0% - 0s\n", " 0 2 125.53640 0 23 78.00000 125.53640 60.9% - 0s\n", "* 206 151 16 81.5000000 124.91667 53.3% 30.9 0s\n", "* 934 451 8 82.2500000 112.02237 36.2% 26.9 1s\n", "* 2715 519 15 83.2500000 95.50000 14.7% 21.4 1s\n", "\n", "Cutting planes:\n", " MIR: 6\n", " Lazy constraints: 994\n", "\n", "Explored 3627 nodes (70039 simplex iterations) in 1.70 seconds (1.53 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 5: 83.25 82.25 81.5 ... 77.25\n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 8.325000000000e+01, best bound 8.325000000000e+01, gap 0.0000%\n", "\n", "User-callback calls 7707, time in user-callback 0.94 sec\n" ] }, { "data": { "text/plain": [ "RobustOCT(solver=gurobi,depth=2,time_limit=300,num_threads=None,verbose=False)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"Train a non-robust tree for comparison\"\"\"\n", "from odtlearn.robust_oct import RobustOCT\n", "\n", "# If you define no uncertainty, you get an optimal tree without regularization that maximizes accuracy\n", "non_robust_classifier = RobustOCT(solver=\"gurobi\", depth=2, time_limit=300)\n", "non_robust_classifier.fit(X_train, y_train)" ] }, { "cell_type": "markdown", "id": "dc499753", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": 42, "id": "885385b9", "metadata": { "cell_id": "cede983182b840ca830bf41e836d1abb", "deepnote_cell_height": 362.734375, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 680, "execution_start": 1664769792015, "source_hash": "388e377f", "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#########node 1\n", "Feature: Feat5 , Cutoff: 1\n", "#########node 2\n", "Feature: Feat3 , Cutoff: 2\n", "#########node 3\n", "Feature: Feat2 , Cutoff: 1\n", "#########node 4\n", "leaf 0\n", "#########node 5\n", "leaf 1\n", "#########node 6\n", "leaf 1\n", "#########node 7\n", "leaf 0\n" ] } ], "source": [ "non_robust_classifier.print_tree()" ] }, { "cell_type": "code", "execution_count": 43, "id": "f122efea", "metadata": { "cell_id": "d2858316c41d4fa0b972e1dd756b0fd1", "deepnote_cell_height": 534, "deepnote_cell_type": "code", "deepnote_output_heights": [ 406 ], "deepnote_to_be_reexecuted": false, "execution_millis": 747, "execution_start": 1664769792016, "source_hash": "3d490653", "tags": [] }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAEeCAYAAACOg886AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAAsTAAALEwEAmpwYAAA1OklEQVR4nO3deXhU9dn/8fedyUISIEBAQFZBEGQTEAS1KqVqVazirsWNgrgvVNzF6k+t1seq1Lq0PqjFDXB51Fap4gZqVZRFZRFkXwyL7JB15v79MWMECTWEJGdy8nldV64ry+TMPcmZ73zme76LuTsiIiIiYZYSdAEiIiIiVU2BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQk+BR0REREJPgUdERERCT4FHREREQi816AJEaptIemZerLigadB1SPBS0uqsjhblNwu6DpHawNw96BpEahUz88PGrQu6DEkCH53bGHe3oOsQqQ10SUtERERCT4FHREREQk+BR0REREJPgUckSRRvXsfXd5/MJ8PbMm/M0KDLEREJFc3SEkkSee/9A1IiHPL4Iixl79+LfH5NT/b77V3kHnx8JVRXPqunPM+3T1xFSnpm6feyWx1I99ve3KvjLnv5XrYt/ZrO14z7r/fV6uTf03LQlXt1X3tj2/K5LHl+NFsXz6Jk63oOeWwhqdk5gdUjIj9S4BFJEgVrl5LVslOlhJ3K4NESLLLnTUR2qwM56K73K7+gKrwvj0Up2baRtHq5e3UcS02lcd+TaH70MOb++bd7XZeIVB4FHpEkMG/MUNZPfwMwVr//DO2G3EXTo4aw8esPWDrxTvLzFpLesDltzriF3F7HAbDhq/dYOvFOCvIWkZKeSe7BJ9D2nDuIpGcyb8xQCr9fwfxHLoKUCE0OO42Wg67ii5G9dup1WPTMzUS3baLDiIcpWLuML0b2Yv/hY1jx6gNEC7bS969z2bpkFoufG832ZbNJzW5Ii0FX0GzAeXv8GIs2rWXxs7ewac5UMKPxISfT9szRpKRlEC3YyvxHL2bLgs+JlRSS3boL7c69h+w2Xfn+8zdY8dqDuMf4z7A2APR/Ymml/N23LpnFmg8nsO6TV2h9ynU0++UFe3W8rOYdyGregYK1yyqlPhGpPAo8Ikmg05VjWfD45USyc2g35C4Ati2bzby/DKXTlU+S0/lwtiz4jDn3n03m7W+R1bwDKel12H/oA2S37kLhuuXMuf9sVr35KK1OGkmnK8fuckmrvC/C66dPoscdk7HUNIo2rmb2vafR/oL7yO1zIttXzmf2n06jzj5tadDliHI/Pndn7gNDqN+xL73v/5xYUQHz/nIhy1/9M21OuxF3p3H/U+l4yeNYSoQl4+9g3sO/o9efPiH34ONp+Zurd7mkBZD/3bd8dmknUjKyaNhjIG1Ov+VnLyEVrl/F2o9fZO2HEyjJ30yTfqfQ5bqJZLfuUnqbGTcdQeH3K3Z7jH6PLyr3YxeR5KDAI5Kk8t59mn1+cVZpsKh/QD8aHnQM33/6KlknX0vOAf1Lb1tnn7Y0G3A+62e+TauTRu7V/bYaPKo0NHw3+X+pf0B/Gh9yMgDZrTrT9IhzWPvxS7sNPNuWz+GTEe1Kv2571h/IbtOVgtWL6D76TSwlhUhGFq1OvIaFT11Lm9NuJDWzHk36DS79ndanXM93b/2Nog15ZDRqXub95HTqz0F/nEKdJm0pXLecb8dew4K/XUbna54pu65ls1n87C1sW/oVjXqfwH7n/ZGcToeVeQmx591TyvW3EpGaQ4FHJEkVrlvGpjkfsmbq86Xf82iU1Mx6AGxZNJ2lE+5k+/K5xIry8ViUzOb77/X91mnc6sca1i5nw6zJOwUYj0XJ6di/rF8Fyh5Xs+7TVynZtolPL9mhPnc8FgMgWpTPkudGs2HWZEq2boBECCnZ8v1uA0+dfdru8Hkb2p37R2bc+AuihduJZGTtcvuSbRvZvmo+GY1bkd26C1ktDkia8VIiUvUUeESSVHpuC5ofexFtzxxd5s/n/3UE+xxxNp2vHkekTjarJj3Gmqkv/HgD2/nFPFInG4Bo0fbSHpyijXlE0jLZ2Y87HWTktiC39/EccPkTe/VYMnJbkFa/MX0fnlPmz1e98QhbF8+i263/IqPRvvFwdHF7HC/zsZTph9vsZrucnM6H0eehL9k4ewprP5rAspfvoV773jQ59DQa9T6+NEgCTL/hMArX7f6SVmWNIRKR6qPAI5Kkmg04nzn3nUmDbgPI6XQoHi1h65IvSc3KIatFR6L5W0jNyiFSJ5vtK+fz3TtPEtlhinZ6ThMK1iwu/TqtXi4ZuS1ZO3U8LQZdyaZ5H7Fh1mQaH3zibmtoctgZrHrzUdZNe51GPX8NwPaV8/BoMfXa9Sr3Y6nbricZuS1YOvFuWgy6gkiduhR+v4L8ld/QsMeviOZvISUtg9SsHKIFW1k68c6dfj89pwnrv1+x08yx9TPfpm7bbqQ3aEbh+lUsfuYmGnb/ZWmwK4ulRGjYbQANuw0gWrCN77/4F2s/msjCp6+jw7AxND7kJAB63fNRuR/bjtwdLy4kVlIIQKykkFhRAZaWgZm2zBIJkgKPSJKq27Y7HS99nGUv/pH8VfPBUshu05W2Z98OQPuh97P42VtZMv4O6rbtTpN+g1k/fVLp77c88WoWjbuJ5a/eT5P+p9L+gvvYf/gYFj51Lctff4BGPY6mSb/BeEnJbmvIaNScA6+bwNLxd7Bw7O/BY2Tu25HWp96wR4/FUiJ0HvkcS8ffwYzrDyWav4WM3JY0/eX5NAT2Pe4S5j8ygs8uP5C0eo1ofeqN5L3zZOnv5/Y9ibUfv8Snlx4AOP0eX8SmuR/y7RNXxYNf3YY0OugYWp9+c7lritTJZp/DzmCfw86gaONqovlb9ugxlaVw3XK+GPljEJx2+YEA9P7zdOo0ab3XxxeRitNu6SLVTLulyw+0W7pI9dGIPREREQk9BR4REREJPQUeERERCT0FHhEREQk9BR4REREJPQUeERERCT0FHhEREQk9rcMjUs0i6Zl5seKCpkHXIcFLSauzOlqU3yzoOkRqAwUeESmTmWUCtwLDgJuAse4eC7aqXZlZF+BviS+Hu3vZG3aJSK2mS1oisgsz+yXwJdAe6O7uTyRj2AFw99nAL4BngA/M7HYzqxNwWSKSZNTDIyKlzCwXuA/4FXCZu78ecEl7xMxaAH8BDgQucvcpAZckIklCPTwigsWdA3wNbAG61LSwA+DuK939FOBG4Dkz+5uZNQi4LBFJAgo8IrWcmbUF3gBuAE5y96vcfe+3Dg+Qu78CdAFKgNlmdrqZaZNOkVpMgUekljKzVDMbCXwOTAF6u/tnAZdVadx9k7tfCpwB/AF4zcxaBVuViARFgUekFjKznsAnwAlAf3f/o7sXB1xWlXD3j4CewGfAdDO7wswiAZclItVMg5ZFahEzywJuB84Drgee9lrUCJhZJ+JT2DOIT2H/MuCSRKSaqIdHpJYws2OID0reF+jm7k/VprAD4O7zgKOAvwOTzezuxHpDIhJy6uERCTkzawL8GTgcuNTd3wy4pKRgZs2Ah4BewAh3fzfgkkSkCqmHRySkElPNzyPeq7Ma6Kqw8yN3z3P3M4GRwFNmNjaxDpGIhJACj0gImVl74C3gauB4d7/W3bcFW1VySqw31IX4+kNfm9k5msIuEj4KPCIhYmZpZnYd8Cnwb6Cvu38RcFlJz923uPtVwEnE1yN6I7E+kYiEhAKPSEiYWR9gGjAQ6OPu/+PuJQGXVaMk1iHqTXxdos/NbKSZpQZclohUAg1aFqnhzKwu8P+As4HfA8/VttlXVcHMOgCPATnEp7DPCLgkEdkL6uERqcHM7Hjig5IbER+U/KzCTuVw9wXEN1F9GJhkZvcl1jESkRpIgUekBjKzpmb2AjAGGObu57v7uqDrChuPewroRnz9oq8T6xmJSA2jwCNSgySmmv8O+ApYAnR398nBVhV+7r7G3X8LXAo8bmbjEusbiUgNocAjUkOYWUfgXWAEcLS73+Du2wMuq1Zx90lAV+LrGn1tZudpCrtIzaBByyJJzszSgVHANcQHJz/s7tFgqxIz6018i4rvgYvdfWHAJYnIf6EeHpEkZmb9gC+AQ4He7v6Qwk5ySKxv1Jf4ekefmtn1ZpYWcFkishvq4RFJQmZWH7gbOIV4z84Ezb5KXma2H/Ep7E2JT2GfFnBJIvIT6uERSTJmdhIwG8ggPtV8vMJOcnP3xcCvgfuA183sgcT6SCKSJBR4RJKEme1rZi8CfwLOdffh7r4+6LqkfBJT2J8lPqi5IfFBzccHXJaIJCjwiATMzFLMbAQwC5gL9HD394OtSirK3de5+wXAMGCMmb1gZk0DLkuk1lPgEQmQmXUGPgAuAAa4+63uXhBsVVIZEusjdSe+XtJXZvY7TWEXCY4GLYsEwMwyiO/KfTnwB+Axzb4KLzPrQXwK+3bgInefH3BJIrWOAo9IxVTKE8fMWrn7iso4liQ3M4sQD7i3Ag+4+50VOUzlViVSeyjwiFRMZT1x9AJWy5hZG+ARd6/IgGadLyIVpMAjUjEKPFJhZmbuHqvIr1Z6MSK1hAYti1TA6NGjefDBB0u/vvnmm3nooYe477776NOnD927d+e2224DYNu2bZxwwgn06NGDrl27Mn78+ICqlmTxw7pKS5YsoXPnzgwfPpwuXbpwzDHHkJ+fz8yZM+nXrx/du3dn8ODBbNiwIeiSRWo8BR6RChg6dCj/+Mc/AIjFYrzwwgs0a9aMBQsW8NlnnzFz5ky++OILpkyZwqRJk9h3332ZNWsWX3/9Nb/+9a8Drl6SyYIFC7jsssuYPXs2DRo04KWXXuK8887j3nvv5csvv6Rbt27cfvvtQZcpUuMp8IhUQNu2bcnNzWXGjBm89dZb9OzZk2nTppV+3qtXL+bNm8eCBQvo1q0bb7/9Ntdffz1Tp04lJycn6PIliey3334cdNBBAPTu3ZuFCxeyceNGjjzySADOP/98pkyZEmCFIuGQGnQBIjXVsGHDeOqpp8jLy2Po0KG888473HjjjYwYMWKX206fPp033niDW265hYEDBzJ69OgAKpZklJGRUfp5JBJh48aNwRUjEmLq4RGpoMGDBzNp0iSmTZvGsccey7HHHsvYsWPZunUrACtXrmTNmjWsWrWKrKwshgwZwqhRo5g+fXrAlUsyy8nJoWHDhkydOhWAcePGlfb2iEjFqYdHpILS09MZMGAADRo0IBKJcMwxxzB37lz69+8PQN26dXnmmWf49ttvGTVqFCkpKaSlpfHoo48GXLkku6effpqLL76Y7du3065dO5588smgSxKp8TQtXaRiPBaL0atXLyZOnEiHDh0qehxNM6699rjxNbO/Ade7+8bKL0ck3HRJS2QPmVmbOXPmsP/++zNw4MC9CTsieyoGzDaz07Qvl8ieUQ+PSDkltga4ErgZ+DNwn7sXB1uV1DZmdjjwN2ABcLm7Lw+4JJEaQT08IuVgZgcBnwAnAv3d/W6FHQmCu38I9AS+AKab2eWJMC4i/4V6eET+CzPLAm4DLiC+u/lTrieNJAkz60y8tycNGO7uXwVckkjSUg+PyG6Y2dHAV0AroLu7P6mwI8nE3ecCRwJjgXfN7C4zqxNwWSJJST08Ij9hZo2Jj9E5ArjU3d8IuCSRn2VmzYExQA9ghLu/F3BJIklFPTwiCRZ3LvA1sA7oqrAjNYW7f+fupwPXAk+b2VgzaxR0XSLJQoFHBDCzdsC/gZHAIHcf6e5bAy5LZI+5+2tAV2Ab8SnsZ2kKu4gCj9RyZpZqZqOAz4C3gb7u/nnAZYnsFXff7O5XAIOJL6PwLzNrG2xVIsFS4JFay8wOBqYBRwOHuLvW1ZFQcfdPgF7Ah8DnZnaNmWlLIamVNGhZah0zqwvcAZwDjAKe0ewrCTsz6wA8DtQHhrn7zGArEqle6uGRWsXMjiM+KLkx8UHJ4xR2pDZw9wXAQOCvwL/N7N7EOlMitYJ6eKRWMLOmwINAX+Bid3872IpEgpN4PjwAHIKeD1JLqIdHQi0x1fxC4EtgGdBNjbvUdu6+2t3PAa4A/m5m/0isPyUSWgo8ElqJMQvvAJcBv3b36919e8BliSSNxDpTXYmvO/W1mZ2rKewSVrqkJaFjZunEF18bCdwJPOzuJcFWJZLcErMW/w6sJX6Za1HAJYlUKvXwSKiY2SHEd5E+HOjt7g8q7Ij8vMT6U32Jr0f1mZldpynsEibq4ZFQMLN6wF3A6cA1wHjNvhKpGDNrDzwKNCG+C7sW45QaTz08UuOZ2W+A2UA20MXdX1DYEak4d18IHEt8E91/mtmfE+tXidRYCjxSY5lZczObCPwPcL67/87d1wddl0gYeNw44oOaGxMf1HxcwGWJVJgCj9Q4ZpZiZhcRn2o+H+jh7u8FXJZIKLn7Onc/DxgOPGxmzyfW8RGpURR4JGmVNT3WzDoB7wNDgV+6+83unl/dtYnUNon1q7oRX8/qKzMb+tPnqKa0SzJT4JGklGg430pMlcXMMszsNuKbIE4ADnP3r4KsUaS2cfft7n498fE9lwLvJta7+sH7ZtY9mOpE/jsFHklW5wINgBlmdjgwg/iuzz3d/WF3jwZZnEht5u4zgH7Aq8B/zOymxPpXzwF/VU+PJCNNS5ekY2YNgLnA2cCZwG+AK4GXNftKJLmYWRviU9hbASOAh4AxiQHPIklDgUeSjpmNAQ4AugD/BG5w942BFiUiu5Xo0TmT+IakU4AjgM563koyUeCRpGJmvwQmA98DbwBRYF+g0N1PCrI2EdlVYnPeC4FVwHqgN9ATmOTuvwmyNpEdadlwSTZHEJ9qPgVYTrwRXZX4nogknxeBRcTfmOwL5ANbgdZBFiXyU+rhERERkdBTD08FRdIz82LFBVp8S0hJq7M6WpTfLOg6JNzU5sgP1OZUjHp4KsjM/LBx64IuQ5LAR+c2xt01DVeqlNoc+YHanIrROjwiIiISego8IiIiEnoKPCIiIhJ6CjwiIiISego8lax48zq+vvtkPhnelnljhgZdjoiEnNockfLRtPRKlvfePyAlwiGPL8JS9j5Pfn5NT/b77V3kHnx8JVRXPqunPM+3T1xFSnpm6feyWx1I99ve3KvjLnv5XrYt/ZrO1/y4xc7qKc+x4vWHKN60BoukUb9Tf9r99i4yGrfcq/vaGyv/9TBrPppA4dplRDLr0bjfYNqccQspqemB1SSyO2pzdq+sNicZn98b50xl+f/9D9uWfAlm9Ht8UWC1hJkCTyUrWLuUrJadKqXhqQweLcEie/5vzm51IAfd9X7lF/QTOQf+gkY9jyWtXi6xogKWvvRHFjxxJV1veHmPjxUrLiRWVEBqds5e1eQeY/9hD5LduhvFm9cy98FzWf7yn2hzxi17dVyRqqA2Z89U5vO7stqcSEY2TY/4LX7o6Sx+fvReHUt2T4GnEs0bM5T1098AjNXvP0O7IXfR9KghbPz6A5ZOvJP8vIWkN2xOmzNuIbfXcQBs+Oo9lk68k4K8RaSkZ5J78Am0PecOIumZzBszlMLvVzD/kYsgJUKTw06j5aCr+GJkLw55bGHpk2zRMzcT3baJDiMepmDtMr4Y2Yv9h49hxasPEC3YSt+/zmXrklksfm4025fNJjW7IS0GXUGzAeft8WMs2rSWxc/ewqY5U8GMxoecTNszR5OSlkG0YCvzH72YLQs+J1ZSSHbrLrQ79x6y23Tl+8/fYMVrD+Ie4z/D2gDQ/4ml1GncqvTYjmOWQkFe+d/duDub53/C2g8nsO6z1zjgsr/RsPvAPX5cO2o56MrSzzMa7cs+h53J99Ne26tjilQFtTl73ubs7fO7Ktqceu17Ua99LzbN/XCvjiP/nQJPJep05VgWPH45kewc2g25C4Bty2Yz7y9D6XTlk+R0PpwtCz5jzv1nk3n7W2Q170BKeh32H/oA2a27ULhuOXPuP5tVbz5Kq5NG0unKsbt0LxesXVauWtZPn0SPOyZjqWkUbVzN7HtPo/0F95Hb50S2r5zP7D+dRp192tKgyxHlfnzuztwHhlC/Y1963/85saIC5v3lQpa/+mfanHYj7k7j/qfS8ZLHsZQIS8bfwbyHf0evP31C7sHH0/I3V+/SvQyw+ZtPmPPnc4hu34xFUml33r0/W0v+d9+y5qOJrP1oIpaaRpNDT6PHHZPJbLpf6W0+GdFut7+fkduSnndPKdfj3jzvY7JadSnXbUWqk9qcirU5Oyrv87s62xypGgo8VSzv3afZ5xdnlT7J6x/Qj4YHHcP3n75K1snXknNA/9Lb1tmnLc0GnM/6mW/T6qSRe3W/rQaPKn039t3k/6X+Af1pfMjJAGS36kzTI85h7ccv7bbx2bZ8zk5P3rZn/YHsNl0pWL2I7qPfxFJSiGRk0erEa1j41LW0Oe1GUjPr0aTf4NLfaX3K9Xz31t8o2pBHRqPmu621/gH96Pf4Ioq3fM/q98aR2aLjbm+7cc5Ulk64k8J1y2nc9yQOuPwJ6rXvVeZtK+M6eN67T7N5wWccdOe7e30skeqgNufn25wflOf5Xd1tjlQdBZ4qVrhuGZvmfMiaqc+Xfs+jUVIz6wGwZdF0lk64k+3L5xIrysdjUTKb77/X97vjpaLCtcvZMGvyTo2Jx6LkdOxf1q8CZV9PX/fpq5Rs28Snl+xQnzseiwEQLcpnyXOj2TBrMiVbN0BiTEHJlu/L1fik1cul6VFD+GJUX/o89BWROtm73KZ48zoK8haS1bIz2W26VsrfanfWfDSRZS/dQ5frXyS9gbatkZpBbU752pzyPr+rs82RqqXAU8XSc1vQ/NiLaHtm2QPR5v91BPsccTadrx5HpE42qyY9xpqpL/x4A9t5IOIPISBatL303VTRxjwiaZns7MdtVjJyW5Db+3gOuPyJvXosGbktSKvfmL4Pzynz56veeISti2fR7dZ/kdFo33hDdXF7HC/zsZQlFi0mun0zxZvXlRl4mvQbTO7BJ7Bhxlus+Xgii5+9hQZdjqTxoafSqMfRpKTXKb3tD9fty3wsjVvS656PdvvzNR/Fj93luolkt9blLKk51Ob8fJuzJ8/v6mpzpOop8FSxZgPOZ859Z9Kg2wByOh2KR0vYuuRLUrNyyGrRkWj+FlKzcojUyWb7yvl8986TRHaYmpme04SCNYtLv06rl0tGbkvWTh1Pi0FXsmneR2yYNZnGB5+42xqaHHYGq958lHXTXqdRz18DsH3lPDxaTL12ZXfNlqVuu55k5LZg6cS7aTHoCiJ16lL4/QryV35Dwx6/Ipq/hZS0DFKzcogWbGXpxDt3+v30nCas/37FTrM4Vk95jgZdjyK9YXOKN61h8bibqNOsPRlNWu+2jpTUdHL7DCK3zyBKtm1k7SevsGrSY3z7xFUc+Pvnqd/xECA+QLEi1v7nJRY/cxMHjppA3bbdK3QMkaCozflRWW1ORZ7fVd3meCyGlxQRKykGIFZUEL/fHcKU7D0FnipWt213Ol76OMte/CP5q+aDpZDdpittz74dgPZD72fxs7eyZPwd1G3bnSb9BrN++qTS32954tUsGncTy1+9nyb9T6X9Bfex//AxLHzqWpa//gCNehxNk36D8ZKS3daQ0ag5B143gaXj72Dh2N+Dx8jctyOtT71hjx6LpUToPPI5lo6/gxnXH0o0fwsZuS1p+svzaQjse9wlzH9kBJ9dfiBp9RrR+tQbyXvnydLfz+17Ems/folPLz0AcPo9vohtS79m2Yt3U7JtM5GseuR0OpQuo8ZjVr6NgFOzG9B84IU0H3ghBWuWYJG0PXpMZVk64S6i+Vv4+u6TS7+nd2dSU6jN+e9tzt4+v6uizdn8zcc71fOf38XXITts3Lq9Prb8yNw96BpqJDNznYwC8NG5jXH38iU0kQpSmyM/UJtTMcmxUpWIiIhIFVLgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQ07T0CoqkZ+bFiguaBl2HBC8lrc7qaFG+9p6QKqU2R36gNqdiFHhkJ2Z2IPAB8Gt3/6ISjnc08DTQ191X7O3xRCRcLL7K6JNABnCO7+WLkpmlAZOB9939tkooUUJCl7SklJnVB14BrquMsAPg7m8DY4AXzSyjMo4pIqFyMdAbGLa3YQfA3YuBM4ChZrb7/S+k1lEPjwBgZinAS0Ceu19Syce2xLHXuPvFlXlsEam5zKw/8CpwmLsvqORj9wNeq4pjS82kHh75wfVAM+Dqyj5w4l3bBcBRZja0so8vIjWPmTUDJgBDqyKQuPsnwGjgZTOrW9nHl5pHPTyCmR0DPAX0cfeVVXg/nYEpwHHu/nlV3Y+IJLfEOJt3gPeqcpxNonf5f4Es4OzKuGQmNZd6eGo5M2sL/IN4Y1BlYQfA3ecCI4iP52lclfclIkntT8AW4PaqvJNEwLkM2B+4pirvS5KfenhqMTPLBD4C/uHuD1bj/d4DHEx8JlhJdd2viATPzM4B7iDeo7yhmu6zDfApcJa7v18d9ynJR4GnlqrsqaB7eN+pwJvAF+5+Q3Xdr4gEy8y6E7+UNdDdv6zm+z6aeG92Hy2RUTvpklbtValTQfdEolfnbOAsMzu1Ou9bRIJhZg2Bl4GrqzvsQOkSGQ8CL2mJjNpJPTy1kJkdCvwfcKi7fxtgHb2BScARifE9IhJCiWUvXgcWuPvVAdZhwIvAWi2RUfuoh6eW+clU0MDCDkBiccPrgFcSix6KSDiNBuoBo4IsItGbfSFwpJn9LshapPqph6cW2WEq6Lvu/oeAyyllZo8SXwPoVHePBV2PiFQeMxsEPAYc7O55QdcDYGadiC+RcYK7Twu6Hqke6uGpXe4jPhX0jqAL+YmrgebEFz8UkZAws/2BscDpyRJ2ANx9HvFxjC+aWZOg65HqoR6eWiKIqaB7wsxaAp8BF7j7W0HXIyJ7x8yygU+AR939kaDrKYuZ/RHog5bIqBUUeGqBIKeC7gkzOxIYD/Rz9yUBlyMiFZQYHPwsUARcmKwrHJtZhPjEienurh7mkNMlrZDbYSroVckcdgDc/QPgXuJ732QGXY+IVNhVQCfgkmQNOwDuHiW+RMaZZnZa0PVI1VIPT4gly1TQPZF4Z/gcUEgSvzMUkbIlemonAIfUlJ7aHZbIONLd5wRdj1QN9fCEW1JMBd0TiYAzjPiiiFonQ6QGMbMWwPPAuTUl7EDpEhmjiC+RkRN0PVI11MMTUompoI8SH6ScNLMjyisxu+Nj4CR3/0/Q9YjIf5dYvfh94DV3/2PA5VSIlsgINwWeEApLWKjpoU2kNtkhLJxSUy9FhyG0ye6lBl2AVK7EVNBXgNtqctgBcPd/mtnBwAQzG+juxUHXJCK7MrMLgV8Sf3NSI8MOgLsXJgYvTzOzL7RERriohydEdhjwW0B864ga/8+tiQOvRWqTMA743WHgdT93Xxx0PVI5NGg5XK4GOgKXhiHsACSuow8BBiUWTxSRJGFmjYGXiE8/D0XYgdIlMv6IlsgIFfXwhETYF+2rKYsnitQWYV+0b4fFE4uJrwCvF8saTj08IZDYlqHGTQXdE4mQcxXxaaMNg65HRLgTMODmoAupComAMxzoCVwScDlSCdTDU8MlZhV8ALxaG2YVmNmDQAfgRE0bFQmGmZ0CPEB8B/S1QddTlXaY9Xqyu38cdD1ScQo8NVxiKmhT4utGhP6faWZpxC9tvefutwVdj0htY2adgCnA8e7+edD1VAczOwF4nHjA0xIZNZQuadVgZjYUGEAtur6cmJp+BjA0sU6PiFQTM6tPfNmLG2tL2AFw938BfwcmJt50SQ2kHp7kUln/DKuk4ySjiv6Nwvw3EakotTnlU5G/U9j/JjWOenhEREQk9BR4ksjo0aN58MEHS7+++eabeeihh7jvvvvo06cP3bt357bb4sNWtm3bxgknnECPHj3o2rUr48ePD6jqYCxZsoTOnTszfPhwunTpwjHHHEN+fj4zZ86kX79+dO/encGDB7Nhw4agSxVJamp3ykdtTgi4uz6S5GPx4sXes2dPd3ePRqPerl07f+GFF3z48OEei8U8Go36CSec4B988IG/+OKLPmzYMP/Bxo0bfQeBP5Yq/HB398WLF3skEvEZM2a4u/vpp5/u48aN827duvn777/v7u633nqrX3XVVbXhb6IPfVT0wyup3Qn6cVTL30ltTs3+UA9PEmnbti25ubnMmDGDt956i549ezJt2rTSz3v16sW8efNYsGAB3bp14+233+b6669n6tSp5OTkBF1+tdtvv/046KCDAOjduzcLFy5k48aNHHnkkQCcf/75TJkyJcAKRZKf2p3yU5tTs2nz0CQzbNgwnnrqKfLy8hg6dCjvvPMON954IyNGjNjlttOnT+eNN97glltuYeDAgYwePTqAioOTkZFR+nkkEmHjxo3BFSNSg6ndKR+1OTWbeniSzODBg5k0aRLTpk3j2GOP5dhjj2Xs2LFs3boVgJUrV7JmzRpWrVpFVlYWQ4YMYdSoUUyfPj3gyoOXk5NDw4YNmTp1KgDjxo0rfeclIrundqdi1ObULOrhSTLp6ekMGDCABg0aEIlEOOaYY5g7dy79+/cHoG7dujzzzDN8++23jBo1ipSUFNLS0nj00UcDrjw5PP3001x88cVs376ddu3a8eSTTwZdkkjSU7tTcWpzag6tw5NcPBaL0atXLyZOnEiHDh0qepwwr/+gdXhEKo8DVEK7E/bnl9bhCQFd0koic+bMYf/992fgwIF7E3ZERMpN7Y7UFurhSS5a9fTnqYdHpPKozSkf9fCEgHp4kosBZmZZZjbdzEb+8L09/Aizcv8dzOxPZjbZzDRWTaRsOz5fzjGzRWaWi9qcnypvm7Ofma02swGBVSq7pR6eJGNmBowFMoGzXf+gCksEnUnANHe/Meh6RJKVmXUD3gV+5e6zgq6nJjOzo4Gngb7uviLoeuRH6uFJPiOAg4HfKezsHXcvAc4GzjazU4OuRyQZmVkD4jugX6Ows/fc/W1gDPCimWX83O2l+qiHJ4mYWX/gVeAwd18QdD1hYWYHA28CR7j73KDrEUkWZpYCvAYsdPergq4nLBI99S8Ba9z94qDrkTj18CQJM2sGTACGKuxULnf/HLgeeNnM6gddj0gSuRXIAa4NupAwSfTOXwAcZWZDAy5HEtTDkwTMLA2YDLzv7rcFXU9YmdljQBPgNF0ulNrOzE4AHgf6uPt3QdcTRmbWGZgCHJd44yUBUg9PcvgTsBW4PehCQu4qoAVwXdCFiATJzPYnPjniDIWdqpO4hH4x8fE8jYOup7ZTD0/AzOxs4E7gYHffEHQ9YWdmLYHPgPMTgwtFahUzywb+Azzu7n8Nup7awMzuIT4Z5deJyRQSAAWeAJlZd+AdNBW0WpnZUcALwCHuvjTYakSqT2Iw7TNACXCBLu1Wj8QSGW8CX7j7DUHXU1vpklZAzKwh8DJwtcJO9XL394lfRnzZzDIDLkekOl0JHAhcrLBTfXZYIuMsLZERHPXwBCAxFfR1YIG7Xx1wObVS4p3u80A+8ZlxeiJIqJnZEcRngvZ398VB11MbaYmMYKmHJxi3AvWAUUEXUlslAs7viF9XHxFwOSJVysxaEL+Me57CTnASM7WuA17REhnVTz081czMBgGPER+knBd0PbWdmXUAPgJ+4+6fBF2PSGVLrPb7PvC6u98dcDlC6RIZ+wCnqne5+ijwVKPEVNCPgZPc/T9B1yNxZnYi8AjxELo66HpEKpOZPQI0J/7iGgu6HikNoR8A/+fu9wRdT22hXaSrSWIq6MvAHxR2kou7v564tj7BzH7l7sVB1yRSGczsAmAg8cUFFXaShLsXmtlpwGdm9oWWyKge6uGpBokBss8CRcCF6sJMPomB5P8E5rn7yKDrEdlbZtYL+DdwpLvPCboe2ZWZHQmMB/q5+5KAywk9DVquHlcBnYBLFHaSU+Ld7xDgpMRikCI1lpnlEt+88hKFneTl7h8A9wIvaYmMqqceniqmBF+zmFkP4vua/dLdvwq6HpE9ZWYR4lOfZ7q7tlFJcokrAM8BBWiJjCqlHp4qlJgK+jzxqaBLAi5HyiGxCOTVxKeNNgi2GpEK+X9ABLgp6ELk5yUCzjC0REaVU+CpRBb3upmlJUbhvwj8xd3fCro2KT93fxb4FzDOzFLMLNfMng26LpGymNlpZjYs8flg4LfAWdqzqeZw923AKcAdZtYfwMxuNbPDgq0sXBR4KldroA/xfWoeAPIATTmsma4FGgC3EN/JfnBipp1IsvkN8fdbnYDHgdPcfW3ANckecvcFwFDis0WbAunAccFWFS4KPJWrDzANuID4VNDzdT22ZkpMTT8DuAj4FTAb6BloUSJl60P8/HwFuNHdpwVcj1SQu/8TGEt8C5DpxP+3UkkUeCpXH2AF8Y0pzwDONLNxwZYke8rMImb2MjCA+IZ/Y4FvUOMjSSaxPUFr4PfAFOATMxtrZkcHW5nsKTP7rZn9BXiKeK/yccDBiUHNUgkUeCpXf+BU4I3ExynEt5GQGsTdo8QvDVwCPA28BxwFHBJgWSJl6QWsJb7sxb7AO8C3gBY3rXn+DWwDPufHwAOwX2AVhYwCTyVJLFzXn/i4jwxgkLsf5+4fBVqYVIi7/9vdfwGcB9QFmqHr6ZJ8zgTaAPWBScB+7n63u28NtizZU+6+zt1vANoDM4FMoBFwcoBlhYrW4akkiW7HF4Gb3P2boOuRymVmfYBr3P2coGsR+YGZXUR8E8p7tSVKuCQWIrwLeM/dXw+6njBQ4BEREZHQ0yUtERERCb2k3S09kpGSFyvypkHXkSxS0m11tDDWLOg6aoLM1LS8gmiJzp2EOpHU1fklxTp3ykHnzo903pSfXq92lqyvV0l7ScvM/KT/07InP3j15Bm4u6YnloOZ+fartd7jD7IevEHnTjnp3PmRzpvy0+vVzpL19UqXtERERCT0FHhEREQk9BR4REREJPRCFXjeGj6b7z7ZGHQZUgN1+t97eO3b2UGXITWQzh2pCL1eVb+knaUVdsXbo8x6dDmrP99EJD2F/Y5vwgFnJt2gdklCt3/8Fv9cOJt569dycY/+3HfUiUGXJDWEzh2piLC8XinwBOSrv6+geGsJx/y9C4WbSvj4tm/J3CeN1gNygy5Nklz7BrncefjxPPn1Z0GXIjWMzh2piLC8XtW4wFO8PcrcZ1aRN20TxVuj1G1Rh77X70dmk/Sdbrd9bREzH17GpsX5eNRp1Cmb7he1JKtpBgBrZm5m9pMr2ba6iNSMFJr3b0CPi1sRLY7x5WPLyftsE7Gok9k4nZ5XtKZhh+xKewwlhTFWTt3A4fd0JK1uKml1U9nvhCYsm7y+xp1ANcnmwgJu+/jfvLFoLhsL8+nQsAkvDBpCy3oNdrrd8s0buWTyi3y59jtKYlEOad6GBwecRJucRgC8s3QBN079F0s2rScrLZ3ftO/CmIGDKSwp4cp3X+GNRXMpjkVpWa8Bjx19Ggc3a1Wpj2PIgb0BeGn+rEo9ruyezh2pCL1eJZcaF3hmjFlKtDDGL+49gDoNUtm0JJ+UjDKGIsWc9r9pQuNu9YiVODMfXsbMR5Zz6O37AzD9oaV0Oa8FrQY0oqQgyuYl+QAsf3c9mxbn86tHDyQ1O8K2VYVE0sse6rTig/XMenzFbmvtcOo+dDx1126/rSsLiJU4Oftlln4vZ79MFry4ek/+FLKHLnprIttLinnvzEtpll2XL9d+R53UtF1uF/MYV/T8BUe2akdRNMolk1/isnde5p+nDANg+FsTuPPw4zincy+2FRfx1drvAHhm7hd8tS6Pry4YRU5GHb7duI7MMo4PMH7eTK5+9/92W+vv+xzFtX2O2uvHLJVD545UhF6vkkuNCjwFG4v57pNNHP33LmQ2ijcGDdpllXnbrKYZpek4kg4dT2vKlOvn4zHHUoyUVGNbXiGFm4rJyEmjUae6AFiqUVIQY8uKQhp2zKJuizq7raflkY1oeWSjPX4c0fwYkToppER+XJcpLTtCSX50j48l5bN62xZeWzibb4bewL516wNw0D4tyrxtm5xGpe/I66SmcV2fARw1/hFiHiPFUkhLibBw4/es3b6VJll16bdvGwDSUiJsLSrkm/Vr6NO8FR0aNtltPWd2OogzOx1UuQ9SqoTOHakIvV4lnxoVePLXFJGSZmT9pDuwLIWbivnqiZV8P2crJdvj/5hYsVOSHyMtO0LfG9oxf2Ie71w2l6wm6XQ4tSktDm9Iq6MaUbi+mFmPLSN/XTHN+uTQ5cIWZNSvvD9VJDOFaGGMWNRLT6Li7VFSMyOVdh+ys2VbNpIRSaVV/QY/e9u127cy6oPX+WjlEjYXFQBQGC1hS1ERORl1eOHEc/nTZ+9y0NP306p+A0b1GcCpHbtzTuee5G3bwpXvvsKKLZs4oV1n7j7iBBpnVl73slQ/nTtSEXq9Sj41KvBk7pNOrNjJX1u0yzXQn5oz7juihTGO+vMBZOSksWnRdt4f+Q0kttJo0D6Lvje0w2POd59u4vP7FpPbtS51GqTR8fRmdDy9GQUbi/ni/iV888J3dL9o12vpyz9Yz6xHl++2ho6nNqXj6bt2EdZtUYeUiLF5cT4N9o8n/s2L86nfZvfpXPZO63oNKIyWsGLLxl3GXfzU6I8msb24mI/PuYImWXWZtWYV/Z8bww/bsPTcpwXPDzqXmMd4beEczv3XcxzeYj+aZtfjur4DuK7vAFZv28IFbz7P3Z9M5s8DTtrlPl6YN4Mr3nlltzWM6hM/jgRP545UhF6vkk+NCjx1GqTRrG8Osx5bzkGXtSYjcU00q3E66T9JtCXbo0QyUkjLTqVocwnzxueV/ixWHGPlhxtp2qc+6XVTScuOJ9WUFGPtl1tIrxuhXptMUjNSSElLwSJlbwnS6shGtKpAF2FqRgr7Ht6Auc99x8G/b0vhpmIW/Wstnc5pvsfHkvJpml2PQe0O5Ip3XuGRo0+laVZ8HEareg3I/cm76C1FhWSlpdEgI5Pv87dx96eTS39WFC3hxflfctx+nWhYJ4sGGfEnfWpKCu8v/5aGGVl0adyU7LR0MlLTSE0p+3r6WZ16claniu29UxyNEvUYUXeiHqOgpJiIpZAWqXnvuGoCnTtSEXq9Sj41KvAA9LqqDXP+sZIPrv2GkvwodVvGR73/VKezmzN9zFLeGPIlmblptP/NPuR9uqn05yumruersSuIFTtZTdLpPbIt6fVTKdxYzJd/W07+umIi6Sk06VGXTlWw3kD3i1ox69Fl/Pt3XxPJSKHd8Y1r3Ij3mubvx57BLR++yeHPPczW4kIOaLgPzw0assvtbul/NMP/PYF9H7udFnVzuKLX4by+cE7pz8fPm8l1H/yTomgJreo14KnjziI3M5s127ZyzbuvsmLrJjJT0xjQan9uOuRXlf44Lpv8Es/MnV769WOz/sOQzr3427FnVPp9SZzOHakIvV4lF+2WXkMk6+6zyUg7Xu9Mu16Xn86dH+m8KT+9Xu0sWV+vQrW1hIiIiEhZFHhEREQk9BR4REREJPQUeERERCT0FHhEREQk9BR4REREJPQUeERERCT0knYdnkhGSl6syJsGXUeySEm31dHCWOWvKBVCmalpeQXREp07CXUiqavzS4p17pSDzp0f6bwpP71e7SxZX6+SNvCIiIiIVBZd0hIREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdBT4BEREZHQU+ARERGR0FPgERERkdD7/4bEL28VMYRYAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(10, 5)) \n", "non_robust_classifier.plot_tree()\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "77bf18eb", "metadata": { "cell_id": "00015-511ab703-4b9f-4c99-8b26-95f27e2ee80e", "deepnote_cell_height": 97.1875, "deepnote_cell_type": "markdown" }, "source": [ "Train a robust tree. First, define the uncertainty. Here, we will generate a probability of certainty for each feature randomly (in practice, you would need to use some guess from domain knowledge). For simplicity, we will not change this probability by data sample $i$. We also define $\\lambda = 0.9$, which in practice must be tuned.\n" ] }, { "cell_type": "code", "execution_count": 44, "id": "b641c408", "metadata": { "cell_id": "00016-14b459f8-9786-4b71-9007-d9a68d7c69aa", "deepnote_cell_height": 257.390625, "deepnote_cell_type": "code", "deepnote_output_heights": [ 39.390625 ], "deepnote_to_be_reexecuted": false, "execution_millis": 680, "execution_start": 1664769798155, "scrolled": true, "source_hash": "5f369a82" }, "outputs": [ { "data": { "text/plain": [ "array([0.94967142, 0.88617357, 0.96476885, 1. , 0.87658466,\n", " 0.8765863 ])" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"Generate q_f values for each feature (i.e. probability of certainty for feature f)\"\"\"\n", "np.random.seed(42)\n", "q_f = np.random.normal(loc=0.9, scale=0.1, size=len(X_train.columns))\n", "# Snap q_f to range [0,1]\n", "q_f[q_f <= 0] = np.nextafter(np.float32(0), np.float32(1))\n", "q_f[q_f > 1] = 1.0\n", "\n", "q_f" ] }, { "attachments": {}, "cell_type": "markdown", "id": "d8118dcd", "metadata": { "cell_id": "00017-e2c44d63-a2a7-40c3-873b-173219fa4020", "deepnote_cell_height": 52.390625, "deepnote_cell_type": "markdown" }, "source": [ "Calibrate the `costs` and `budget` parameters for the `fit` function." ] }, { "cell_type": "code", "execution_count": 45, "id": "7a563a91", "metadata": { "cell_id": "00018-8348cb86-a857-4d9d-a5ee-44cda4446659", "deepnote_cell_height": 184.1875, "deepnote_cell_type": "code", "deepnote_output_heights": [ 20.1875 ], "deepnote_to_be_reexecuted": false, "execution_millis": 334, "execution_start": 1664769801529, "source_hash": "8febf87c" }, "outputs": [ { "data": { "text/plain": [ "13.275424972886112" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"Define budget of uncertainty\"\"\"\n", "from math import log\n", "\n", "l = 0.9 # Lambda value between 0 and 1\n", "budget = -1 * X_train.shape[0] * log(l)\n", "budget" ] }, { "cell_type": "code", "execution_count": 46, "id": "68ef855d", "metadata": { "cell_id": "00019-a1add7b6-8e21-46a1-87b6-e6a2d74ef071", "deepnote_cell_height": 793, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 28, "execution_start": 1664769805562, "scrolled": true, "source_hash": "7f3949b" }, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Feat0Feat1Feat2Feat3Feat4Feat5
02.9891822.1730813.34582514.2754252.09222.092213
12.9891822.1730813.34582514.2754252.09222.092213
22.9891822.1730813.34582514.2754252.09222.092213
32.9891822.1730813.34582514.2754252.09222.092213
42.9891822.1730813.34582514.2754252.09222.092213
.....................
1212.9891822.1730813.34582514.2754252.09222.092213
1222.9891822.1730813.34582514.2754252.09222.092213
1232.9891822.1730813.34582514.2754252.09222.092213
1242.9891822.1730813.34582514.2754252.09222.092213
1252.9891822.1730813.34582514.2754252.09222.092213
\n", "

126 rows × 6 columns

\n", "
" ], "text/plain": [ " Feat0 Feat1 Feat2 Feat3 Feat4 Feat5\n", "0 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "1 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "2 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "3 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "4 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", ".. ... ... ... ... ... ...\n", "121 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "122 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "123 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "124 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "125 2.989182 2.173081 3.345825 14.275425 2.0922 2.092213\n", "\n", "[126 rows x 6 columns]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"Based on q_f values, create costs of uncertainty\"\"\"\n", "from copy import deepcopy\n", "\n", "costs = deepcopy(X_train)\n", "costs = costs.astype(\"float\")\n", "for f in range(len(q_f)):\n", " if q_f[f] == 1:\n", " costs[costs.columns[f]] = budget + 1 # no uncertainty = \"infinite\" cost\n", " else:\n", " costs[costs.columns[f]] = -1 * log(1 - q_f[f])\n", "\n", "costs" ] }, { "attachments": {}, "cell_type": "markdown", "id": "873b1077", "metadata": { "cell_id": "873b53227f2847c48fd956daa42241d6", "deepnote_cell_height": 52.390625, "deepnote_cell_type": "markdown", "tags": [] }, "source": [ "Train the robust tree using the costs and budget." ] }, { "cell_type": "code", "execution_count": 47, "id": "8dc237ab", "metadata": { "cell_id": "00020-17db6a05-404c-4fb0-9b35-d58abc3aa541", "deepnote_cell_height": 184.1875, "deepnote_cell_type": "code", "deepnote_output_heights": [ 20.1875 ], "deepnote_to_be_reexecuted": false, "execution_millis": 115497, "execution_start": 1664769815612, "scrolled": true, "source_hash": "ae6f9fa2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2024-06-27\n", "Set parameter TimeLimit to value 200\n", "Set parameter NodeLimit to value 1073741824\n", "Set parameter SolutionLimit to value 1073741824\n", "Set parameter LazyConstraints to value 1\n", "Set parameter IntFeasTol to value 1e-06\n", "Set parameter Method to value 3\n", "Gurobi Optimizer version 10.0.2 build v10.0.2rc0 (mac64[arm])\n", "\n", "CPU model: Apple M1 Pro\n", "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 7 rows, 173 columns and 47 nonzeros\n", "Model fingerprint: 0xafd32360\n", "Variable types: 126 continuous, 47 integer (47 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [2e-01, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n", "Presolve removed 4 rows and 4 columns\n", "Presolve time: 0.00s\n", "Presolved: 3 rows, 169 columns, 39 nonzeros\n", "Variable types: 126 continuous, 43 integer (43 binary)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Root relaxation presolved: 82 rows, 169 columns, 1072 nonzeros\n", "\n", "\n", "Root relaxation: objective 1.260000e+02, 5 iterations, 0.00 seconds (0.00 work units)\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 126.00000 0 - - 126.00000 - - 0s\n", " 0 0 125.75000 0 - - 125.75000 - - 0s\n", " 0 0 125.75000 0 7 - 125.75000 - - 0s\n", "H 0 0 77.2500000 125.75000 62.8% - 0s\n", "H 0 0 78.0000000 125.75000 61.2% - 0s\n", " 0 0 125.55000 0 13 78.00000 125.55000 61.0% - 0s\n", " 0 0 125.54167 0 14 78.00000 125.54167 61.0% - 0s\n", " 0 2 125.53640 0 23 78.00000 125.53640 60.9% - 0s\n", "* 472 333 14 78.5000000 122.24074 55.7% 29.0 1s\n", "* 2519 887 14 79.5000000 99.00000 24.5% 20.5 3s\n", " 3648 758 85.00000 20 2 79.50000 90.91667 14.4% 19.2 5s\n", "\n", "Cutting planes:\n", " MIR: 6\n", " Lazy constraints: 1319\n", "\n", "Explored 5135 nodes (84698 simplex iterations) in 8.19 seconds (3.26 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 4: 79.5 78.5 78 77.25 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 7.950000000000e+01, best bound 7.950000000000e+01, gap 0.0000%\n", "\n", "User-callback calls 11149, time in user-callback 6.77 sec\n" ] }, { "data": { "text/plain": [ "RobustOCT(solver=gurobi,depth=2,time_limit=200,num_threads=None,verbose=False)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "robust_classifier = RobustOCT(\n", " solver=\"gurobi\",\n", " depth=2,\n", " time_limit=200,\n", ")\n", "robust_classifier.fit(X_train, y_train, costs=costs, budget=budget)" ] }, { "cell_type": "code", "execution_count": 48, "id": "5ee04af2", "metadata": { "cell_id": "6ea60076b5ff4d4db35fef0d61992e3c", "deepnote_cell_height": 362.734375, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 2, "execution_start": 1664769931108, "source_hash": "a3f1115a", "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#########node 1\n", "Feature: Feat3 , Cutoff: 2\n", "#########node 2\n", "leaf 0\n", "#########node 3\n", "Feature: Feat2 , Cutoff: 1\n", "#########node 4\n", "pruned\n", "#########node 5\n", "pruned\n", "#########node 6\n", "leaf 1\n", "#########node 7\n", "leaf 0\n" ] } ], "source": [ "robust_classifier.print_tree()" ] }, { "cell_type": "code", "execution_count": 49, "id": "986d5b8f", "metadata": { "cell_id": "02b308f6ab99429d8ffe4d3f4ae0ada7", "deepnote_cell_height": 534, "deepnote_cell_type": "code", "deepnote_output_heights": [ 406 ], "deepnote_to_be_reexecuted": false, "execution_millis": 389, "execution_start": 1664769931109, "source_hash": "fbc9df0d", "tags": [] }, "outputs": [ { "data": { "image/png": "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x461/fr1s2VlZfZQY8eOtfHx8ba2ttZaa+1pp51mx48fb4+Bu5+7Jz2stdY++OCDFrBTp05t8EJfeeWVNjIy0lpr7fr16y1gb7755gZtDm67cOFC/Y700EOPFn+oh0fc4qabbqKyspK33367ftm7775LRUUFN954I3l5eXzxxRdMmjSJ0tJScnJy6h/jxo0jLS2N7du3AxAaGsqmTZvqf5bWN23atAY/n3vuueTm5lJUVMTHH38MwD333NOgzfTp03E4HPXrRURakgKPuEXfvn0ZPnx4g6GpefPm0b9/f4YMGUJKSgrWWh566CGio6MbPGbMmAFAVpbrUjB/+tOfKCwspHfv3vTv35977rmH5ORktzyv9ioxMbHBz+Hh4QDk5+ezZ88ejDH06tWrQZvQ0FDi4uJITU1trTJFpB3zdncB0n5NmTKFO++8k9TUVLy9vfn222959NFHAaitrQVcvQCXXHJJk9sPGDAAgFGjRrFz504WLlzI559/zty5c3n66ad57LHHmDlzZus8mXbO4XA0udxazc8RkbZBgUfc5tprr2XGjBnMmzcPX19fAK6//noAunfvDoC3tzcXXnjhUfcVHh7OlClTmDJlCuXl5VxyySU8+OCDzJgx47BfxtI6unTpgrWW7du3M3DgwPrlRUVFHDhwgEsvvdSN1YlIe6EhLXGbyMhIxo8fz7x583j99de54IIL6Ny5MwAxMTFccMEFvPjii6SlpTXaNjs7u/7/c3NzG6wLCAigT58+VFRU6LTnNmD8+PEAPP300w2WP/PMMzidTgUeEWkV6uERt5oyZQpXXnklAK+++mqDdf/85z8ZOXIkgwYNYtq0afTo0YOsrCxWrFjB5s2bSUlJAVzzgUaNGsXw4cOJiopi/fr1vPTSS1x66aV06NChtZ+S/I9BgwZxyy238PLLL1NYWMjo0aNZs2YNr7zyCuPGjTvskKWIyMmkwCNuNX78eKKioigrK2PixIkN1vXu3Zvk5GRmzZrF3LlzycnJITo6msGDB/Pwww/Xt7v77rtZsGABX331FeXl5SQkJHDfffdx7733tvbTkcN44YUX6NatG6+88goLFiwgNjaW3/3ud8yaNQtjdPssEWl5unmotLYGbzin00nnzp0ZPXo0r7/+eksfW9+sJ49uHioipxTN4RG3WrhwIRkZGdx0003uLkVERDyYenik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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(10, 5))\n", "robust_classifier.plot_tree()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 50, "id": "cf5d1de9", "metadata": { "cell_id": "00021-3cc7fda4-c89b-43f7-bbf4-7e6ca8a7298e", "deepnote_cell_height": 260.78125, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 7, "execution_start": 1664769931564, "source_hash": "e4bb380a" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Non-robust training accuracy: 0.6666666666666666\n", "Robust training accuracy: 0.6587301587301587\n", "Non-robust test accuracy: 0.5813953488372093\n", "Robust test accuracy: 0.5581395348837209\n" ] } ], "source": [ "from sklearn.metrics import accuracy_score\n", "\n", "print(\n", " \"Non-robust training accuracy: \",\n", " accuracy_score(y_train, non_robust_classifier.predict(X_train)),\n", ")\n", "print(\n", " \"Robust training accuracy: \",\n", " accuracy_score(y_train, robust_classifier.predict(X_train)),\n", ")\n", "print(\n", " \"Non-robust test accuracy: \",\n", " accuracy_score(y_test, non_robust_classifier.predict(X_test)),\n", ")\n", "print(\n", " \"Robust test accuracy: \",\n", " accuracy_score(y_test, robust_classifier.predict(X_test)),\n", ")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "10f24f30", "metadata": { "cell_id": "00022-17f6f113-6d42-41de-97a4-425263e19c21", "deepnote_cell_height": 74.796875, "deepnote_cell_type": "markdown" }, "source": [ "To measure the performance of the trained models, perturb the test data based off of our known certainties of each feature (to simulate a distribtion shift), and then see how well each tree performs against the perturbed data\n" ] }, { "cell_type": "code", "execution_count": 51, "id": "785bec50", "metadata": { "cell_id": "00023-6873bd0d-ac31-4d00-9fd8-74d79f46f931", "deepnote_cell_height": 454, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 5400, "execution_start": 1664769931576, "source_hash": "fa02f8dd" }, "outputs": [], "source": [ "def perturb(data, q_f, seed):\n", " \"\"\"Perturb X given q_f based off of the symmetric geometric distribution\"\"\"\n", " new_data = deepcopy(data)\n", " np.random.seed(seed)\n", " # Perturbation of features\n", " for f in range(len(new_data.columns)):\n", " perturbations = np.random.geometric(q_f[f], size=new_data.shape[0])\n", " perturbations = perturbations - 1 # Support should be 0,1,2,...\n", " signs = (2 * np.random.binomial(1, 0.5, size=new_data.shape[0])) - 1\n", " perturbations = perturbations * signs\n", " new_data[new_data.columns[f]] = new_data[new_data.columns[f]] + perturbations\n", " return new_data\n", "\n", "\n", "\"\"\"Obtain 1000 different perturbed test sets, and record accuracies\"\"\"\n", "non_robust_acc = []\n", "robust_acc = []\n", "for s in range(1, 1001):\n", " X_test_perturbed = perturb(X_test, q_f, s)\n", " non_robust_pred = non_robust_classifier.predict(X_test_perturbed)\n", " robust_pred = robust_classifier.predict(X_test_perturbed)\n", " non_robust_acc += [accuracy_score(y_test, non_robust_pred)]\n", " robust_acc += [accuracy_score(y_test, robust_pred)]" ] }, { "cell_type": "code", "execution_count": 52, "id": "0b6a4289", "metadata": { "cell_id": "00024-32351bf0-26fb-4ff1-9892-f9e0b484ca12", "deepnote_cell_height": 219.78125, "deepnote_cell_type": "code", "deepnote_to_be_reexecuted": false, "execution_millis": 4, "execution_start": 1664769936979, "source_hash": "8fcb1c0a" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Worst-case accuracy (Non-Robust Tree): 0.4418604651162791\n", "Worst-case accuracy (Robust Tree): 0.5116279069767442\n", "Average accuracy (Non-Robust Tree): 0.5660930232558059\n", "Average accuracy (Robust Tree): 0.5584186046511533\n" ] } ], "source": [ "print(\"Worst-case accuracy (Non-Robust Tree): \", min(non_robust_acc))\n", "print(\"Worst-case accuracy (Robust Tree): \", min(robust_acc))\n", "print(\n", " \"Average accuracy (Non-Robust Tree): \", sum(non_robust_acc) / len(non_robust_acc)\n", ")\n", "print(\"Average accuracy (Robust Tree): \", sum(robust_acc) / len(robust_acc))" ] }, { "attachments": {}, "cell_type": "markdown", "id": "117c0143", "metadata": { "cell_id": "6e94893cd87747d48562368a596e05cc", "deepnote_cell_height": 341.59375, "deepnote_cell_type": "markdown", "tags": [] }, "source": [ "## References\n", "* Justin, N., Aghaei, S., Gómez, A., & Vayanos, P. (2022). Optimal robust classification trees. *The AAAI-2022 Workshop on Adversarial Machine Learning and Beyond*. https://openreview.net/pdf?id=HbasA9ysA3\n", "* Dua, D. and Graff, C. (2019). [UCI Machine Learning Repository](http://archive.ics.uci.edu/ml). Irvine, CA: University of California, School of Information and Computer Science." ] } ], "metadata": { "deepnote": {}, "deepnote_execution_queue": [], "deepnote_notebook_id": "48fbaca3-de19-4cc4-b8bd-5da9f4b14110", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 5 }