intro.html 36.25 KiB
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-99.9.9">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Endogenous Macrodynamics in Algorithmic Recourse - 1 Introduction</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { color: #008000; } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { color: #008000; font-weight: bold; } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
<script src="site_libs/quarto-nav/headroom.min.js"></script>
<script src="site_libs/clipboard/clipboard.min.js"></script>
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
<script src="site_libs/quarto-search/fuse.min.js"></script>
<script src="site_libs/quarto-search/quarto-search.js"></script>
<meta name="quarto:offset" content="./">
<link href="./sections/data_preprocessing/index.html" rel="next">
<link href="./index.html" rel="prev">
<script src="site_libs/quarto-html/quarto.js"></script>
<script src="site_libs/quarto-html/popper.min.js"></script>
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
<script src="site_libs/quarto-html/anchor.min.js"></script>
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
<script id="quarto-search-options" type="application/json">{
"location": "sidebar",
"copy-button": false,
"collapse-after": 3,
"panel-placement": "start",
"type": "textbox",
"limit": 20,
"language": {
"search-no-results-text": "No results",
"search-matching-documents-text": "matching documents",
"search-copy-link-title": "Copy link to search",
"search-hide-matches-text": "Hide additional matches",
"search-more-match-text": "more match in this document",
"search-more-matches-text": "more matches in this document",
"search-clear-button-title": "Clear",
"search-detached-cancel-button-title": "Cancel",
"search-submit-button-title": "Submit"
}
}</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
</head>
<body class="nav-sidebar floating">
<div id="quarto-search-results"></div>
<header id="quarto-header" class="headroom fixed-top">
<nav class="quarto-secondary-nav" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
<div class="container-fluid d-flex justify-content-between">
<h1 class="quarto-secondary-nav-title"><span class="chapter-number">1</span> <span class="chapter-title">Introduction</span></h1>
<button type="button" class="quarto-btn-toggle btn" aria-label="Show secondary navigation">
<i class="bi bi-chevron-right"></i>
</button>
</div>
</nav>
</header>
<!-- content -->
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article">
<!-- sidebar -->
<nav id="quarto-sidebar" class="sidebar collapse sidebar-navigation floating overflow-auto">
<div class="pt-lg-2 mt-2 text-left sidebar-header">
<div class="sidebar-title mb-0 py-0">
<a href="./">Endogenous Macrodynamics in Algorithmic Recourse</a>
</div>
</div>
<div class="mt-2 flex-shrink-0 align-items-center">
<div class="sidebar-search">
<div id="quarto-search" class="" title="Search"></div>
</div>
</div>
<div class="sidebar-menu-container">
<ul class="list-unstyled mt-1">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./index.html" class="sidebar-item-text sidebar-link">Preface</a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./intro.html" class="sidebar-item-text sidebar-link active"><span class="chapter-number">1</span> <span class="chapter-title">Introduction</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./sections/data_preprocessing/index.html" class="sidebar-item-text sidebar-link"><span class="chapter-number">2</span> <span class="chapter-title">Data Preprocessing</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./sections/experiments/index.html" class="sidebar-item-text sidebar-link"><span class="chapter-number">3</span> <span class="chapter-title">Experimental Results</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./sections/generators/index.html" class="sidebar-item-text sidebar-link"><span class="chapter-number">4</span> <span class="chapter-title">Generators</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./references.html" class="sidebar-item-text sidebar-link">References</a>
</div>
</li>
</ul>
</div>
</nav>
<!-- margin-sidebar -->
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
<nav id="TOC" role="doc-toc" class="toc-active">
<h2 id="toc-title">Table of contents</h2>
<ul>
<li><a href="#data" id="toc-data" class="nav-link active" data-scroll-target="#data"><span class="toc-section-number">1.1</span> Data</a></li>
<li><a href="#classifier" id="toc-classifier" class="nav-link" data-scroll-target="#classifier"><span class="toc-section-number">1.2</span> Classifier</a></li>
<li><a href="#implementation-of-recourse" id="toc-implementation-of-recourse" class="nav-link" data-scroll-target="#implementation-of-recourse"><span class="toc-section-number">1.3</span> Implementation of Recourse</a></li>
<li><a href="#generate-counterfactual" id="toc-generate-counterfactual" class="nav-link" data-scroll-target="#generate-counterfactual"><span class="toc-section-number">1.4</span> Generate counterfactual</a></li>
<li><a href="#retrain" id="toc-retrain" class="nav-link" data-scroll-target="#retrain"><span class="toc-section-number">1.5</span> Retrain</a></li>
<li><a href="#repeat" id="toc-repeat" class="nav-link" data-scroll-target="#repeat"><span class="toc-section-number">1.6</span> Repeat</a></li>
</ul>
</nav>
</div>
<!-- main -->
<main class="content" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<h1 class="title d-none d-lg-block"><span class="chapter-number">1</span> <span class="chapter-title">Introduction</span></h1>
</div>
<div class="quarto-title-meta">
</div>
</header>
<p>To start with, we will look at a proof-of-concept that demonstrates the main observation underlying that paper is framed around. In particular, we will use synthetic data to see how endogenous domain shifts and the resulting model shifts can have implications on the validity and cost of algorithmic recourse.</p>
<section id="data" class="level2" data-number="1.1">
<h2 data-number="1.1" class="anchored" data-anchor-id="data"><span class="header-section-number">1.1</span> Data</h2>
<p>We begin by generating the synthetic data for a simple binary classification problem. For illustrative purposes we will use data that is linearly separable. The chart below shows the data <span class="math inline">\(\mathcal{D}\)</span> at time zero, before any implementation of recourse.</p>
<div class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>N <span class="op">=</span> <span class="fl">1000</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>xmax <span class="op">=</span> <span class="fl">2</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>X, ys <span class="op">=</span> <span class="fu">make_blobs</span>(</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> N, <span class="fl">2</span>; </span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> centers<span class="op">=</span><span class="fl">2</span>, as_table<span class="op">=</span><span class="cn">false</span>, center_box<span class="op">=</span>(<span class="op">-</span>xmax <span class="op">=></span> xmax), cluster_std<span class="op">=</span><span class="fl">0.1</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>)</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>ys <span class="op">.=</span> ys<span class="op">.==</span><span class="fl">2</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>X <span class="op">=</span> X<span class="op">'</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>xs <span class="op">=</span> Flux.<span class="fu">unstack</span>(X,<span class="fl">2</span>)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>data <span class="op">=</span> <span class="fu">zip</span>(xs,ys)</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>counterfactual_data <span class="op">=</span> <span class="fu">CounterfactualData</span>(X,ys<span class="op">'</span>)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="fu">plot</span>()</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="fu">scatter!</span>(counterfactual_data)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-display" data-execution_count="3">
<div id="fig-data" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="intro_files/figure-html/fig-data-output-1.svg" class="img-fluid figure-img"></p>
<p></p><figcaption class="figure-caption">Figure 1.1: Linearly separable synthetic data</figcaption><p></p>
</figure>
</div>
</div>
</div>
</section>
<section id="classifier" class="level2" data-number="1.2">
<h2 data-number="1.2" class="anchored" data-anchor-id="classifier"><span class="header-section-number">1.2</span> Classifier</h2>
<p>To model this data <span class="math inline">\(\mathcal{D}\)</span> we will use a linear classifier. In particular, as in the paper, we will build a logistic regression model in <code>Flux.jl</code>: a single layer with sigmoid activation.</p>
<div class="cell" data-execution_count="3">
<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>n_epochs <span class="op">=</span> <span class="fl">100</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>model <span class="op">=</span> <span class="fu">Chain</span>(<span class="fu">Dense</span>(<span class="fl">2</span>,<span class="fl">1</span>))</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>mod <span class="op">=</span> <span class="fu">FluxModel</span>(model)</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>Models.<span class="fu">train</span>(mod, counterfactual_data; n_epochs<span class="op">=</span>n_epochs)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p><a href="#fig-model">Figure <span>1.2</span></a> below shows the linear separation of the two classes.</p>
<div class="cell" data-execution_count="4">
<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>plt_original <span class="op">=</span> <span class="fu">plot</span>(mod, counterfactual_data; zoom<span class="op">=</span><span class="fl">0</span>, colorbar<span class="op">=</span><span class="cn">false</span>, title<span class="op">=</span><span class="st">"(a)"</span>)</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(plt_original)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-display">
<div id="fig-model" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="intro_files/figure-html/fig-model-output-1.svg" class="img-fluid figure-img"></p>
<p></p><figcaption class="figure-caption">Figure 1.2: The baseline model: contours indicate the predicted label; dots indicate observed data points.</figcaption><p></p>
</figure>
</div>
</div>
</div>
</section>
<section id="implementation-of-recourse" class="level2" data-number="1.3">
<h2 data-number="1.3" class="anchored" data-anchor-id="implementation-of-recourse"><span class="header-section-number">1.3</span> Implementation of Recourse</h2>
</section>
<section id="generate-counterfactual" class="level2" data-number="1.4">
<h2 data-number="1.4" class="anchored" data-anchor-id="generate-counterfactual"><span class="header-section-number">1.4</span> Generate counterfactual</h2>
<div class="cell" data-execution_count="5">
<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>γ <span class="op">=</span> <span class="fl">0.50</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>μ <span class="op">=</span> <span class="fl">0.10</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>Markdown.<span class="fu">parse</span>(</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"""</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="st"> To generate counterfactual explanations we will rely on the most generic approach. As our decision threshold we will use </span><span class="sc">$</span>(γ<span class="op">*</span><span class="fl">100</span>)<span class="st">% here. In other words, the counterfactual is considered as valid, as soon as the classifier is more convinced that it belongs to the target class (blue) than the non-target class (orange). In each round we will implement recourse for </span><span class="sc">$</span>(μ <span class="op">*</span> <span class="fl">100</span>)<span class="st">% of the individuals in the non-target class. </span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="st"> """</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<div class="cell" data-execution_count="6">
<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>opt <span class="op">=</span> Flux.<span class="fu">Adam</span>(<span class="fl">0.01</span>)</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>gen <span class="op">=</span> <span class="fu">GenericGenerator</span>(;decision_threshold<span class="op">=</span>γ, opt<span class="op">=</span>opt)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p><a href="#fig-round-1">Figure <span>1.3</span></a> below shows the recourse outcome, which we denote here as <span class="math inline">\(\mathcal{D}^{\prime}\)</span>. The obvious observation at this point is that the resulting counterfactuals, while valid, are clearly distinguishable from the factuals that were always in the target class. This is not a new observation and nor is it entirely surprising. In fact, a lot of recent work in this field has tried to address this issue. In this work we wonder what happens when we let these sorts of dynamics play out further in practice. While the outcome in (b) is not surprising, it may be much harder to observe so clearly it in practice (when the data is more complex).</p>
<div class="cell" data-execution_count="7">
<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>candidates <span class="op">=</span> <span class="fu">findall</span>(ys<span class="op">.==</span><span class="fl">0</span>)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>chosen_individuals <span class="op">=</span> <span class="fu">rand</span>(candidates, <span class="fu">Int</span>(<span class="fu">round</span>(<span class="fu">μ*length</span>(candidates))))</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>X′ <span class="op">=</span> <span class="fu">copy</span>(X)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>y′ <span class="op">=</span> <span class="fu">copy</span>(ys)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>factuals <span class="op">=</span> <span class="fu">select_factual</span>(counterfactual_data,chosen_individuals)</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>outcome <span class="op">=</span> <span class="fu">generate_counterfactual</span>(factuals, <span class="fl">1</span>, counterfactual_data, mod, gen; initialization<span class="op">=:</span>identity)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>X′[<span class="op">:</span>,chosen_individuals] <span class="op">=</span> <span class="fu">reduce</span>(hcat, @.(<span class="fu">selectdim</span>(<span class="fu">counterfactual</span>(outcome), <span class="fl">3</span>, <span class="fl">1</span>)))</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>y′[chosen_individuals] <span class="op">=</span> <span class="fu">reduce</span>(vcat,@.(<span class="fu">selectdim</span>(<span class="fu">counterfactual_label</span>(outcome),<span class="fl">3</span>,<span class="fl">1</span>)))</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>counterfactual_data′ <span class="op">=</span> <span class="fu">CounterfactualData</span>(X′,y′<span class="ch">')</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>plt_single <span class="op">=</span> <span class="fu">plot</span>(mod,counterfactual_data′;zoom<span class="op">=</span><span class="fl">0</span>,colorbar<span class="op">=</span><span class="cn">false</span>,title<span class="op">=</span><span class="st">"(b)"</span>)</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(plt_single)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-display">
<div id="fig-round-1" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="intro_files/figure-html/fig-round-1-output-1.svg" class="img-fluid figure-img"></p>
<p></p><figcaption class="figure-caption">Figure 1.3: The recourse outcome after one round.</figcaption><p></p>
</figure>
</div>
</div>
</div>
</section>
<section id="retrain" class="level2" data-number="1.5">
<h2 data-number="1.5" class="anchored" data-anchor-id="retrain"><span class="header-section-number">1.5</span> Retrain</h2>
<p>Suppose the agent in charge of the black-box system has provided recourse to a share of individuals leading to the outcome in <a href="#fig-round-1">Figure <span>1.3</span></a>. In practice, models are regularly updated through retraining to account for concept drift, for example. For our experiments, we assume that the agent accepts <span class="math inline">\(\mathcal{D}^{\prime}\)</span> as its new ground truth. To isolate the endogenous effects we are interested in here from any other effect, we further assume away any exogenous changes to the data that we might expect to occur in practice. Retraining the model on <span class="math inline">\(\mathcal{D}^{\prime}\)</span> leads to a shift of the decision boundary <strong>in the direction of the non-target class</strong> (<a href="#fig-retrain">Figure <span>1.4</span></a>).</p>
<div class="cell" data-execution_count="8">
<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>mod <span class="op">=</span> Models.<span class="fu">train</span>(mod, counterfactual_data′)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>plt_single_retrained <span class="op">=</span> <span class="fu">plot</span>(mod,counterfactual_data′;zoom<span class="op">=</span><span class="fl">0</span>,colorbar<span class="op">=</span><span class="cn">false</span>,title<span class="op">=</span><span class="st">"(c)"</span>)</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(plt_single_retrained)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-display">
<div id="fig-retrain" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="intro_files/figure-html/fig-retrain-output-1.svg" class="img-fluid figure-img"></p>
<p></p><figcaption class="figure-caption">Figure 1.4: The retrained model.</figcaption><p></p>
</figure>
</div>
</div>
</div>
</section>
<section id="repeat" class="level2" data-number="1.6">
<h2 data-number="1.6" class="anchored" data-anchor-id="repeat"><span class="header-section-number">1.6</span> Repeat</h2>
<p>We finally go on to repeat this process of recourse followed by model updates for multiple round. <a href="#fig-final">Figure <span>1.5</span></a> below presents the different stages of the experiment side-by-side, where panel (d) represents the outcome after ten rounds.</p>
<p>At first glance it seems that costs to individuals seeking recourse are gradually reduced as the decision boundary moves into the direction of the non-target class: they need to exert less effort to move to valid counterfactual states. The problem with this idea is, of course, that there is no free lunch. This reduction inflicts a burden on the agent in charge of the black-box: the group of individuals that is now classified as target class individuals looks entirely different from the original group.</p>
<p>Why is this a problem? Let’s, for example, that the two synthetic features accurately describe the credit worthiness of individual seeking loans, where credit-worthiness increases in the South-West direction. Non-target class individuals (orange) are denied credit, while target class individuals (blue) receive a loan. Then the population of borrowers in (d) is much more risky than in (a). Clearly, any lender (bank) aware of such dynamics would avoid them in practice. They might choose not to offer recourse in the first place, generating a cost to all individuals seeking recourse. Alternatively, they may reward first movers, but stop offering recourse after a few rounds.</p>
<p>This last point makes it clear that the implementation of recourse by one individual may generate external costs for other individuals. This notion motivates the ideas set out in the paper.</p>
<div class="cell" data-execution_count="9">
<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>i <span class="op">=</span> <span class="fl">2</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> i <span class="op"><=</span> <span class="fl">10</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> counterfactual_data′ <span class="op">=</span> <span class="fu">CounterfactualData</span>(X′,y′<span class="ch">')</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> candidates <span class="op">=</span> <span class="fu">findall</span>(y′<span class="op">.==</span><span class="fl">0</span>)</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> chosen_individuals <span class="op">=</span> <span class="fu">rand</span>(candidates, <span class="fu">Int</span>(<span class="fu">round</span>(<span class="fu">μ*length</span>(candidates))))</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> Models.<span class="fu">train</span>(mod, counterfactual_data′)</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> factuals <span class="op">=</span> <span class="fu">select_factual</span>(counterfactual_data′,chosen_individuals)</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> outcome <span class="op">=</span> <span class="fu">generate_counterfactual</span>(factuals, <span class="fl">1</span>, counterfactual_data′, mod, gen; initialization<span class="op">=:</span>identity)</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> X′[<span class="op">:</span>,chosen_individuals] <span class="op">=</span> <span class="fu">reduce</span>(hcat, @.(<span class="fu">selectdim</span>(<span class="fu">counterfactual</span>(outcome), <span class="fl">3</span>, <span class="fl">1</span>)))</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> y′[chosen_individuals] <span class="op">=</span> <span class="fu">reduce</span>(vcat,@.(<span class="fu">selectdim</span>(<span class="fu">counterfactual_label</span>(outcome),<span class="fl">3</span>,<span class="fl">1</span>)))</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> i <span class="op">+=</span> <span class="fl">1</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="cf">end</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>plt_single_repeat <span class="op">=</span> <span class="fu">plot</span>(mod,counterfactual_data′;zoom<span class="op">=</span><span class="fl">0</span>,colorbar<span class="op">=</span><span class="cn">false</span>,title<span class="op">=</span><span class="st">"(d)"</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<div class="cell" data-execution_count="10">
<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>plt <span class="op">=</span> <span class="fu">plot</span>(plt_original, plt_single, plt_single_retrained, plt_single_repeat, layout<span class="op">=</span>(<span class="fl">1</span>,<span class="fl">4</span>), legend<span class="op">=</span><span class="cn">false</span>, axis<span class="op">=</span><span class="cn">nothing</span>, size<span class="op">=</span>(<span class="fl">600</span>,<span class="fl">165</span>))</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="fu">savefig</span>(plt, <span class="fu">joinpath</span>(www_path, <span class="st">"poc.png"</span>))</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(plt)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-display">
<div id="fig-final" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="intro_files/figure-html/fig-final-output-1.svg" class="img-fluid figure-img"></p>
<p></p><figcaption class="figure-caption">Figure 1.5: The different stages of the experiment.</figcaption><p></p>
</figure>
</div>
</div>
</div>
</section>
</main> <!-- /main -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const clipboard = new window.ClipboardJS('.code-copy-button', {
target: function(trigger) {
return trigger.previousElementSibling;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
function tippyHover(el, contentFn) {
const config = {
allowHTML: true,
content: contentFn,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start'
};
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
return note.innerHTML;
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
} else {
return undefined;
}
};
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement('div');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
}
});
</script>
<nav class="page-navigation">
<div class="nav-page nav-page-previous">
<a href="./index.html" class="pagination-link">
<i class="bi bi-arrow-left-short"></i> <span class="nav-page-text">Preface</span>
</a>
</div>
<div class="nav-page nav-page-next">
<a href="./sections/data_preprocessing/index.html" class="pagination-link">
<span class="nav-page-text"><span class="chapter-number">2</span> <span class="chapter-title">Data Preprocessing</span></span> <i class="bi bi-arrow-right-short"></i>
</a>
</div>
</nav>
</div> <!-- /content -->
</body></html>