{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "tags": [
     "remove_input"
    ]
   },
   "outputs": [],
   "source": [
    "path_data = '../../data/'\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "plt.style.use('fivethirtyeight')\n",
    "\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Assessing Models\n",
    "In data science, a \"model\" is a set of assumptions about data. Often, models include assumptions about chance processes used to generate data. \n",
    "\n",
    "Sometimes, data scientists have to decide whether or not their models are good. In this section we will discuss two examples of making such decisions. In later sections we will use the methods developed here as the building blocks of a general framework for testing hypotheses."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## U.S. Supreme Court, 1965: Swain vs. Alabama\n",
    "\n",
    "In the early 1960's, in Talladega County in Alabama, a black man called Robert Swain was convicted of raping a white woman and was sentenced to death. He appealed his sentence, citing among other factors the all-white jury. At the time, only men aged 21 or older were allowed to serve on juries in Talladega County. In the county, 26% of the eligible jurors were black, but there were only 8 black men among the 100 selected for the jury panel in Swain's trial. No black man was selected for the trial jury.\n",
    "\n",
    "In 1965, the Supreme Court of the United States denied Swain's appeal. In its ruling, the Court wrote \"... the overall percentage disparity has been small and reflects no studied attempt to include or exclude a specified number of Negroes.\"\n",
    "\n",
    "Jury panels are supposed to be selected at random from the eligible population. Because 26% of the eligible population was black, 8 black men on a panel of 100 might seem low.\n",
    "\n",
    "### A Model\n",
    "But one view of the data – a model, in other words – is that the panel was selected at random and ended up with a small number of black men just due to chance. This model is consistent with what the Supreme Court wrote in its ruling.\n",
    "\n",
    "The model specifies the details of a chance process. It says the data are like a random sample from a population in which 26% of the people are black. We are in a good position to assess this model, because:\n",
    "- We can simulate data based on the model. That is, we can simulate drawing at random from a population of whom 26% are black. \n",
    "- Our simulation will show what a panel *would* look like *if* it were selected at random.\n",
    "- We can then compare the results of the simulation with the composition of Robert Swain's panel. \n",
    "- If the results of our simulation are not consistent with the composition of Swain's panel, that will be evidence against the model of random selection.\n",
    "\n",
    "Let's go through the process in detail. \n",
    "\n",
    "### The Statistic\n",
    "First, we have to choose a statistic to simulate. The statistic has to be able to help us decide between the model and alternative views about the data. The model says the panel was drawn at random. The alternative viewpoint, suggested by Robert Swain's appeal, is that the panel was not drawn at random because it contained too few black men. A natural statistic, then, is the number of black men in our simulated sample of 100 men representing the panel. Small values of the statistic will favor the alternative viewpoint.\n",
    "\n",
    "### Predicting the Statistic Under the Model\n",
    "If the model were true, how big would the statistic typically be? To answer that, we have to start by working out the details of the simulation. \n",
    "\n",
    "#### Generating One Value of the Statistic\n",
    "First let's figure out how to simulate one value of the statistic. For this, we have to sample 100 times at random from the population of eligible jurors and count the number of black men we get.\n",
    "\n",
    "One way is to set up a table representing the eligible population and use `sample` as we did in the previous chapter. But there is also a quicker way, we can build a function tailored for sampling at random from categorical distributions. We will use this function `sample_proportions` several times in this chapter.\n",
    "\n",
    "The `sample_proportions` function will take two arguments:\n",
    "- the sample size\n",
    "- the distribution of the categories in the population, as a list or array of proportions that add up to 1\n",
    "\n",
    "As the function uses a numpy 'method' an array will be returned containing the distribution of the categories in a random sample of the given size taken from the population. This is an array consisting of the **sample proportions** in all the different categories.\n",
    "\n",
    "To see how to use this, remember that according to our model, the panel is selected at random from a population of men among whom 26% were black and 74% were not. Thus the distribution of the two categories can be represented as the list `[0.26, 0.74]`, which we have assigned to the name `eligible_population`. Now let's sample at random 100 times from this distribution, and see what proportions of the two categories we get in our sample."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sample_proportions(sample_size, probabilities):\n",
    "    \"\"\"Return the proportion of random draws for each outcome in a distribution.\n",
    "    This function is similar to np.random.multinomial, but returns proportions\n",
    "    instead of counts.\n",
    "    Args:\n",
    "        ``sample_size``: The size of the sample to draw from the distribution.\n",
    "        ``probabilities``: An array of probabilities that forms a distribution.\n",
    "    Returns:\n",
    "        An array with the same length as ``probability`` that sums to 1.\n",
    "    \"\"\"\n",
    "    return np.random.multinomial(sample_size, probabilities) / sample_size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.27, 0.73])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eligible_population = [0.26, 0.74]\n",
    "sample_proportions(100, eligible_population)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That was easy! The proportion of black men in the random sample is `item(0)` of the output array.\n",
    "\n",
    "Because there are 100 men in the sample, the number of men in each category is 100 times the proportion. So we can just as easily simulate counts instead of proportions, and access the count of black men only. \n",
    "\n",
    "Run the cell a few times to see how the output varies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "26.0"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# count of black men in a simulated panel\n",
    "\n",
    "(100 * sample_proportions(100, eligible_population)).item(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Running the Simulation ####\n",
    "To get a sense of the variability without running the cell over and over, let's generate 10,000 simulated values of the count. \n",
    "\n",
    "The code follows the same steps that we have used in every simulation. First, we define a function to simulate one value of the count, using the code we wrote above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "def one_simulated_count():\n",
    "    return (100 * sample_proportions(100, eligible_population)).item(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we create an array of 10,000 simulated counts by using a `for` loop."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "counts = np.array([])\n",
    "\n",
    "repetitions = 10000\n",
    "for i in np.arange(repetitions):\n",
    "    counts = np.append(counts, one_simulated_count())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The Prediction\n",
    "To interpret the results of our simulation, we start as usual by visualizing the results by an empirical histogram."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "# When creating a histogram in previous chapters we have been using almost the same code each time.\n",
    "# To make life a little easier we can (if we choose), define a function \n",
    "\n",
    "def hist_with_bins(df, bins, plot_title, x_axis_label, y_axis_label):\n",
    "    \"\"\"\n",
    "    df['col']: optional, name of df with column or name of df\n",
    "    bins: number of bins as np.array (range or list)\n",
    "    units: unit of measurement\n",
    "    \"\"\"\n",
    "    source = df\n",
    "\n",
    "    fig, ax1 = plt.subplots()\n",
    "\n",
    "    ax1.hist(source, bins=bins, density=True, alpha=0.8, ec='white')\n",
    "\n",
    "    y_vals = ax1.get_yticks()\n",
    "\n",
    "    y_label = y_axis_label\n",
    "\n",
    "    x_label = x_axis_label\n",
    "\n",
    "    ax1.set_yticklabels(['{:g}'.format(x * 100) for x in y_vals])\n",
    "\n",
    "    plt.ylabel(y_label)\n",
    "\n",
    "    plt.xlabel(x_label)\n",
    "\n",
    "    plt.title('%s' % plot_title)\n",
    "\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19664 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "random_sample_counts = pd.DataFrame({'Count in a Random Sample':counts})\n",
    "\n",
    "hist_with_bins(random_sample_counts, np.arange(5.5, 46.6, 1), \n",
    "               'Random Sampling', 'Count in Random Sample', 'Percent per Unit')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The histogram tells us what the model of random selection predicts about our statistic, the count of black men in the sample.\n",
    "\n",
    "To generate each simulated count, we drew at 100 times at random from a population in which 26% were black. So, as you would expect, most of the simulated counts are around 26. They are not exactly 26: there is some variation. The counts range from about 10 to about 45. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comparing the Prediction and the Data\n",
    "Though the simulated counts are quite varied, very few of them came out to be eight or less. The value eight is far out in the left hand tail of the histogram. It's the red dot on the horizontal axis of the histogram."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15328 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bins = np.arange(5.5, 46.6, 1)\n",
    "\n",
    "unit = ''\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "\n",
    "ax.hist(random_sample_counts, bins=bins, density=True, alpha=0.8, ec='white', zorder=5)\n",
    "\n",
    "ax.scatter(8,0,color='red', s=30, zorder=10).set_clip_on(False)\n",
    "\n",
    "y_vals = ax.get_yticks()\n",
    "\n",
    "y_label = 'Percent per ' + (unit if unit else 'unit')\n",
    "\n",
    "x_label = 'Count in Random Sample'\n",
    "\n",
    "ax.set_yticklabels(['{:g}'.format(x * 100) for x in y_vals])\n",
    "\n",
    "plt.ylabel(y_label)\n",
    "\n",
    "plt.xlabel(x_label)\n",
    "\n",
    "plt.title('');\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The simulation shows that if we select a panel of 100 jurors at random from the eligible population, we are very unlikely to get counts of black men as low as the eight that were in Swain's jury panel. This is evidence that the model of random selection of the jurors in the panel is not consistent with the data from the panel. \n",
    "\n",
    "When the data and a model are inconsistent, the model is hard to justify. After all, the data are real. The model is just a set of assumptions. When assumptions are at odds with reality, we have to question those assumptions.\n",
    "\n",
    "While it is *possible* that a panel like Robert Swain's could have been generated by chance, our simulation demonstrates that it is very unlikely. Thus our assessment is that the model of random draws is not supported by the evidence. Swain's jury panel does not look like the result of random sampling from the population of eligible jurors."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This method of assessing models is very general. Here is an example in which we use it to assess a model in a completely different setting."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Mendel's Pea Flowers\n",
    "[Gregor Mendel](https://en.wikipedia.org/wiki/Gregor_Mendel) (1822-1884) was an Austrian monk who is widely recognized as the founder of the modern field of genetics. Mendel performed careful and large-scale experiments on plants to come up with fundamental laws of genetics. \n",
    "\n",
    "Many of his experiments were on varieties of pea plants. He formulated sets of assumptions about each variety; these were his models. He then tested the validity of his models by growing the plants and gathering data.\n",
    "\n",
    "Let's analyze the data from one such experiment to see if Mendel's model was good.\n",
    "\n",
    "In a particular variety, each plant has either purple flowers or white. The color in each plant is unaffected by the colors in other plants. Mendel hypothesized that the plants should bear purple or white flowers at random, in the ratio 3:1. \n",
    "\n",
    "### Mendel's Model\n",
    "For every plant, there is a 75% chance that it will have purple flowers, and a 25% chance that the flowers will be white, regardless of the colors in all the other plants.\n",
    "\n",
    "#### Approach to Assessment\n",
    "To go about assessing Mendel's model, we can simulate plants under the assumptions of the model and see what it predicts. Then we will be able to compare the predictions with the data that Mendel recorded.\n",
    "\n",
    "### The Statistic\n",
    "Our goal is to see whether or not Mendel's model is good. We need to simulate a statistic that will help us make this decision. \n",
    "\n",
    "If the model is good, the percent of purple-flowering plants in the sample should be close to 75%. If the model is not good, the percent purple-flowering will be away from 75%. It may be higher, or lower; the direction doesn't matter.\n",
    "\n",
    "The key for us is the *distance* between 75% and the percent of purple-flowering plants in the sample. Big distances are evidence that the model isn't good.\n",
    "\n",
    "Our statistic, therefore, is the **distance between the sample percent and 75%**:\n",
    "\n",
    "$$\n",
    "\\big{\\vert} \\text{sample percent of purple-flowering plants} - 75 \\big{\\vert}\n",
    "$$\n",
    "\n",
    "### Predicting the Statistic Under the Model\n",
    "To see how big the distance would be if Mendel's model were true, we can use `sample_proportions` to simulate the distance under the assumptions of the model.\n",
    "\n",
    "First, we have to figure out how many times to sample. To do this, remember that we are going to compare our simulation with Mendel's plants. So we should simulate the same number of plants that he had.\n",
    "\n",
    "Mendel grew a lot of plants. There were 929 plants of the variety corresponding to this model. So we have to sample 929 times. \n",
    "\n",
    "#### Generating One Value of the Statistic\n",
    "\n",
    "The steps in the calculation:\n",
    "\n",
    "- Sample 929 times at random from the distribution specified by the model and find the sample proportion in the purple-flowering category. \n",
    "- Multiply the proportion by 100 to get a pecent.\n",
    "- Subtract 75 and take the absolute value of the difference.\n",
    "\n",
    "That's the statistic: the distance between the sample percent and 75."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will start by defining a function that takes a proportion and returns the absolute difference between the corresponding percent and 75."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def distance_from_75(p):\n",
    "    return abs(100*p - 75)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To simulate one value of the distance between the sample percent of purple-flowering plants and 75%, under the assumptions of Mendel's model, we have to first simulate the proportion of purple-flowering plants among 929 plants under the assumption of the model, and then calculate the discrepancy from 75%."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_proportions = [0.75, 0.25]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.565123789020447"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "proportion_purple_in_sample = sample_proportions(929, model_proportions).item(0)\n",
    "distance_from_75(proportion_purple_in_sample)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's one simulated value of the distance between the sample percent of purple-flowering plants and 75% as predicted by Mendel's model. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Running the Simulation\n",
    "To get a sense of how variable the distance could be, we have to simulate it many more times.\n",
    "\n",
    "We will generate 10,000 values of the distance. As before, we will first use the code we developed above to define a function that returns one simulated value Mendel's hypothesis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "def one_simulated_distance():\n",
    "    proportion_purple_in_sample = sample_proportions(929, model_proportions).item(0)\n",
    "    return distance_from_75(proportion_purple_in_sample)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we will use a `for` loop to create 10,000 such simulated distances."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "distances = np.array([])\n",
    "\n",
    "repetitions = 10000\n",
    "for i in np.arange(repetitions):\n",
    "    distances = np.append(distances, one_simulated_distance())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The Prediction\n",
    "The empirical histogram of the simulated values shows the distribution of the distance as predicted by Mendel's model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19444 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sample_distance = pd.DataFrame({'Distance between Sample % and 75%':distances})\n",
    "\n",
    "unit = ''\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "\n",
    "ax.hist(sample_distance, density=True, alpha=0.8, ec='white', zorder=5)\n",
    "\n",
    "y_vals = ax.get_yticks()\n",
    "\n",
    "y_label = 'Percent per ' + (unit if unit else 'unit')\n",
    "\n",
    "x_label = 'Distance between Sample % and 75%'\n",
    "\n",
    "ax.set_yticklabels(['{:g}'.format(x * 100) for x in y_vals])\n",
    "\n",
    "plt.ylabel(y_label)\n",
    "\n",
    "plt.xlabel(x_label)\n",
    "\n",
    "plt.title('');\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Look on the horizontal axis to see the typical values of the distance, as predicted by the model. They are rather small. For example, a high proportion of the distances are in the range 0 to 1, meaning that for a high proportion of the samples, the percent of purple-flowering plants is within 1% of 75%, that is, the sample percent is in the range 74% to 76%."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comparing the Prediction and the Data\n",
    "To assess the model, we have to compare this prediction with the data. Mendel recorded the number of purple and white flowering plants. Among the 929 plants that he grew, 705 were purple flowering. That's just about 75.89%."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7588805166846071"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "705 / 929"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So the observed value of our statistic – the distance between Mendel's sample percent and 75 – is about 0.89:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8880516684607045"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "observed_statistic = distance_from_75(705/929)\n",
    "observed_statistic"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Just by eye, locate roughly where 0.89 is on the horizontal axis of the histogram. You will see that it is clearly in the heart of the distribution predicted by Mendel's model.\n",
    "\n",
    "The cell below redraws the histogram with the observed value plotted on the horizontal axis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19676 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "distance_0_75 = pd.DataFrame({'Distance between Sample % and 75%':distances})\n",
    "\n",
    "unit = ''\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "\n",
    "ax.hist(distance_0_75, density=True, alpha=0.8, ec='white', zorder=5)\n",
    "\n",
    "ax.scatter(observed_statistic, 0, color='red', s=30, zorder=10).set_clip_on(False)\n",
    "\n",
    "y_vals = ax.get_yticks()\n",
    "\n",
    "y_label = 'Percent per ' + (unit if unit else 'unit')\n",
    "\n",
    "x_label = 'Distance between Sample % and 75%'\n",
    "\n",
    "ax.set_yticklabels(['{:g}'.format(x * 100) for x in y_vals])\n",
    "\n",
    "plt.ylabel(y_label)\n",
    "\n",
    "plt.xlabel(x_label)\n",
    "\n",
    "plt.title('');\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The observed statistic is like a typical distance predicted by the model. By this measure, the data are consistent with the histogram that we generated under the assumptions of Mendel's model. This is evidence in favor of the model."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
