{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "---\n",
    "execute:\n",
    "  enabled: false\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=environment-and-distribution-shift-md-1 fw=all -->\n",
    "\n",
    "# Environment and Distribution Shift\n",
    "\n",
    "In the previous sections, we worked through\n",
    "a number of hands-on applications of machine learning,\n",
    "fitting models to a variety of datasets.\n",
    "And yet, we never stopped to contemplate\n",
    "either where data came from in the first place\n",
    "or what we ultimately plan to do\n",
    "with the outputs from our models.\n",
    "Too often, machine learning developers\n",
    "in possession of data rush to develop models\n",
    "without pausing to consider these fundamental issues.\n",
    "\n",
    "Many failed machine learning deployments\n",
    "can be traced back to this failure.\n",
    "Sometimes models appear to perform marvelously\n",
    "as measured by test set accuracy\n",
    "but fail catastrophically in deployment\n",
    "when the distribution of data suddenly shifts.\n",
    "More insidiously, sometimes the very deployment of a model\n",
    "can be the catalyst that perturbs the data distribution.\n",
    "Say, for example, that we trained a model\n",
    "to predict who will repay rather than default on a loan,\n",
    "finding that an applicant's choice of footwear\n",
    "was associated with the risk of default\n",
    "(Oxfords indicate repayment, sneakers indicate default).\n",
    "We might be inclined \n",
    "thereafter to grant a loan\n",
    "to any applicant wearing Oxfords\n",
    "and to deny all applicants wearing sneakers.\n",
    "\n",
    "In this case, our ill-considered leap from\n",
    "pattern recognition to decision-making\n",
    "and our failure to critically consider the environment\n",
    "might have disastrous consequences.\n",
    "For starters, as soon as we began\n",
    "making decisions based on footwear,\n",
    "customers would catch on and change their behavior.\n",
    "Before long, all applicants would be wearing Oxfords,\n",
    "without any coincident improvement in credit-worthiness.\n",
    "Take a minute to digest this because similar issues abound\n",
    "in many applications of machine learning:\n",
    "by introducing our model-based decisions to the environment,\n",
    "we might break the model. This is a machine-learning incarnation of *Goodhart's law*:\n",
    "when a measure becomes a target, it ceases to be a good measure.\n",
    "\n",
    "While we cannot possibly give these topics\n",
    "a complete treatment in one section,\n",
    "we aim here to expose some common concerns,\n",
    "and to stimulate the critical thinking\n",
    "required to detect such situations early,\n",
    "mitigate damage, and use machine learning responsibly.\n",
    "Some of the solutions are simple\n",
    "(ask for the \"right\" data),\n",
    "some are technically difficult\n",
    "(implement a reinforcement learning system),\n",
    "and others require that we step outside\n",
    "statistical prediction altogether and\n",
    "grapple with difficult philosophical questions\n",
    "concerning the ethical application of algorithms.\n",
    "\n",
    "## Types of Distribution Shift\n",
    "\n",
    "To begin, we stick with the passive prediction setting\n",
    "considering the various ways that data distributions might shift\n",
    "and what might be done to salvage model performance.\n",
    "In one classic setup, we assume that our training data\n",
    "was sampled from some distribution $p_S(\\mathbf{x},y)$\n",
    "but that our test data will consist\n",
    "of unlabeled examples drawn from\n",
    "some different distribution $p_T(\\mathbf{x},y)$.\n",
    "Already, we must confront a sobering reality.\n",
    "Absent any assumptions on how $p_S$\n",
    "and $p_T$ relate to each other,\n",
    "learning a classifier that works at test time is impossible.\n",
    "\n",
    "Consider a binary classification problem,\n",
    "where we wish to distinguish between dogs and cats.\n",
    "If the distribution can shift in arbitrary ways,\n",
    "then our setup permits the pathological case\n",
    "in which the distribution over inputs remains\n",
    "constant: $p_S(\\mathbf{x}) = p_T(\\mathbf{x})$,\n",
    "but the labels are all flipped:\n",
    "$p_S(y \\mid \\mathbf{x}) = 1 - p_T(y \\mid \\mathbf{x})$.\n",
    "In other words, if God can suddenly decide\n",
    "that in the future all \"cats\" are now dogs\n",
    "and what we previously called \"dogs\" are now cats, without\n",
    "any change in the distribution of inputs $p(\\mathbf{x})$,\n",
    "then we cannot possibly distinguish this setting\n",
    "from one in which the distribution did not change at all.\n",
    "\n",
    "Fortunately, under some restricted assumptions\n",
    "on the ways our data might change in the future,\n",
    "principled algorithms can detect shift\n",
    "and sometimes even adapt on the fly,\n",
    "improving on the accuracy of the original classifier.\n",
    "\n",
    "### Covariate Shift\n",
    "\n",
    "Among categories of distribution shift,\n",
    "covariate shift may be the most widely studied.\n",
    "Here, we assume that while the distribution of inputs\n",
    "may change over time, the labeling function,\n",
    "i.e., the conditional distribution\n",
    "$P(y \\mid \\mathbf{x})$ does not change.\n",
    "Statisticians call this *covariate shift*\n",
    "because the problem arises due to a\n",
    "shift in the distribution of the covariates (features).\n",
    "While we can sometimes reason about distribution shift\n",
    "without invoking causality, we note that covariate shift\n",
    "is the natural assumption to invoke in settings\n",
    "where we believe that $\\mathbf{x}$ causes $y$.\n",
    "\n",
    "Consider the challenge of distinguishing cats and dogs.\n",
    "Our training data might consist of images of the kind in the figure.\n",
    "\n",
    "![Training data for distinguishing cats and dogs (illustrations: Lafeez Hossain / 500px / Getty Images; ilkermetinkursova / iStock / Getty Images Plus; GlobalP / iStock / Getty Images Plus; Musthafa Aboobakuru / 500px / Getty Images).](../img/cat-dog-train.png)\n",
    "\n",
    "\n",
    "At test time we are asked to classify the images in the figure.\n",
    "\n",
    "![Test data for distinguishing cats and dogs (illustrations: SIBAS_minich / iStock / Getty Images Plus; Ghrzuzudu / iStock / Getty Images Plus; id-work / DigitalVision Vectors / Getty Images; Yime / iStock / Getty Images Plus).](../img/cat-dog-test.png)\n",
    "\n",
    "The training set consists of photos,\n",
    "while the test set contains only cartoons.\n",
    "Training on a dataset with substantially different\n",
    "characteristics from the test set\n",
    "can spell trouble absent a coherent plan\n",
    "for how to adapt to the new domain.\n",
    "\n",
    "### Label Shift\n",
    "\n",
    "*Label shift* describes the converse problem.\n",
    "Here, we assume that the label marginal $P(y)$\n",
    "can change\n",
    "but the class-conditional distribution\n",
    "$P(\\mathbf{x} \\mid y)$ remains fixed across domains.\n",
    "Label shift is a reasonable assumption to make\n",
    "when we believe that $y$ causes $\\mathbf{x}$.\n",
    "For example, we may want to predict diagnoses\n",
    "given their symptoms (or other manifestations),\n",
    "even as the relative prevalence of diagnoses\n",
    "is changing over time.\n",
    "Label shift is the appropriate assumption here\n",
    "because diseases cause symptoms.\n",
    "In some degenerate cases the label shift\n",
    "and covariate shift assumptions can hold simultaneously.\n",
    "For example, when the label is deterministic,\n",
    "the covariate shift assumption will be satisfied,\n",
    "even when $y$ causes $\\mathbf{x}$.\n",
    "Interestingly, in these cases,\n",
    "it is often advantageous to work with methods\n",
    "that flow from the label shift assumption.\n",
    "That is because these methods tend\n",
    "to involve manipulating objects that look like labels (often low-dimensional),\n",
    "as opposed to objects that look like inputs,\n",
    "which tend to be high-dimensional in deep learning.\n",
    "\n",
    "### Concept Shift\n",
    "\n",
    "We may also encounter the related problem of *concept shift*,\n",
    "which arises when the very definitions of labels can change.\n",
    "This sounds weird (a *cat* is a *cat*, no?).\n",
    "However, other categories are subject to changes in usage over time.\n",
    "Diagnostic criteria for mental illness,\n",
    "what passes for fashionable, and job titles,\n",
    "are all subject to considerable\n",
    "amounts of concept shift.\n",
    "It turns out that if we navigate around the United States,\n",
    "shifting the source of our data by geography,\n",
    "we will find considerable concept shift regarding\n",
    "the distribution of names for *soft drinks*\n",
    "as shown in the figure.\n",
    "\n",
    "![Concept shift for soft drink names in the United States (CC-BY: Alan McConchie, PopVsSoda.com).](../img/popvssoda.png)\n",
    "\n",
    "If we were to build a machine translation system,\n",
    "the distribution $P(y \\mid \\mathbf{x})$ might be different\n",
    "depending on our location.\n",
    "This problem can be tricky to spot.\n",
    "We might hope to exploit knowledge\n",
    "that shift only takes place gradually\n",
    "either in a temporal or geographic sense.\n",
    "\n",
    "## Examples of Distribution Shift\n",
    "\n",
    "Before turning to formalism and algorithms,\n",
    "we can discuss some concrete situations\n",
    "where covariate or concept shift might not be obvious.\n",
    "\n",
    "\n",
    "### Medical Diagnostics\n",
    "\n",
    "Imagine that you want to design an algorithm to detect cancer.\n",
    "You collect data from healthy and sick people\n",
    "and you train your algorithm.\n",
    "It works fine, giving you high accuracy\n",
    "and you conclude that you are ready\n",
    "for a successful career in medical diagnostics.\n",
    "*Not so fast.*\n",
    "\n",
    "The distributions that gave rise to the training data\n",
    "and those you will encounter in the wild might differ considerably.\n",
    "This happened to an unfortunate startup\n",
    "that some of us authors worked with years ago.\n",
    "They were developing a blood test for a disease\n",
    "that predominantly affects older men\n",
    "and hoped to study it using blood samples\n",
    "that they had collected from patients.\n",
    "However, it is considerably more difficult\n",
    "to obtain blood samples from healthy men\n",
    "than from sick patients already in the system.\n",
    "To compensate, the startup solicited\n",
    "blood donations from students on a university campus\n",
    "to serve as healthy controls in developing their test.\n",
    "Then they asked whether we could help them\n",
    "to build a classifier for detecting the disease.\n",
    "\n",
    "As we explained to them,\n",
    "it would indeed be easy to distinguish\n",
    "between the healthy and sick cohorts\n",
    "with near-perfect accuracy.\n",
    "However, that is because the test subjects\n",
    "differed in age, hormone levels,\n",
    "physical activity, diet, alcohol consumption,\n",
    "and many more factors unrelated to the disease.\n",
    "This was unlikely to be the case with real patients.\n",
    "Due to their sampling procedure,\n",
    "we could expect to encounter extreme covariate shift.\n",
    "Moreover, this case was unlikely to be\n",
    "correctable via conventional methods.\n",
    "In short, they wasted a significant sum of money.\n",
    "\n",
    "\n",
    "### Self-Driving Cars\n",
    "\n",
    "Say a company wanted to use machine learning\n",
    "for developing self-driving cars.\n",
    "One key component here is a roadside detector.\n",
    "Since real annotated data is expensive to get,\n",
    "they had the (smart and questionable) idea\n",
    "to use synthetic data from a game rendering engine\n",
    "as additional training data.\n",
    "This worked really well on \"test data\"\n",
    "drawn from the rendering engine.\n",
    "Alas, inside a real car it was a disaster.\n",
    "As it turned out, the roadside had been rendered\n",
    "with a very simplistic texture.\n",
    "More importantly, *all* the roadside had been rendered\n",
    "with the *same* texture and the roadside detector\n",
    "learned about this \"feature\" very quickly.\n",
    "\n",
    "A famous (and possibly apocryphal) cautionary tale makes the same point.\n",
    "As the story goes, the US Army once tried to train a neural network\n",
    "to detect tanks hidden among trees.\n",
    "They photographed a forest with no tanks,\n",
    "then drove tanks in and photographed it again,\n",
    "and the classifier appeared to work *perfectly* on held-out images,\n",
    "until it failed in the field.\n",
    "It had supposedly learned not to find tanks\n",
    "but to tell the tank-free photos from the rest:\n",
    "the two image sets differed in lighting and shadow\n",
    "(one set was taken in the early morning, the other at noon), not in their tanks.\n",
    "Whether or not it happened exactly this way, the lesson is exact.\n",
    "A spurious feature correlated with the label in your sample,\n",
    "but absent in deployment,\n",
    "is enough to fool a model that never saw the distinction you actually care about.\n",
    "\n",
    "### Nonstationary Distributions\n",
    "\n",
    "A much more subtle situation arises\n",
    "when the distribution changes slowly\n",
    "(also known as *nonstationary distribution*)\n",
    "and the model is not updated adequately.\n",
    "Below are some typical cases.\n",
    "\n",
    "* We train a computational advertising model and then fail to update it frequently (e.g., we forget to incorporate that an obscure new device called an iPad was just launched).\n",
    "* We build a spam filter. It works well at detecting all spam that we have seen so far. But then the spammers wise up and craft new messages that look unlike anything we have seen before.\n",
    "* We build a product recommendation system. It works throughout the winter but then continues to recommend Santa hats long after Christmas.\n",
    "\n",
    "### Further Failure Modes\n",
    "\n",
    "* We build a face detector. It works well on all benchmarks. Unfortunately it fails on test data: the offending examples are close-ups where the face fills the entire image (no such data was in the training set).\n",
    "* We build a web search engine for the US market and want to deploy it in the UK.\n",
    "* We train an image classifier by compiling a large dataset where each among a large set of classes is equally represented in the dataset, say 1000 categories, represented by 1000 images each. Then we deploy the system in the real world, where the actual label distribution of photographs is decidedly non-uniform.\n",
    "\n",
    "\n",
    "## Correction of Distribution Shift\n",
    "\n",
    "As we have discussed, there are many cases\n",
    "where training and test distributions\n",
    "$P(\\mathbf{x}, y)$ are different.\n",
    "In some cases, we get lucky and the models work\n",
    "despite covariate, label, or concept shift.\n",
    "In other cases, we can do better by employing\n",
    "principled strategies to cope with the shift.\n",
    "The remainder of this section grows considerably more technical.\n",
    "The impatient reader could continue on to the next section\n",
    "as this material is not prerequisite to subsequent concepts.\n",
    "\n",
    "Recall from that section the distinction\n",
    "between the *empirical risk* the equation (the average\n",
    "loss on the training data) and the *risk*\n",
    "the equation (the expected loss under the true data\n",
    "distribution $p(\\mathbf{x}, y)$). In practice we cannot evaluate the risk\n",
    "directly and so we turn to *empirical risk minimization*, hoping that\n",
    "minimizing the empirical risk on the training set will approximately\n",
    "minimize the risk.\n",
    "\n",
    "\n",
    "### Covariate Shift Correction\n",
    "\n",
    "Assume that we want to estimate\n",
    "some dependency $P(y \\mid \\mathbf{x})$\n",
    "for which we have labeled data $(\\mathbf{x}_i, y_i)$.\n",
    "Unfortunately, the observations $\\mathbf{x}_i$ are drawn\n",
    "from some *source distribution* $q(\\mathbf{x})$\n",
    "rather than the *target distribution* $p(\\mathbf{x})$.\n",
    "Fortunately,\n",
    "the dependency assumption means\n",
    "that the conditional distribution does not change: $p(y \\mid \\mathbf{x}) = q(y \\mid \\mathbf{x})$.\n",
    "If the source distribution $q(\\mathbf{x})$ is \"wrong\",\n",
    "we can correct for that by reweighting the risk with the following simple\n",
    "identity [@Shimodaira.2000]:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\int\\int l(f(\\mathbf{x}), y) p(y \\mid \\mathbf{x})p(\\mathbf{x}) \\;d\\mathbf{x}dy =\n",
    "\\int\\int l(f(\\mathbf{x}), y) q(y \\mid \\mathbf{x})q(\\mathbf{x})\\frac{p(\\mathbf{x})}{q(\\mathbf{x})} \\;d\\mathbf{x}dy.\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "In other words, we need to reweigh each data example\n",
    "by the ratio of the\n",
    "probability\n",
    "that it would have been drawn from the correct distribution to that from the wrong one:\n",
    "\n",
    "$$\\beta_i \\stackrel{\\textrm{def}}{=} \\frac{p(\\mathbf{x}_i)}{q(\\mathbf{x}_i)}.$$\n",
    "\n",
    "Plugging in the weight $\\beta_i$ for\n",
    "each data example $(\\mathbf{x}_i, y_i)$\n",
    "we can train our model using\n",
    "*weighted empirical risk minimization*:\n",
    "\n",
    "$$\\mathop{\\mathrm{minimize}}_f \\frac{1}{n} \\sum_{i=1}^n \\beta_i l(f(\\mathbf{x}_i), y_i).$$\n",
    "\n",
    "\n",
    "Alas, we do not know that ratio,\n",
    "so before we can do anything useful we need to estimate it.\n",
    "Many methods estimate this ratio directly, matching moments of the reweighted\n",
    "source to the target without ever estimating $p$ and $q$ separately\n",
    "[@Gretton.Borgwardt.Rasch.ea.2012].\n",
    "Note that for any such approach, we need samples\n",
    "drawn from both distributions: the \"true\" $p$, e.g.,\n",
    "by access to test data, and the one used\n",
    "for generating the training set $q$ (the latter is trivially available).\n",
    "Note however, that we only need features $\\mathbf{x} \\sim p(\\mathbf{x})$;\n",
    "we do not need to access labels $y \\sim p(y)$.\n",
    "\n",
    "In this case, there exists a very effective approach\n",
    "that will give almost as good results as the original: namely, logistic regression,\n",
    "which is a special case of softmax regression (see that section)\n",
    "for binary classification.\n",
    "This is all that is needed to compute estimated probability ratios.\n",
    "We learn a classifier to distinguish\n",
    "between data drawn from $p(\\mathbf{x})$\n",
    "and data drawn from $q(\\mathbf{x})$.\n",
    "If it is impossible to distinguish\n",
    "between the two distributions\n",
    "then it means that the associated instances\n",
    "are equally likely to come from\n",
    "either one of those two distributions.\n",
    "On the other hand, any instances\n",
    "that can be well discriminated\n",
    "should be significantly overweighted\n",
    "or underweighted accordingly.\n",
    "\n",
    "For simplicity's sake assume that we have\n",
    "an equal number of instances from both distributions\n",
    "$p(\\mathbf{x})$\n",
    "and $q(\\mathbf{x})$, respectively.\n",
    "Now denote by $z$ labels that are $1$\n",
    "for data drawn from $p$ and $-1$ for data drawn from $q$.\n",
    "Then the probability in a mixed dataset is given by\n",
    "\n",
    "$$P(z=1 \\mid \\mathbf{x}) = \\frac{p(\\mathbf{x})}{p(\\mathbf{x})+q(\\mathbf{x})} \\textrm{ and hence } \\frac{P(z=1 \\mid \\mathbf{x})}{P(z=-1 \\mid \\mathbf{x})} = \\frac{p(\\mathbf{x})}{q(\\mathbf{x})}.$$\n",
    "\n",
    "Thus, if we use a logistic regression approach,\n",
    "where $P(z=1 \\mid \\mathbf{x})=\\frac{1}{1+\\exp(-h(\\mathbf{x}))}$ ($h$ is a parametrized function),\n",
    "it follows that\n",
    "\n",
    "$$\n",
    "\\beta_i = \\frac{1/(1 + \\exp(-h(\\mathbf{x}_i)))}{\\exp(-h(\\mathbf{x}_i))/(1 + \\exp(-h(\\mathbf{x}_i)))} = \\exp(h(\\mathbf{x}_i)).\n",
    "$$\n",
    "\n",
    "(With unequal sample sizes $\\exp(h)$ estimates $p/q$ only up to the constant\n",
    "$m/n$, which does not affect the weighted minimizer.)\n",
    "\n",
    "As a result, we need to solve two problems:\n",
    "the first, to distinguish between\n",
    "data drawn from both distributions,\n",
    "and then a weighted empirical risk minimization problem\n",
    "in the equation\n",
    "where we weigh terms by $\\beta_i$.\n",
    "\n",
    "Now we are ready to describe a correction algorithm.\n",
    "Suppose that we have a training set $\\{(\\mathbf{x}_1, y_1), \\ldots, (\\mathbf{x}_n, y_n)\\}$ and an unlabeled test set $\\{\\mathbf{u}_1, \\ldots, \\mathbf{u}_m\\}$.\n",
    "For covariate shift,\n",
    "we assume that $\\mathbf{x}_i$ for all $1 \\leq i \\leq n$ are drawn from some source distribution\n",
    "and $\\mathbf{u}_i$ for all $1 \\leq i \\leq m$\n",
    "are drawn from the target distribution.\n",
    "Here is a prototypical algorithm\n",
    "for correcting covariate shift:\n",
    "\n",
    "1. Create a binary-classification training set: $\\{(\\mathbf{x}_1, -1), \\ldots, (\\mathbf{x}_n, -1), (\\mathbf{u}_1, 1), \\ldots, (\\mathbf{u}_m, 1)\\}$.\n",
    "1. Train a binary classifier using logistic regression to get the function $h$.\n",
    "1. Weigh training data using $\\beta_i = \\exp(h(\\mathbf{x}_i))$ or better $\\beta_i = \\min(\\exp(h(\\mathbf{x}_i)), c)$ for some constant $c$.\n",
    "1. Use weights $\\beta_i$ for training on $\\{(\\mathbf{x}_1, y_1), \\ldots, (\\mathbf{x}_n, y_n)\\}$ in the equation.\n",
    "\n",
    "Clipping the weights at a ceiling $c$ trades a little bias for much lower variance:\n",
    "when source and target barely overlap, a handful of examples acquire enormous weights\n",
    "$\\beta_i$ that would otherwise dominate, and destabilize, the weighted objective.\n",
    "the figure shows the geometry of the whole construction:\n",
    "where the target density $p$ exceeds the source density $q$,\n",
    "the ratio $\\beta = p/q$ grows, and it grows *exponentially* fast\n",
    "out in the tail where the source has almost no mass,\n",
    "which is exactly where the clip takes over.\n",
    "\n",
    "![Importance weights for covariate shift. Training data comes from the source density $q$ (left curve) but the risk we care about weights points by the target density $p$ (right curve). The correction weight $\\beta(x) = p(x)/q(x)$ is near zero where only the source has mass, crosses $1$ where the densities agree, and explodes where the target outweighs a vanishing source; clipping $\\beta$ at a ceiling $c$ (dashed) caps the variance contributed by those rare, enormously weighted examples.](../img/mdl-clf-density-ratio.svg)\n",
    "\n",
    "Note that the above algorithm relies on one assumption.\n",
    "For this scheme to work, we need that each data example\n",
    "in the target (e.g., test time) distribution\n",
    "had nonzero probability of occurring at training time.\n",
    "If we find a point where $p(\\mathbf{x}) > 0$ but $q(\\mathbf{x}) = 0$,\n",
    "then the corresponding importance weight should be infinity.\n",
    "\n",
    "#### Covariate Shift Correction in Code\n",
    "\n",
    "The entire pipeline, from discriminator to reweighted training, fits in a\n",
    "few lines, so let us watch it work. We make the shift two-dimensional so that\n",
    "it is drastic but visible: source inputs are Gaussian around the origin,\n",
    "target inputs are the same Gaussian shifted to be centered at $(2, 0)$, and both share\n",
    "one labeling rule (covariate shift by construction). The label depends on\n",
    "$\\mathbf{x}$ through a *curved* boundary, so a linear classifier is\n",
    "misspecified and it matters *where* it spends its capacity. The only trainer\n",
    "we need is logistic regression by gradient descent, with an optional\n",
    "per-example weight:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "environment-and-distribution-shift-covariate-shift-correction-1"
   },
   "source": [
    "import numpy as np\n",
    "\n",
    "rng = np.random.default_rng(0)\n",
    "n = 1000\n",
    "X_src = rng.normal(0.0, 1.0, (n, 2))            # source q: centered at (0, 0)\n",
    "X_tgt = rng.normal(0.0, 1.0, (n, 2)) + [2, 0]   # target p: centered at (2, 0)\n",
    "label = lambda X: (X[:, 1] > 0.5 * X[:, 0]**2 - 1).astype(float)\n",
    "y_src, y_tgt = label(X_src), label(X_tgt)\n",
    "\n",
    "def fit_logreg(X, y, weights=None, lr=0.1, steps=2000):\n",
    "    w, b = np.zeros(X.shape[1]), 0.0\n",
    "    v = np.ones(len(y)) if weights is None else weights / weights.mean()\n",
    "    for _ in range(steps):\n",
    "        g = v * (1 / (1 + np.exp(-(X @ w + b))) - y)   # weighted residual\n",
    "        w -= lr * X.T @ g / len(y)\n",
    "        b -= lr * g.mean()\n",
    "    return w, b"
   ],
   "execution_count": 1,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=environment-and-distribution-shift-md-2 fw=all -->\n",
    "\n",
    "Step one of the algorithm: pool the source inputs (labeled $z=0$) with the\n",
    "*unlabeled* target inputs ($z=1$) and train the domain discriminator $h$. For\n",
    "two unit Gaussians the true log-density-ratio is exactly linear,\n",
    "$\\log (p(\\mathbf{x})/q(\\mathbf{x})) = 2x_1 - 2$, so we can check the learned $h$\n",
    "against the truth, and the weights are $\\beta_i = \\exp(h(\\mathbf{x}_i))$:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "environment-and-distribution-shift-covariate-shift-correction-2"
   },
   "source": [
    "w_h, b_h = fit_logreg(np.concatenate([X_src, X_tgt]),\n",
    "                      np.concatenate([np.zeros(n), np.ones(n)]))\n",
    "beta = np.exp(X_src @ w_h + b_h)\n",
    "print(f'learned h(x) = {w_h[0]:.2f} x1 {w_h[1]:+.2f} x2 {b_h:+.2f} '\n",
    "      f'(true log-ratio: 2 x1 - 2)')\n",
    "print(f'beta on source data: mean {beta.mean():.2f}, max {beta.max():.1f}')"
   ],
   "execution_count": 2,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "learned h(x) = 2.06 x1 +0.09 x2 -2.03 (true log-ratio: 2 x1 - 2)\nbeta on source data: mean 0.86, max 56.2\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=environment-and-distribution-shift-md-3 fw=all -->\n",
    "\n",
    "Step two: train the actual classifier three ways, on the same source data\n",
    "with the same labels, and evaluate each on the *target* domain, which is the\n",
    "one we care about:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "environment-and-distribution-shift-covariate-shift-correction-3"
   },
   "source": [
    "acc = lambda wb, X, y: ((X @ wb[0] + wb[1] > 0) == (y > 0.5)).mean()\n",
    "for name, wts in [('unweighted', None), ('weighted', beta),\n",
    "                  ('clipped, c=5', np.minimum(beta, 5))]:\n",
    "    wb = fit_logreg(X_src, y_src, wts)\n",
    "    print(f'{name:12s}  target accuracy: {acc(wb, X_tgt, y_tgt):.3f}'\n",
    "          f'   (source accuracy: {acc(wb, X_src, y_src):.3f})')"
   ],
   "execution_count": 3,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "unweighted    target accuracy: 0.502   (source accuracy: 0.860)\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "weighted      target accuracy: 0.933   (source accuracy: 0.795)\nclipped, c=5  target accuracy: 0.945   (source accuracy: 0.817)\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=environment-and-distribution-shift-md-4 fw=all -->\n",
    "\n",
    "The unweighted model is fitted where the *source* data lives, so on the\n",
    "target domain it is no better than a coin flip; reweighting by $\\beta$ lifts\n",
    "target accuracy above 90%, at the price of a worse fit on the now-discounted\n",
    "source region, exactly the trade the identity\n",
    "the equation prescribes. The clipped run bears out the\n",
    "earlier warning: the largest raw weight here is over 50, so a handful of the\n",
    "thousand source points would otherwise dominate the objective, and capping\n",
    "$\\beta$ at $c=5$ here even helps a little.\n",
    "Exercises 3 and 4 let you probe when this pipeline fails, most instructively\n",
    "when the supports stop overlapping.\n",
    "\n",
    "\n",
    "### Label Shift Correction\n",
    "\n",
    "Assume that we are dealing with a\n",
    "classification task with $k$ categories.\n",
    "Using the same notation in that section,\n",
    "$q$ and $p$ are the source distribution (e.g., training time) and target distribution (e.g., test time), respectively.\n",
    "Assume that the distribution of labels shifts over time:\n",
    "$q(y) \\neq p(y)$, but the class-conditional distribution\n",
    "stays the same: $q(\\mathbf{x} \\mid y)=p(\\mathbf{x} \\mid y)$.\n",
    "If the source distribution $q(y)$ is \"wrong\",\n",
    "we can correct for that\n",
    "according to\n",
    "the following identity in the risk\n",
    "as defined in\n",
    "the equation:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\int\\int l(f(\\mathbf{x}), y) p(\\mathbf{x} \\mid y)p(y) \\;d\\mathbf{x}dy =\n",
    "\\int\\int l(f(\\mathbf{x}), y) q(\\mathbf{x} \\mid y)q(y)\\frac{p(y)}{q(y)} \\;d\\mathbf{x}dy.\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "\n",
    "Here, our importance weights will correspond to the\n",
    "label likelihood ratios:\n",
    "\n",
    "$$\\beta_i \\stackrel{\\textrm{def}}{=} \\frac{p(y_i)}{q(y_i)}.$$\n",
    "\n",
    "One nice thing about label shift is that\n",
    "if we have a reasonably good model\n",
    "on the source distribution,\n",
    "then we can get consistent estimates of these weights\n",
    "without ever having to deal with the ambient dimension.\n",
    "In deep learning, the inputs tend\n",
    "to be high-dimensional objects like images,\n",
    "while the labels are often simpler objects like categories.\n",
    "\n",
    "To estimate the target label distribution,\n",
    "we first take our reasonably good off-the-shelf classifier\n",
    "(typically trained on the training data)\n",
    "and compute its confusion matrix $\\mathbf{C}$ on the validation set\n",
    "(also from the training distribution).\n",
    "Recall the $k \\times k$ confusion matrix of that section,\n",
    "column-normalized exactly as we computed it in that section:\n",
    "entry $c_{ij}$ is the fraction of validation examples of true class $j$\n",
    "that the model predicted as class $i$, so each column sums to $1$\n",
    "and estimates $P(\\hat{y}=i \\mid y=j)$.\n",
    "\n",
    "Now, we cannot calculate the confusion matrix\n",
    "on the target data directly\n",
    "because we do not get to see the labels for the examples\n",
    "that we see in the wild,\n",
    "unless we invest in a complex real-time annotation pipeline.\n",
    "What we can do, however, is average all of our model's predictions\n",
    "at test time together, yielding the mean model outputs $\\mu(\\hat{\\mathbf{y}}) \\in \\mathbb{R}^k$,\n",
    "where the $i^\\textrm{th}$ element $\\mu(\\hat{y}_i)$\n",
    "is the fraction of the total predictions on the test set\n",
    "where our model predicted $i$.\n",
    "\n",
    "It turns out that under some mild conditions, namely that\n",
    "our classifier was reasonably accurate in the first place,\n",
    "that the target data contains only categories\n",
    "that we have seen before,\n",
    "and that the label shift assumption holds in the first place\n",
    "(the strongest assumption here), we can estimate the test set label distribution\n",
    "by solving a simple linear system\n",
    "\n",
    "$$\\mathbf{C} p(\\mathbf{y}) = \\mu(\\hat{\\mathbf{y}}),$$\n",
    "\n",
    "because as an estimate $\\sum_{j=1}^k c_{ij} p(y_j) = \\mu(\\hat{y}_i)$ holds for all $1 \\leq i \\leq k$,\n",
    "where $p(y_j)$ is the $j^\\textrm{th}$ element of the $k$-dimensional label distribution vector $p(\\mathbf{y})$.\n",
    "If our classifier is accurate enough that $\\mathbf{C}$\n",
    "is diagonally dominant (each class is predicted correctly\n",
    "more often than it is mistaken for any collection of others),\n",
    "then $\\mathbf{C}$ will be invertible,\n",
    "and we get a solution $p(\\mathbf{y}) = \\mathbf{C}^{-1} \\mu(\\hat{\\mathbf{y}})$.\n",
    "This confusion-matrix estimator goes back to @Saerens.Latinne.Decaestecker.2002;\n",
    "@Lipton.Wang.Smola.2018 showed that, treating the trained classifier as a\n",
    "black box, it yields *consistent* estimates of the target label distribution under\n",
    "the label-shift assumption (an approach they call black-box shift estimation).\n",
    "\n",
    "Because we observe the labels on the source data,\n",
    "it is easy to estimate the distribution $q(y)$.\n",
    "Then, for any training example $i$ with label $y_i$,\n",
    "we can take the ratio of our estimated $p(y_i)/q(y_i)$\n",
    "to calculate the weight $\\beta_i$,\n",
    "and plug this into weighted empirical risk minimization\n",
    "in the equation.\n",
    "\n",
    "\n",
    "### Concept Shift Correction\n",
    "\n",
    "Concept shift is much harder to fix in a principled manner.\n",
    "For instance, in a situation where suddenly the problem changes\n",
    "from distinguishing cats from dogs to one of\n",
    "distinguishing white from black animals,\n",
    "it will be unreasonable to assume\n",
    "that we can do much better than just collecting new labels\n",
    "and training from scratch.\n",
    "Fortunately, in practice, such extreme shifts are rare.\n",
    "Instead, what usually happens is that the task keeps on changing slowly.\n",
    "To make things more concrete, here are some examples:\n",
    "\n",
    "* In computational advertising, new products are launched,\n",
    "old products become less popular. This means that the distribution over ads and their popularity changes gradually and any click-through rate predictor needs to change gradually with it.\n",
    "* Traffic camera lenses degrade gradually due to environmental wear, affecting image quality progressively.\n",
    "* News content changes gradually (i.e., most of the news remains unchanged but new stories appear).\n",
    "\n",
    "In such cases, we can use the same approach that we used for training networks to make them adapt to the change in the data. In other words, we use the existing network weights and simply perform a few update steps with the new data rather than training from scratch.\n",
    "\n",
    "\n",
    "## A Taxonomy of Learning Problems\n",
    "\n",
    "Armed with knowledge about how to deal with changes in distributions, we can now consider some other aspects of machine learning problem formulation.\n",
    "\n",
    "\n",
    "### Batch Learning\n",
    "\n",
    "In *batch learning*, we have access to training features and labels $\\{(\\mathbf{x}_1, y_1), \\ldots, (\\mathbf{x}_n, y_n)\\}$, which we use to train a model $f(\\mathbf{x})$. Later on, we deploy this model to score new data $(\\mathbf{x}, y)$ drawn from the same distribution. This is the default assumption for any of the problems that we discuss here. For instance, we might train a cat detector based on lots of pictures of cats and dogs. Once we have trained it, we ship it as part of a smart catdoor computer vision system that lets only cats in. This is then installed in a customer's home and is never updated again (barring extreme circumstances).\n",
    "\n",
    "\n",
    "### Online Learning\n",
    "\n",
    "Now imagine that the data $(\\mathbf{x}_i, y_i)$ arrives one sample at a time. More specifically, assume that we first observe $\\mathbf{x}_i$, then we need to come up with an estimate $f(\\mathbf{x}_i)$. Only once we have done this do we observe $y_i$ and so receive a reward or incur a loss, given our decision.\n",
    "Many real problems fall into this category. For example, we need to predict tomorrow's stock price, which allows us to trade based on that estimate and at the end of the day we find out whether our estimate made us a profit. In other words, in *online learning*, we have the following cycle where we are continuously improving our model given new observations:\n",
    "\n",
    "$$\\begin{aligned}&\\textrm{model } f_t \\longrightarrow \\textrm{data }  \\mathbf{x}_t \\longrightarrow \\textrm{estimate } f_t(\\mathbf{x}_t) \\longrightarrow\\\\ \\textrm{obs}&\\textrm{ervation } y_t \\longrightarrow \\textrm{loss } l(y_t, f_t(\\mathbf{x}_t)) \\longrightarrow \\textrm{model } f_{t+1}\\end{aligned}$$\n",
    "\n",
    "### Bandits\n",
    "\n",
    "A *bandit* problem supplies only partial feedback: after choosing an action, the\n",
    "learner observes the reward for that action rather than labels or rewards for\n",
    "all alternatives. The classical multi-armed bandit has finitely many actions;\n",
    "contextual and continuous-action variants are also common. This feedback\n",
    "structure distinguishes bandits from ordinary supervised online learning.\n",
    "\n",
    "\n",
    "### Control\n",
    "\n",
    "In control problems, an action changes the system state and therefore affects\n",
    "later observations. A coffee-boiler controller, for example, sees a temperature\n",
    "that depends on its earlier heating decisions; a PID\n",
    "(proportional-integral-derivative) controller is one standard approach.\n",
    "Likewise, recommendations shown to a user can change what the user reads next.\n",
    "Sequential dynamics distinguish control from ordinary online prediction.\n",
    "\n",
    "\n",
    "### Reinforcement Learning\n",
    "\n",
    "*Reinforcement learning* studies sequential decisions in which actions affect\n",
    "future states and rewards may be delayed. It includes single-agent control as\n",
    "well as cooperative and competitive multiagent problems. Chess, Go, and\n",
    "StarCraft are multiagent examples; autonomous driving is a control problem in\n",
    "which other road users also respond to the vehicle's actions. Partial\n",
    "observability, delayed credit, and exploration are separate difficulties that\n",
    "may occur in these settings.\n",
    "\n",
    "### Considering the Environment\n",
    "\n",
    "One key distinction between the different situations above is that a strategy that might have worked throughout in the case of a stationary environment, might not work throughout in an environment that can adapt. For instance, an arbitrage opportunity discovered by a trader is likely to disappear once it is exploited. The speed and manner at which the environment changes determines to a large extent the type of algorithms that we can bring to bear. For instance, if we know that things may only change slowly, we can force any estimate to change only slowly, too. If we know that the environment might change instantaneously, but only very infrequently, we can make allowances for that. These types of knowledge are what let the aspiring data scientist deal with concept shift, i.e., when the problem that is being solved can change over time.\n",
    "\n",
    "\n",
    "## Fairness, Accountability, and Transparency in Machine Learning\n",
    "\n",
    "Deploying a machine learning system often turns predictions into decisions\n",
    "that affect people.\n",
    "These technical systems can impact the lives\n",
    "of individuals who are subject to the resulting decisions.\n",
    "The leap from considering predictions to making decisions\n",
    "raises new ethical questions alongside the technical ones,\n",
    "and these must be carefully considered.\n",
    "If we are deploying a medical diagnostic system,\n",
    "we need to know for which populations\n",
    "it may work and for which it may not.\n",
    "Overlooking foreseeable risks to the welfare of\n",
    "a subpopulation could cause us to administer inferior care.\n",
    "Moreover, once we contemplate decision-making systems,\n",
    "we must step back and reconsider how we evaluate our technology.\n",
    "Among other consequences of this change of scope,\n",
    "we will find that *accuracy* is seldom the right measure.\n",
    "For instance, when translating predictions into actions,\n",
    "we will often want to take into account\n",
    "the potential cost sensitivity of erring in various ways.\n",
    "The cost of an error can differ across decisions and populations. Thresholds\n",
    "should therefore be chosen from an explicit loss model and evaluated separately\n",
    "for affected groups. Threshold adjustment alone does not establish fairness:\n",
    "different fairness criteria can conflict, and the labels, data-collection\n",
    "process, and decision policy may themselves create harm. This section only\n",
    "identifies the problem; a later treatment develops the definitions and their\n",
    "limitations.\n",
    "We also want to be careful about\n",
    "how prediction systems can lead to feedback loops.\n",
    "For example, consider predictive policing systems,\n",
    "which allocate patrol officers\n",
    "to areas with high forecasted crime.\n",
    "It is easy to see how a worrying pattern can emerge:\n",
    "\n",
    " 1. Neighborhoods with more crime get more patrols.\n",
    " 1. Consequently, more crimes are discovered in these neighborhoods, entering the training data available for future iterations.\n",
    " 1. Exposed to more positives, the model predicts yet more crime in these neighborhoods.\n",
    " 1. In the next iteration, the updated model targets the same neighborhood even more heavily leading to yet more crimes discovered, etc.\n",
    "\n",
    "Often, the various mechanisms by which\n",
    "a model's predictions become coupled to its training data\n",
    "are unaccounted for in the modeling process.\n",
    "This can lead to what researchers call *runaway feedback loops*.\n",
    "Additionally, we want to be careful about\n",
    "whether we are addressing the right problem in the first place.\n",
    "Predictive algorithms now play an outsize role\n",
    "in mediating the dissemination of information.\n",
    "Should the news that an individual encounters\n",
    "be determined by the set of Facebook pages they have *Liked*?\n",
    "These are just a few among the many pressing ethical dilemmas\n",
    "that you might encounter in a career in machine learning.\n",
    "\n",
    "\n",
    "## Summary\n",
    "\n",
    "In many cases training and test sets do not come from the same distribution. This is called distribution shift.\n",
    "The risk is the expectation of the loss over the entire population of data drawn from their true distribution. However, this entire population is usually unavailable. Empirical risk is an average loss over the training data to approximate the risk. In practice, we perform empirical risk minimization.\n",
    "\n",
    "Under covariate- or label-shift assumptions, unlabeled target data can support\n",
    "specific reweighting corrections. A change in the input marginal may be\n",
    "detectable without labels, but the claim that $P(y\\mid\\mathbf{x})$ or\n",
    "$P(\\mathbf{x}\\mid y)$ stayed fixed is not generally identifiable from those\n",
    "data alone. Corrections therefore depend on an assumption that must be defended\n",
    "from domain knowledge and checked when target labels become available.\n",
    "In some cases, the environment may remember automated actions and respond in surprising ways. We must account for this possibility when building models and continue to monitor live systems, open to the possibility that our models and the environment will become entangled in unanticipated ways.\n",
    "\n",
    "These ideas predate the current era of large pretrained models, but\n",
    "distribution shift has only become more central since, as a foundation model is\n",
    "routinely deployed on domains, users, and time periods unlike its training\n",
    "corpus. Curated benchmarks such as WILDS [@Koh.Sagawa.Marklund.ea.2021]\n",
    "show that models with strong in-distribution accuracy can still degrade sharply\n",
    "out of distribution, and that a correction which helps on one shift often fails\n",
    "on another, so it pays to measure on the shift you actually face.\n",
    "\n",
    "## Exercises\n",
    "\n",
    "1. If you change the behavior of a search engine, how might users respond? How might advertisers respond? Explain why this is an instance of the feedback loop described for the loan/footwear example at the start of the section.\n",
    "1. Starting from the risk under the target distribution $p(\\mathbf{x}, y)$, derive the covariate-shift reweighting identity the equation (whose sample version is the weighted objective the equation), and state precisely the assumption on the supports of $p(\\mathbf{x})$ and $q(\\mathbf{x})$ under which the importance weights $\\beta_i=p(\\mathbf{x}_i)/q(\\mathbf{x}_i)$ are finite.\n",
    "1. Implement a covariate shift detector. Take any labeled dataset and create a shifted copy of the features (e.g., add Gaussian noise, or subsample by thresholding one feature). Train a logistic-regression classifier to distinguish \"original\" from \"shifted\" inputs and report its accuracy. Relate the accuracy to how detectable the shift is, and to the classifier-as-shift-detector idea in that section. *Hint: if the classifier cannot beat chance, the two distributions are indistinguishable from these features.*\n",
    "1. Implement a covariate shift corrector. Using the classifier from the previous exercise, compute weights $\\beta_i=\\exp(h(\\mathbf{x}_i))$, retrain your downstream model with weighted empirical risk minimization the equation, and compare its target-domain accuracy with and without reweighting. What happens to the variance of the $\\beta_i$ as the shift grows, and how does clipping $\\beta_i\\leftarrow\\min(\\beta_i,c)$ help?\n",
    "1. You have a $k$-class classifier and its validation confusion matrix $\\mathbf{C}$. Show that the linear system $\\mathbf{C}\\, p(\\mathbf{y})=\\mu(\\hat{\\mathbf{y}})$ follows from the law of total probability under the label-shift assumption, and explain why $\\mathbf{C}$ must be invertible for the estimate $p(\\mathbf{y})=\\mathbf{C}^{-1}\\mu(\\hat{\\mathbf{y}})$ to be usable.\n",
    "1. Besides distribution shift, what else could make the empirical risk a poor approximation of the risk? *Hint: think about dependence between examples, and about the loss not matching the deployment objective.*\n",
    "\n",
    "\n",
    "[Discussions](https://d2l.discourse.group/t/105)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "d2l-pytorch",
   "display_name": "d2l (PyTorch)",
   "language": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
