{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Implementing CDFs\n", "\n", "This notebook outlines the API for `Cdf` objects in the `empiricaldist` library, showing the implementations of many methods.\n", "\n", "[Click here to run this notebook on Colab](https://colab.research.google.com/github/AllenDowney/empiricaldist/blob/master/empiricaldist/cdf_demo.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try:\n", " import empiricaldist\n", "except ImportError:\n", " !pip install empiricaldist" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import inspect\n", "\n", "def psource(obj):\n", " \"\"\"Prints the source code for a given object.\n", "\n", " obj: function or method object\n", " \"\"\"\n", " print(inspect.getsource(obj))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Constructor\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/11).\n", "\n", "The `Cdf` class inherits its constructor from `pd.Series`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can create an empty `Cdf` and then add elements.\n", "\n", "Here's a `Cdf` that representat a four-sided die." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from empiricaldist import Cdf\n", "\n", "d4 = Cdf()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "d4[1] = 1\n", "d4[2] = 2\n", "d4[3] = 3\n", "d4[4] = 4" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
11
22
33
44
\n", "
" ], "text/plain": [ "1 1\n", "2 2\n", "3 3\n", "4 4\n", "dtype: int64" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a normalized `Cdf`, the last probability is 1.\n", "\n", "`normalize` makes that true. The return value is the total probability before normalizing." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def normalize(self):\n", " \"\"\"Make the probabilities add up to 1 (modifies self).\n", "\n", " Returns: normalizing constant\n", " \"\"\"\n", " total = self.ps[-1]\n", " self /= total\n", " return total\n", "\n" ] } ], "source": [ "psource(Cdf.normalize)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.normalize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the Cdf is normalized." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "dtype: float64" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Properties\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/2).\n", "\n", "In a `Cdf` the index contains the quantities (`qs`) and the values contain the probabilities (`ps`).\n", "\n", "These attributes are available as properties that return arrays (same semantics as the Pandas `values` property)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.qs" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.25, 0.5 , 0.75, 1. ])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.ps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sharing\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/12).\n", "\n", "Because `Cdf` is a `Series` you can initialize it with any type `Series.__init__` can handle.\n", "\n", "Here's an example with a dictionary." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
a0.333333
b0.666667
c1.000000
\n", "
" ], "text/plain": [ "a 0.333333\n", "b 0.666667\n", "c 1.000000\n", "dtype: float64" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = dict(a=1, b=2, c=3)\n", "cdf = Cdf(d)\n", "cdf.normalize()\n", "cdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's an example with two lists." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "dtype: float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qs = [1,2,3,4]\n", "ps = [0.25, 0.5, 0.75, 1.0]\n", "d4 = Cdf(ps, index=qs)\n", "d4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can copy a `Cdf` like this." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "dtype: float64" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4_copy = Cdf(d4)\n", "d4_copy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, you have to be careful about sharing. In this example, the copies share the arrays:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.index is d4_copy.index" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.ps is d4_copy.ps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can avoid sharing with `copy=True`" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "dtype: float64" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4_copy = Cdf(d4, copy=True)\n", "d4_copy" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.index is d4_copy.index" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.ps is d4_copy.ps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or by calling `copy` explicitly." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "dtype: float64" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4_copy = d4.copy()\n", "d4_copy" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.index is d4_copy.index" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.ps is d4_copy.ps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Displaying CDFs\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/13).\n", "\n", "`Cdf` provides `_repr_html_`, so it looks good when displayed in a notebook." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def _repr_html_(self):\n", " \"\"\"Returns an HTML representation of the series.\n", "\n", " Mostly used for Jupyter notebooks.\n", " \"\"\"\n", " df = pd.DataFrame(dict(probs=self))\n", " return df._repr_html_()\n", "\n" ] } ], "source": [ "psource(Cdf._repr_html_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Cdf` provides `plot`, which plots the Cdf as a line." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "class PlotAccessor(PandasObject):\n", " \"\"\"\n", " Make plots of Series or DataFrame.\n", "\n", " Uses the backend specified by the\n", " option ``plotting.backend``. By default, matplotlib is used.\n", "\n", " Parameters\n", " ----------\n", " data : Series or DataFrame\n", " The object for which the method is called.\n", " x : label or position, default None\n", " Only used if data is a DataFrame.\n", " y : label, position or list of label, positions, default None\n", " Allows plotting of one column versus another. Only used if data is a\n", " DataFrame.\n", " kind : str\n", " The kind of plot to produce:\n", "\n", " - 'line' : line plot (default)\n", " - 'bar' : vertical bar plot\n", " - 'barh' : horizontal bar plot\n", " - 'hist' : histogram\n", " - 'box' : boxplot\n", " - 'kde' : Kernel Density Estimation plot\n", " - 'density' : same as 'kde'\n", " - 'area' : area plot\n", " - 'pie' : pie plot\n", " - 'scatter' : scatter plot (DataFrame only)\n", " - 'hexbin' : hexbin plot (DataFrame only)\n", " ax : matplotlib axes object, default None\n", " An axes of the current figure.\n", " subplots : bool or sequence of iterables, default False\n", " Whether to group columns into subplots:\n", "\n", " - ``False`` : No subplots will be used\n", " - ``True`` : Make separate subplots for each column.\n", " - sequence of iterables of column labels: Create a subplot for each\n", " group of columns. For example `[('a', 'c'), ('b', 'd')]` will\n", " create 2 subplots: one with columns 'a' and 'c', and one\n", " with columns 'b' and 'd'. Remaining columns that aren't specified\n", " will be plotted in additional subplots (one per column).\n", "\n", " .. versionadded:: 1.5.0\n", "\n", " sharex : bool, default True if ax is None else False\n", " In case ``subplots=True``, share x axis and set some x axis labels\n", " to invisible; defaults to True if ax is None otherwise False if\n", " an ax is passed in; Be aware, that passing in both an ax and\n", " ``sharex=True`` will alter all x axis labels for all axis in a figure.\n", " sharey : bool, default False\n", " In case ``subplots=True``, share y axis and set some y axis labels to invisible.\n", " layout : tuple, optional\n", " (rows, columns) for the layout of subplots.\n", " figsize : a tuple (width, height) in inches\n", " Size of a figure object.\n", " use_index : bool, default True\n", " Use index as ticks for x axis.\n", " title : str or list\n", " Title to use for the plot. If a string is passed, print the string\n", " at the top of the figure. If a list is passed and `subplots` is\n", " True, print each item in the list above the corresponding subplot.\n", " grid : bool, default None (matlab style default)\n", " Axis grid lines.\n", " legend : bool or {'reverse'}\n", " Place legend on axis subplots.\n", " style : list or dict\n", " The matplotlib line style per column.\n", " logx : bool or 'sym', default False\n", " Use log scaling or symlog scaling on x axis.\n", "\n", " logy : bool or 'sym' default False\n", " Use log scaling or symlog scaling on y axis.\n", "\n", " loglog : bool or 'sym', default False\n", " Use log scaling or symlog scaling on both x and y axes.\n", "\n", " xticks : sequence\n", " Values to use for the xticks.\n", " yticks : sequence\n", " Values to use for the yticks.\n", " xlim : 2-tuple/list\n", " Set the x limits of the current axes.\n", " ylim : 2-tuple/list\n", " Set the y limits of the current axes.\n", " xlabel : label, optional\n", " Name to use for the xlabel on x-axis. Default uses index name as xlabel, or the\n", " x-column name for planar plots.\n", "\n", " .. versionchanged:: 1.2.0\n", "\n", " Now applicable to planar plots (`scatter`, `hexbin`).\n", "\n", " .. versionchanged:: 2.0.0\n", "\n", " Now applicable to histograms.\n", "\n", " ylabel : label, optional\n", " Name to use for the ylabel on y-axis. Default will show no ylabel, or the\n", " y-column name for planar plots.\n", "\n", " .. versionchanged:: 1.2.0\n", "\n", " Now applicable to planar plots (`scatter`, `hexbin`).\n", "\n", " .. versionchanged:: 2.0.0\n", "\n", " Now applicable to histograms.\n", "\n", " rot : float, default None\n", " Rotation for ticks (xticks for vertical, yticks for horizontal\n", " plots).\n", " fontsize : float, default None\n", " Font size for xticks and yticks.\n", " colormap : str or matplotlib colormap object, default None\n", " Colormap to select colors from. If string, load colormap with that\n", " name from matplotlib.\n", " colorbar : bool, optional\n", " If True, plot colorbar (only relevant for 'scatter' and 'hexbin'\n", " plots).\n", " position : float\n", " Specify relative alignments for bar plot layout.\n", " From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5\n", " (center).\n", " table : bool, Series or DataFrame, default False\n", " If True, draw a table using the data in the DataFrame and the data\n", " will be transposed to meet matplotlib's default layout.\n", " If a Series or DataFrame is passed, use passed data to draw a\n", " table.\n", " yerr : DataFrame, Series, array-like, dict and str\n", " See :ref:`Plotting with Error Bars ` for\n", " detail.\n", " xerr : DataFrame, Series, array-like, dict and str\n", " Equivalent to yerr.\n", " stacked : bool, default False in line and bar plots, and True in area plot\n", " If True, create stacked plot.\n", " secondary_y : bool or sequence, default False\n", " Whether to plot on the secondary y-axis if a list/tuple, which\n", " columns to plot on secondary y-axis.\n", " mark_right : bool, default True\n", " When using a secondary_y axis, automatically mark the column\n", " labels with \"(right)\" in the legend.\n", " include_bool : bool, default is False\n", " If True, boolean values can be plotted.\n", " backend : str, default None\n", " Backend to use instead of the backend specified in the option\n", " ``plotting.backend``. For instance, 'matplotlib'. Alternatively, to\n", " specify the ``plotting.backend`` for the whole session, set\n", " ``pd.options.plotting.backend``.\n", " **kwargs\n", " Options to pass to matplotlib plotting method.\n", "\n", " Returns\n", " -------\n", " :class:`matplotlib.axes.Axes` or numpy.ndarray of them\n", " If the backend is not the default matplotlib one, the return value\n", " will be the object returned by the backend.\n", "\n", " Notes\n", " -----\n", " - See matplotlib documentation online for more on this subject\n", " - If `kind` = 'bar' or 'barh', you can specify relative alignments\n", " for bar plot layout by `position` keyword.\n", " From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5\n", " (center)\n", "\n", " Examples\n", " --------\n", " For Series:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ser = pd.Series([1, 2, 3, 3])\n", " >>> plot = ser.plot(kind='hist', title=\"My plot\")\n", "\n", " For DataFrame:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({'length': [1.5, 0.5, 1.2, 0.9, 3],\n", " ... 'width': [0.7, 0.2, 0.15, 0.2, 1.1]},\n", " ... index=['pig', 'rabbit', 'duck', 'chicken', 'horse'])\n", " >>> plot = df.plot(title=\"DataFrame Plot\")\n", "\n", " For SeriesGroupBy:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> lst = [-1, -2, -3, 1, 2, 3]\n", " >>> ser = pd.Series([1, 2, 2, 4, 6, 6], index=lst)\n", " >>> plot = ser.groupby(lambda x: x > 0).plot(title=\"SeriesGroupBy Plot\")\n", "\n", " For DataFrameGroupBy:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({\"col1\" : [1, 2, 3, 4],\n", " ... \"col2\" : [\"A\", \"B\", \"A\", \"B\"]})\n", " >>> plot = df.groupby(\"col2\").plot(kind=\"bar\", title=\"DataFrameGroupBy Plot\")\n", " \"\"\"\n", "\n", " _common_kinds = (\"line\", \"bar\", \"barh\", \"kde\", \"density\", \"area\", \"hist\", \"box\")\n", " _series_kinds = (\"pie\",)\n", " _dataframe_kinds = (\"scatter\", \"hexbin\")\n", " _kind_aliases = {\"density\": \"kde\"}\n", " _all_kinds = _common_kinds + _series_kinds + _dataframe_kinds\n", "\n", " def __init__(self, data) -> None:\n", " self._parent = data\n", "\n", " @staticmethod\n", " def _get_call_args(backend_name: str, data, args, kwargs):\n", " \"\"\"\n", " This function makes calls to this accessor `__call__` method compatible\n", " with the previous `SeriesPlotMethods.__call__` and\n", " `DataFramePlotMethods.__call__`. Those had slightly different\n", " signatures, since `DataFramePlotMethods` accepted `x` and `y`\n", " parameters.\n", " \"\"\"\n", " if isinstance(data, ABCSeries):\n", " arg_def = [\n", " (\"kind\", \"line\"),\n", " (\"ax\", None),\n", " (\"figsize\", None),\n", " (\"use_index\", True),\n", " (\"title\", None),\n", " (\"grid\", None),\n", " (\"legend\", False),\n", " (\"style\", None),\n", " (\"logx\", False),\n", " (\"logy\", False),\n", " (\"loglog\", False),\n", " (\"xticks\", None),\n", " (\"yticks\", None),\n", " (\"xlim\", None),\n", " (\"ylim\", None),\n", " (\"rot\", None),\n", " (\"fontsize\", None),\n", " (\"colormap\", None),\n", " (\"table\", False),\n", " (\"yerr\", None),\n", " (\"xerr\", None),\n", " (\"label\", None),\n", " (\"secondary_y\", False),\n", " (\"xlabel\", None),\n", " (\"ylabel\", None),\n", " ]\n", " elif isinstance(data, ABCDataFrame):\n", " arg_def = [\n", " (\"x\", None),\n", " (\"y\", None),\n", " (\"kind\", \"line\"),\n", " (\"ax\", None),\n", " (\"subplots\", False),\n", " (\"sharex\", None),\n", " (\"sharey\", False),\n", " (\"layout\", None),\n", " (\"figsize\", None),\n", " (\"use_index\", True),\n", " (\"title\", None),\n", " (\"grid\", None),\n", " (\"legend\", True),\n", " (\"style\", None),\n", " (\"logx\", False),\n", " (\"logy\", False),\n", " (\"loglog\", False),\n", " (\"xticks\", None),\n", " (\"yticks\", None),\n", " (\"xlim\", None),\n", " (\"ylim\", None),\n", " (\"rot\", None),\n", " (\"fontsize\", None),\n", " (\"colormap\", None),\n", " (\"table\", False),\n", " (\"yerr\", None),\n", " (\"xerr\", None),\n", " (\"secondary_y\", False),\n", " (\"xlabel\", None),\n", " (\"ylabel\", None),\n", " ]\n", " else:\n", " raise TypeError(\n", " f\"Called plot accessor for type {type(data).__name__}, \"\n", " \"expected Series or DataFrame\"\n", " )\n", "\n", " if args and isinstance(data, ABCSeries):\n", " positional_args = str(args)[1:-1]\n", " keyword_args = \", \".join(\n", " [f\"{name}={repr(value)}\" for (name, _), value in zip(arg_def, args)]\n", " )\n", " msg = (\n", " \"`Series.plot()` should not be called with positional \"\n", " \"arguments, only keyword arguments. The order of \"\n", " \"positional arguments will change in the future. \"\n", " f\"Use `Series.plot({keyword_args})` instead of \"\n", " f\"`Series.plot({positional_args})`.\"\n", " )\n", " raise TypeError(msg)\n", "\n", " pos_args = {name: value for (name, _), value in zip(arg_def, args)}\n", " if backend_name == \"pandas.plotting._matplotlib\":\n", " kwargs = dict(arg_def, **pos_args, **kwargs)\n", " else:\n", " kwargs = dict(pos_args, **kwargs)\n", "\n", " x = kwargs.pop(\"x\", None)\n", " y = kwargs.pop(\"y\", None)\n", " kind = kwargs.pop(\"kind\", \"line\")\n", " return x, y, kind, kwargs\n", "\n", " def __call__(self, *args, **kwargs):\n", " plot_backend = _get_plot_backend(kwargs.pop(\"backend\", None))\n", "\n", " x, y, kind, kwargs = self._get_call_args(\n", " plot_backend.__name__, self._parent, args, kwargs\n", " )\n", "\n", " kind = self._kind_aliases.get(kind, kind)\n", "\n", " # when using another backend, get out of the way\n", " if plot_backend.__name__ != \"pandas.plotting._matplotlib\":\n", " return plot_backend.plot(self._parent, x=x, y=y, kind=kind, **kwargs)\n", "\n", " if kind not in self._all_kinds:\n", " raise ValueError(f\"{kind} is not a valid plot kind\")\n", "\n", " # The original data structured can be transformed before passed to the\n", " # backend. For example, for DataFrame is common to set the index as the\n", " # `x` parameter, and return a Series with the parameter `y` as values.\n", " data = self._parent.copy()\n", "\n", " if isinstance(data, ABCSeries):\n", " kwargs[\"reuse_plot\"] = True\n", "\n", " if kind in self._dataframe_kinds:\n", " if isinstance(data, ABCDataFrame):\n", " return plot_backend.plot(data, x=x, y=y, kind=kind, **kwargs)\n", " else:\n", " raise ValueError(f\"plot kind {kind} can only be used for data frames\")\n", " elif kind in self._series_kinds:\n", " if isinstance(data, ABCDataFrame):\n", " if y is None and kwargs.get(\"subplots\") is False:\n", " raise ValueError(\n", " f\"{kind} requires either y column or 'subplots=True'\"\n", " )\n", " if y is not None:\n", " if is_integer(y) and not data.columns._holds_integer():\n", " y = data.columns[y]\n", " # converted to series actually. copy to not modify\n", " data = data[y].copy()\n", " data.index.name = y\n", " elif isinstance(data, ABCDataFrame):\n", " data_cols = data.columns\n", " if x is not None:\n", " if is_integer(x) and not data.columns._holds_integer():\n", " x = data_cols[x]\n", " elif not isinstance(data[x], ABCSeries):\n", " raise ValueError(\"x must be a label or position\")\n", " data = data.set_index(x)\n", " if y is not None:\n", " # check if we have y as int or list of ints\n", " int_ylist = is_list_like(y) and all(is_integer(c) for c in y)\n", " int_y_arg = is_integer(y) or int_ylist\n", " if int_y_arg and not data.columns._holds_integer():\n", " y = data_cols[y]\n", "\n", " label_kw = kwargs[\"label\"] if \"label\" in kwargs else False\n", " for kw in [\"xerr\", \"yerr\"]:\n", " if kw in kwargs and (\n", " isinstance(kwargs[kw], str) or is_integer(kwargs[kw])\n", " ):\n", " try:\n", " kwargs[kw] = data[kwargs[kw]]\n", " except (IndexError, KeyError, TypeError):\n", " pass\n", "\n", " # don't overwrite\n", " data = data[y].copy()\n", "\n", " if isinstance(data, ABCSeries):\n", " label_name = label_kw or y\n", " data.name = label_name\n", " else:\n", " match = is_list_like(label_kw) and len(label_kw) == len(y)\n", " if label_kw and not match:\n", " raise ValueError(\n", " \"label should be list-like and same length as y\"\n", " )\n", " label_name = label_kw or data.columns\n", " data.columns = label_name\n", "\n", " return plot_backend.plot(data, kind=kind, **kwargs)\n", "\n", " __call__.__doc__ = __doc__\n", "\n", " @Appender(\n", " \"\"\"\n", " See Also\n", " --------\n", " matplotlib.pyplot.plot : Plot y versus x as lines and/or markers.\n", "\n", " Examples\n", " --------\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> s = pd.Series([1, 3, 2])\n", " >>> s.plot.line() # doctest: +SKIP\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " The following example shows the populations for some animals\n", " over the years.\n", "\n", " >>> df = pd.DataFrame({\n", " ... 'pig': [20, 18, 489, 675, 1776],\n", " ... 'horse': [4, 25, 281, 600, 1900]\n", " ... }, index=[1990, 1997, 2003, 2009, 2014])\n", " >>> lines = df.plot.line()\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " An example with subplots, so an array of axes is returned.\n", "\n", " >>> axes = df.plot.line(subplots=True)\n", " >>> type(axes)\n", " \n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " Let's repeat the same example, but specifying colors for\n", " each column (in this case, for each animal).\n", "\n", " >>> axes = df.plot.line(\n", " ... subplots=True, color={\"pig\": \"pink\", \"horse\": \"#742802\"}\n", " ... )\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " The following example shows the relationship between both\n", " populations.\n", "\n", " >>> lines = df.plot.line(x='pig', y='horse')\n", " \"\"\"\n", " )\n", " @Substitution(kind=\"line\")\n", " @Appender(_bar_or_line_doc)\n", " def line(\n", " self, x: Hashable | None = None, y: Hashable | None = None, **kwargs\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Plot Series or DataFrame as lines.\n", "\n", " This function is useful to plot lines using DataFrame's values\n", " as coordinates.\n", " \"\"\"\n", " return self(kind=\"line\", x=x, y=y, **kwargs)\n", "\n", " @Appender(\n", " \"\"\"\n", " See Also\n", " --------\n", " DataFrame.plot.barh : Horizontal bar plot.\n", " DataFrame.plot : Make plots of a DataFrame.\n", " matplotlib.pyplot.bar : Make a bar plot with matplotlib.\n", "\n", " Examples\n", " --------\n", " Basic plot.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({'lab':['A', 'B', 'C'], 'val':[10, 30, 20]})\n", " >>> ax = df.plot.bar(x='lab', y='val', rot=0)\n", "\n", " Plot a whole dataframe to a bar plot. Each column is assigned a\n", " distinct color, and each row is nested in a group along the\n", " horizontal axis.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> speed = [0.1, 17.5, 40, 48, 52, 69, 88]\n", " >>> lifespan = [2, 8, 70, 1.5, 25, 12, 28]\n", " >>> index = ['snail', 'pig', 'elephant',\n", " ... 'rabbit', 'giraffe', 'coyote', 'horse']\n", " >>> df = pd.DataFrame({'speed': speed,\n", " ... 'lifespan': lifespan}, index=index)\n", " >>> ax = df.plot.bar(rot=0)\n", "\n", " Plot stacked bar charts for the DataFrame\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.bar(stacked=True)\n", "\n", " Instead of nesting, the figure can be split by column with\n", " ``subplots=True``. In this case, a :class:`numpy.ndarray` of\n", " :class:`matplotlib.axes.Axes` are returned.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> axes = df.plot.bar(rot=0, subplots=True)\n", " >>> axes[1].legend(loc=2) # doctest: +SKIP\n", "\n", " If you don't like the default colours, you can specify how you'd\n", " like each column to be colored.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> axes = df.plot.bar(\n", " ... rot=0, subplots=True, color={\"speed\": \"red\", \"lifespan\": \"green\"}\n", " ... )\n", " >>> axes[1].legend(loc=2) # doctest: +SKIP\n", "\n", " Plot a single column.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.bar(y='speed', rot=0)\n", "\n", " Plot only selected categories for the DataFrame.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.bar(x='lifespan', rot=0)\n", " \"\"\"\n", " )\n", " @Substitution(kind=\"bar\")\n", " @Appender(_bar_or_line_doc)\n", " def bar( # pylint: disable=disallowed-name\n", " self, x: Hashable | None = None, y: Hashable | None = None, **kwargs\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Vertical bar plot.\n", "\n", " A bar plot is a plot that presents categorical data with\n", " rectangular bars with lengths proportional to the values that they\n", " represent. A bar plot shows comparisons among discrete categories. One\n", " axis of the plot shows the specific categories being compared, and the\n", " other axis represents a measured value.\n", " \"\"\"\n", " return self(kind=\"bar\", x=x, y=y, **kwargs)\n", "\n", " @Appender(\n", " \"\"\"\n", " See Also\n", " --------\n", " DataFrame.plot.bar: Vertical bar plot.\n", " DataFrame.plot : Make plots of DataFrame using matplotlib.\n", " matplotlib.axes.Axes.bar : Plot a vertical bar plot using matplotlib.\n", "\n", " Examples\n", " --------\n", " Basic example\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({'lab': ['A', 'B', 'C'], 'val': [10, 30, 20]})\n", " >>> ax = df.plot.barh(x='lab', y='val')\n", "\n", " Plot a whole DataFrame to a horizontal bar plot\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> speed = [0.1, 17.5, 40, 48, 52, 69, 88]\n", " >>> lifespan = [2, 8, 70, 1.5, 25, 12, 28]\n", " >>> index = ['snail', 'pig', 'elephant',\n", " ... 'rabbit', 'giraffe', 'coyote', 'horse']\n", " >>> df = pd.DataFrame({'speed': speed,\n", " ... 'lifespan': lifespan}, index=index)\n", " >>> ax = df.plot.barh()\n", "\n", " Plot stacked barh charts for the DataFrame\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.barh(stacked=True)\n", "\n", " We can specify colors for each column\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.barh(color={\"speed\": \"red\", \"lifespan\": \"green\"})\n", "\n", " Plot a column of the DataFrame to a horizontal bar plot\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> speed = [0.1, 17.5, 40, 48, 52, 69, 88]\n", " >>> lifespan = [2, 8, 70, 1.5, 25, 12, 28]\n", " >>> index = ['snail', 'pig', 'elephant',\n", " ... 'rabbit', 'giraffe', 'coyote', 'horse']\n", " >>> df = pd.DataFrame({'speed': speed,\n", " ... 'lifespan': lifespan}, index=index)\n", " >>> ax = df.plot.barh(y='speed')\n", "\n", " Plot DataFrame versus the desired column\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> speed = [0.1, 17.5, 40, 48, 52, 69, 88]\n", " >>> lifespan = [2, 8, 70, 1.5, 25, 12, 28]\n", " >>> index = ['snail', 'pig', 'elephant',\n", " ... 'rabbit', 'giraffe', 'coyote', 'horse']\n", " >>> df = pd.DataFrame({'speed': speed,\n", " ... 'lifespan': lifespan}, index=index)\n", " >>> ax = df.plot.barh(x='lifespan')\n", " \"\"\"\n", " )\n", " @Substitution(kind=\"bar\")\n", " @Appender(_bar_or_line_doc)\n", " def barh(\n", " self, x: Hashable | None = None, y: Hashable | None = None, **kwargs\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Make a horizontal bar plot.\n", "\n", " A horizontal bar plot is a plot that presents quantitative data with\n", " rectangular bars with lengths proportional to the values that they\n", " represent. A bar plot shows comparisons among discrete categories. One\n", " axis of the plot shows the specific categories being compared, and the\n", " other axis represents a measured value.\n", " \"\"\"\n", " return self(kind=\"barh\", x=x, y=y, **kwargs)\n", "\n", " def box(self, by: IndexLabel | None = None, **kwargs) -> PlotAccessor:\n", " r\"\"\"\n", " Make a box plot of the DataFrame columns.\n", "\n", " A box plot is a method for graphically depicting groups of numerical\n", " data through their quartiles.\n", " The box extends from the Q1 to Q3 quartile values of the data,\n", " with a line at the median (Q2). The whiskers extend from the edges\n", " of box to show the range of the data. The position of the whiskers\n", " is set by default to 1.5*IQR (IQR = Q3 - Q1) from the edges of the\n", " box. Outlier points are those past the end of the whiskers.\n", "\n", " For further details see Wikipedia's\n", " entry for `boxplot `__.\n", "\n", " A consideration when using this chart is that the box and the whiskers\n", " can overlap, which is very common when plotting small sets of data.\n", "\n", " Parameters\n", " ----------\n", " by : str or sequence\n", " Column in the DataFrame to group by.\n", "\n", " .. versionchanged:: 1.4.0\n", "\n", " Previously, `by` is silently ignore and makes no groupings\n", "\n", " **kwargs\n", " Additional keywords are documented in\n", " :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " :class:`matplotlib.axes.Axes` or numpy.ndarray of them\n", "\n", " See Also\n", " --------\n", " DataFrame.boxplot: Another method to draw a box plot.\n", " Series.plot.box: Draw a box plot from a Series object.\n", " matplotlib.pyplot.boxplot: Draw a box plot in matplotlib.\n", "\n", " Examples\n", " --------\n", " Draw a box plot from a DataFrame with four columns of randomly\n", " generated data.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> data = np.random.randn(25, 4)\n", " >>> df = pd.DataFrame(data, columns=list('ABCD'))\n", " >>> ax = df.plot.box()\n", "\n", " You can also generate groupings if you specify the `by` parameter (which\n", " can take a column name, or a list or tuple of column names):\n", "\n", " .. versionchanged:: 1.4.0\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> age_list = [8, 10, 12, 14, 72, 74, 76, 78, 20, 25, 30, 35, 60, 85]\n", " >>> df = pd.DataFrame({\"gender\": list(\"MMMMMMMMFFFFFF\"), \"age\": age_list})\n", " >>> ax = df.plot.box(column=\"age\", by=\"gender\", figsize=(10, 8))\n", " \"\"\"\n", " return self(kind=\"box\", by=by, **kwargs)\n", "\n", " def hist(\n", " self, by: IndexLabel | None = None, bins: int = 10, **kwargs\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Draw one histogram of the DataFrame's columns.\n", "\n", " A histogram is a representation of the distribution of data.\n", " This function groups the values of all given Series in the DataFrame\n", " into bins and draws all bins in one :class:`matplotlib.axes.Axes`.\n", " This is useful when the DataFrame's Series are in a similar scale.\n", "\n", " Parameters\n", " ----------\n", " by : str or sequence, optional\n", " Column in the DataFrame to group by.\n", "\n", " .. versionchanged:: 1.4.0\n", "\n", " Previously, `by` is silently ignore and makes no groupings\n", "\n", " bins : int, default 10\n", " Number of histogram bins to be used.\n", " **kwargs\n", " Additional keyword arguments are documented in\n", " :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " class:`matplotlib.AxesSubplot`\n", " Return a histogram plot.\n", "\n", " See Also\n", " --------\n", " DataFrame.hist : Draw histograms per DataFrame's Series.\n", " Series.hist : Draw a histogram with Series' data.\n", "\n", " Examples\n", " --------\n", " When we roll a die 6000 times, we expect to get each value around 1000\n", " times. But when we roll two dice and sum the result, the distribution\n", " is going to be quite different. A histogram illustrates those\n", " distributions.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame(\n", " ... np.random.randint(1, 7, 6000),\n", " ... columns = ['one'])\n", " >>> df['two'] = df['one'] + np.random.randint(1, 7, 6000)\n", " >>> ax = df.plot.hist(bins=12, alpha=0.5)\n", "\n", " A grouped histogram can be generated by providing the parameter `by` (which\n", " can be a column name, or a list of column names):\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> age_list = [8, 10, 12, 14, 72, 74, 76, 78, 20, 25, 30, 35, 60, 85]\n", " >>> df = pd.DataFrame({\"gender\": list(\"MMMMMMMMFFFFFF\"), \"age\": age_list})\n", " >>> ax = df.plot.hist(column=[\"age\"], by=\"gender\", figsize=(10, 8))\n", " \"\"\"\n", " return self(kind=\"hist\", by=by, bins=bins, **kwargs)\n", "\n", " def kde(\n", " self,\n", " bw_method: Literal[\"scott\", \"silverman\"] | float | Callable | None = None,\n", " ind: np.ndarray | int | None = None,\n", " **kwargs,\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Generate Kernel Density Estimate plot using Gaussian kernels.\n", "\n", " In statistics, `kernel density estimation`_ (KDE) is a non-parametric\n", " way to estimate the probability density function (PDF) of a random\n", " variable. This function uses Gaussian kernels and includes automatic\n", " bandwidth determination.\n", "\n", " .. _kernel density estimation:\n", " https://en.wikipedia.org/wiki/Kernel_density_estimation\n", "\n", " Parameters\n", " ----------\n", " bw_method : str, scalar or callable, optional\n", " The method used to calculate the estimator bandwidth. This can be\n", " 'scott', 'silverman', a scalar constant or a callable.\n", " If None (default), 'scott' is used.\n", " See :class:`scipy.stats.gaussian_kde` for more information.\n", " ind : NumPy array or int, optional\n", " Evaluation points for the estimated PDF. If None (default),\n", " 1000 equally spaced points are used. If `ind` is a NumPy array, the\n", " KDE is evaluated at the points passed. If `ind` is an integer,\n", " `ind` number of equally spaced points are used.\n", " **kwargs\n", " Additional keyword arguments are documented in\n", " :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " matplotlib.axes.Axes or numpy.ndarray of them\n", "\n", " See Also\n", " --------\n", " scipy.stats.gaussian_kde : Representation of a kernel-density\n", " estimate using Gaussian kernels. This is the function used\n", " internally to estimate the PDF.\n", "\n", " Examples\n", " --------\n", " Given a Series of points randomly sampled from an unknown\n", " distribution, estimate its PDF using KDE with automatic\n", " bandwidth determination and plot the results, evaluating them at\n", " 1000 equally spaced points (default):\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> s = pd.Series([1, 2, 2.5, 3, 3.5, 4, 5])\n", " >>> ax = s.plot.kde()\n", "\n", " A scalar bandwidth can be specified. Using a small bandwidth value can\n", " lead to over-fitting, while using a large bandwidth value may result\n", " in under-fitting:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = s.plot.kde(bw_method=0.3)\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = s.plot.kde(bw_method=3)\n", "\n", " Finally, the `ind` parameter determines the evaluation points for the\n", " plot of the estimated PDF:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = s.plot.kde(ind=[1, 2, 3, 4, 5])\n", "\n", " For DataFrame, it works in the same way:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({\n", " ... 'x': [1, 2, 2.5, 3, 3.5, 4, 5],\n", " ... 'y': [4, 4, 4.5, 5, 5.5, 6, 6],\n", " ... })\n", " >>> ax = df.plot.kde()\n", "\n", " A scalar bandwidth can be specified. Using a small bandwidth value can\n", " lead to over-fitting, while using a large bandwidth value may result\n", " in under-fitting:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.kde(bw_method=0.3)\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.kde(bw_method=3)\n", "\n", " Finally, the `ind` parameter determines the evaluation points for the\n", " plot of the estimated PDF:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.kde(ind=[1, 2, 3, 4, 5, 6])\n", " \"\"\"\n", " return self(kind=\"kde\", bw_method=bw_method, ind=ind, **kwargs)\n", "\n", " density = kde\n", "\n", " def area(\n", " self,\n", " x: Hashable | None = None,\n", " y: Hashable | None = None,\n", " stacked: bool = True,\n", " **kwargs,\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Draw a stacked area plot.\n", "\n", " An area plot displays quantitative data visually.\n", " This function wraps the matplotlib area function.\n", "\n", " Parameters\n", " ----------\n", " x : label or position, optional\n", " Coordinates for the X axis. By default uses the index.\n", " y : label or position, optional\n", " Column to plot. By default uses all columns.\n", " stacked : bool, default True\n", " Area plots are stacked by default. Set to False to create a\n", " unstacked plot.\n", " **kwargs\n", " Additional keyword arguments are documented in\n", " :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " matplotlib.axes.Axes or numpy.ndarray\n", " Area plot, or array of area plots if subplots is True.\n", "\n", " See Also\n", " --------\n", " DataFrame.plot : Make plots of DataFrame using matplotlib / pylab.\n", "\n", " Examples\n", " --------\n", " Draw an area plot based on basic business metrics:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({\n", " ... 'sales': [3, 2, 3, 9, 10, 6],\n", " ... 'signups': [5, 5, 6, 12, 14, 13],\n", " ... 'visits': [20, 42, 28, 62, 81, 50],\n", " ... }, index=pd.date_range(start='2018/01/01', end='2018/07/01',\n", " ... freq='M'))\n", " >>> ax = df.plot.area()\n", "\n", " Area plots are stacked by default. To produce an unstacked plot,\n", " pass ``stacked=False``:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.area(stacked=False)\n", "\n", " Draw an area plot for a single column:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax = df.plot.area(y='sales')\n", "\n", " Draw with a different `x`:\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({\n", " ... 'sales': [3, 2, 3],\n", " ... 'visits': [20, 42, 28],\n", " ... 'day': [1, 2, 3],\n", " ... })\n", " >>> ax = df.plot.area(x='day')\n", " \"\"\"\n", " return self(kind=\"area\", x=x, y=y, stacked=stacked, **kwargs)\n", "\n", " def pie(self, **kwargs) -> PlotAccessor:\n", " \"\"\"\n", " Generate a pie plot.\n", "\n", " A pie plot is a proportional representation of the numerical data in a\n", " column. This function wraps :meth:`matplotlib.pyplot.pie` for the\n", " specified column. If no column reference is passed and\n", " ``subplots=True`` a pie plot is drawn for each numerical column\n", " independently.\n", "\n", " Parameters\n", " ----------\n", " y : int or label, optional\n", " Label or position of the column to plot.\n", " If not provided, ``subplots=True`` argument must be passed.\n", " **kwargs\n", " Keyword arguments to pass on to :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " matplotlib.axes.Axes or np.ndarray of them\n", " A NumPy array is returned when `subplots` is True.\n", "\n", " See Also\n", " --------\n", " Series.plot.pie : Generate a pie plot for a Series.\n", " DataFrame.plot : Make plots of a DataFrame.\n", "\n", " Examples\n", " --------\n", " In the example below we have a DataFrame with the information about\n", " planet's mass and radius. We pass the 'mass' column to the\n", " pie function to get a pie plot.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame({'mass': [0.330, 4.87 , 5.97],\n", " ... 'radius': [2439.7, 6051.8, 6378.1]},\n", " ... index=['Mercury', 'Venus', 'Earth'])\n", " >>> plot = df.plot.pie(y='mass', figsize=(5, 5))\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> plot = df.plot.pie(subplots=True, figsize=(11, 6))\n", " \"\"\"\n", " if (\n", " isinstance(self._parent, ABCDataFrame)\n", " and kwargs.get(\"y\", None) is None\n", " and not kwargs.get(\"subplots\", False)\n", " ):\n", " raise ValueError(\"pie requires either y column or 'subplots=True'\")\n", " return self(kind=\"pie\", **kwargs)\n", "\n", " def scatter(\n", " self,\n", " x: Hashable,\n", " y: Hashable,\n", " s: Hashable | Sequence[Hashable] | None = None,\n", " c: Hashable | Sequence[Hashable] | None = None,\n", " **kwargs,\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Create a scatter plot with varying marker point size and color.\n", "\n", " The coordinates of each point are defined by two dataframe columns and\n", " filled circles are used to represent each point. This kind of plot is\n", " useful to see complex correlations between two variables. Points could\n", " be for instance natural 2D coordinates like longitude and latitude in\n", " a map or, in general, any pair of metrics that can be plotted against\n", " each other.\n", "\n", " Parameters\n", " ----------\n", " x : int or str\n", " The column name or column position to be used as horizontal\n", " coordinates for each point.\n", " y : int or str\n", " The column name or column position to be used as vertical\n", " coordinates for each point.\n", " s : str, scalar or array-like, optional\n", " The size of each point. Possible values are:\n", "\n", " - A string with the name of the column to be used for marker's size.\n", "\n", " - A single scalar so all points have the same size.\n", "\n", " - A sequence of scalars, which will be used for each point's size\n", " recursively. For instance, when passing [2,14] all points size\n", " will be either 2 or 14, alternatively.\n", "\n", " c : str, int or array-like, optional\n", " The color of each point. Possible values are:\n", "\n", " - A single color string referred to by name, RGB or RGBA code,\n", " for instance 'red' or '#a98d19'.\n", "\n", " - A sequence of color strings referred to by name, RGB or RGBA\n", " code, which will be used for each point's color recursively. For\n", " instance ['green','yellow'] all points will be filled in green or\n", " yellow, alternatively.\n", "\n", " - A column name or position whose values will be used to color the\n", " marker points according to a colormap.\n", "\n", " **kwargs\n", " Keyword arguments to pass on to :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " :class:`matplotlib.axes.Axes` or numpy.ndarray of them\n", "\n", " See Also\n", " --------\n", " matplotlib.pyplot.scatter : Scatter plot using multiple input data\n", " formats.\n", "\n", " Examples\n", " --------\n", " Let's see how to draw a scatter plot using coordinates from the values\n", " in a DataFrame's columns.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> df = pd.DataFrame([[5.1, 3.5, 0], [4.9, 3.0, 0], [7.0, 3.2, 1],\n", " ... [6.4, 3.2, 1], [5.9, 3.0, 2]],\n", " ... columns=['length', 'width', 'species'])\n", " >>> ax1 = df.plot.scatter(x='length',\n", " ... y='width',\n", " ... c='DarkBlue')\n", "\n", " And now with the color determined by a column as well.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> ax2 = df.plot.scatter(x='length',\n", " ... y='width',\n", " ... c='species',\n", " ... colormap='viridis')\n", " \"\"\"\n", " return self(kind=\"scatter\", x=x, y=y, s=s, c=c, **kwargs)\n", "\n", " def hexbin(\n", " self,\n", " x: Hashable,\n", " y: Hashable,\n", " C: Hashable | None = None,\n", " reduce_C_function: Callable | None = None,\n", " gridsize: int | tuple[int, int] | None = None,\n", " **kwargs,\n", " ) -> PlotAccessor:\n", " \"\"\"\n", " Generate a hexagonal binning plot.\n", "\n", " Generate a hexagonal binning plot of `x` versus `y`. If `C` is `None`\n", " (the default), this is a histogram of the number of occurrences\n", " of the observations at ``(x[i], y[i])``.\n", "\n", " If `C` is specified, specifies values at given coordinates\n", " ``(x[i], y[i])``. These values are accumulated for each hexagonal\n", " bin and then reduced according to `reduce_C_function`,\n", " having as default the NumPy's mean function (:meth:`numpy.mean`).\n", " (If `C` is specified, it must also be a 1-D sequence\n", " of the same length as `x` and `y`, or a column label.)\n", "\n", " Parameters\n", " ----------\n", " x : int or str\n", " The column label or position for x points.\n", " y : int or str\n", " The column label or position for y points.\n", " C : int or str, optional\n", " The column label or position for the value of `(x, y)` point.\n", " reduce_C_function : callable, default `np.mean`\n", " Function of one argument that reduces all the values in a bin to\n", " a single number (e.g. `np.mean`, `np.max`, `np.sum`, `np.std`).\n", " gridsize : int or tuple of (int, int), default 100\n", " The number of hexagons in the x-direction.\n", " The corresponding number of hexagons in the y-direction is\n", " chosen in a way that the hexagons are approximately regular.\n", " Alternatively, gridsize can be a tuple with two elements\n", " specifying the number of hexagons in the x-direction and the\n", " y-direction.\n", " **kwargs\n", " Additional keyword arguments are documented in\n", " :meth:`DataFrame.plot`.\n", "\n", " Returns\n", " -------\n", " matplotlib.AxesSubplot\n", " The matplotlib ``Axes`` on which the hexbin is plotted.\n", "\n", " See Also\n", " --------\n", " DataFrame.plot : Make plots of a DataFrame.\n", " matplotlib.pyplot.hexbin : Hexagonal binning plot using matplotlib,\n", " the matplotlib function that is used under the hood.\n", "\n", " Examples\n", " --------\n", " The following examples are generated with random data from\n", " a normal distribution.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> n = 10000\n", " >>> df = pd.DataFrame({'x': np.random.randn(n),\n", " ... 'y': np.random.randn(n)})\n", " >>> ax = df.plot.hexbin(x='x', y='y', gridsize=20)\n", "\n", " The next example uses `C` and `np.sum` as `reduce_C_function`.\n", " Note that `'observations'` values ranges from 1 to 5 but the result\n", " plot shows values up to more than 25. This is because of the\n", " `reduce_C_function`.\n", "\n", " .. plot::\n", " :context: close-figs\n", "\n", " >>> n = 500\n", " >>> df = pd.DataFrame({\n", " ... 'coord_x': np.random.uniform(-3, 3, size=n),\n", " ... 'coord_y': np.random.uniform(30, 50, size=n),\n", " ... 'observations': np.random.randint(1,5, size=n)\n", " ... })\n", " >>> ax = df.plot.hexbin(x='coord_x',\n", " ... y='coord_y',\n", " ... C='observations',\n", " ... reduce_C_function=np.sum,\n", " ... gridsize=10,\n", " ... cmap=\"viridis\")\n", " \"\"\"\n", " if reduce_C_function is not None:\n", " kwargs[\"reduce_C_function\"] = reduce_C_function\n", " if gridsize is not None:\n", " kwargs[\"gridsize\"] = gridsize\n", "\n", " return self(kind=\"hexbin\", x=x, y=y, C=C, **kwargs)\n", "\n" ] } ], "source": [ "psource(Cdf.plot)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "def decorate_dice(title):\n", " \"\"\"Labels the axes.\n", " \n", " title: string\n", " \"\"\"\n", " plt.xlabel('Outcome')\n", " plt.ylabel('CDF')\n", " plt.title(title)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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iRMnzI4oIg5K5UZE6sTEiRNxdXXl66+/5tJLL6V9+/Zce+21fPvttxw5coSnnnoKAIvFwqpVq6qs26JFC959912Ayl//Dg8Px2KxcNlll1WOW7RoEb1798bNzY02bdoQExNT+dihQ4cYPnw4zZs3x9vbm5EjR5KRkVH5+LPPPktYWBiLFi2iffv2NG/enAcffBCbzcY//vEPAgMD8ff358UXX6ySLScnh7vvvhs/Pz+8vb254oor2LJlSy3uORG5UCo3IlLrTpw4wdq1a3nwwQfx8PCo8lhgYCC33347y5Ytozo/bbdp0yYAvv32W44dO8bKlSsB+Oc//8nEiRO59957SU5O5rPPPqNLly4A2O12hg8fzokTJ/jxxx/55ptv2LdvH6NGjary3Hv37uWrr75izZo1LFmyhHfeeYfrr7+ew4cP8+OPP/LKK6/w9NNP88svv1Suc9ttt5GZmclXX33F5s2biYiI4Morr9SZKJEGxNnsACLieFJTUzEMg549e5728Z49e3Ly5EmysrLO+Vx+fn4AtG7dmsDAwMrlL7zwAo8++iiTJ0+uXDZw4EAA4uPjSU5OZv/+/QQHBwPw3nvv0bt3b3799dfKcXa7nUWLFuHl5UWvXr24/PLLSUlJYfXq1VitVrp3784rr7zC999/T2RkJOvXr2fTpk1kZmbi5uYGwGuvvcaqVatYsWIF995773nsLRGpbSo3IlJnqnNm5nxkZmZy9OhRrrzyytM+vnPnToKDgyuLDUCvXr1o0aIFO3furCw3ISEheHl5VY4JCAjAyckJq9VaZVlmZiYAW7ZsoaCggNatW1d5veLiYvbu3Vtr2yciF0blRkRqXZcuXbBYLOzcuZObbrrplMd37txJy5Yt8fPzw2KxnFKCysvLz/r8f57qOl8uLi5V7lssltMus9vtABQUFNCmTRt++OGHU56rRYsWtZJJRC6crrkRkVrXunVrrrrqKt58802Ki4urPJaens6HH37IqFGjsFgs+Pn5cezYscrHU1NTKSoqqrzv6uoKgM1mq1zm5eVFSEgI8fHxp339nj17kpaWRlpaWuWyHTt2kJOTQ69evc57uyIiIkhPT8fZ2ZkuXbpUufn6+p7384pI7VK5EZE6MW/ePEpLSxk6dCjr1q0jLS2NNWvWcNVVVxEUFFT5KaQrrriCefPmkZiYyG+//cb9999f5eyJv78/Hh4erFmzhoyMDHJzc4HfP+30+uuvM2fOHFJTU0lISGDu3LkAREdH07dvX26//XYSEhLYtGkT48aN49JLL2XAgAHnvU3R0dFERUUxYsQIvv76aw4cOMCGDRt46qmn+O233y5gb4lIbVK5EZE60bVrV3777Tc6derEyJEj6dy5M/feey+XX345GzdupFWrVgC8/vrrBAcHM2TIEMaOHctjjz2Gp6dn5fM4OzszZ84cFi5cSNu2bRk+fDgA48ePZ9asWbz55pv07t2bG264gdTUVOD3qaRPP/2Uli1bcskllxAdHU2nTp1YtmzZBW2TxWJh9erVXHLJJUyYMIFu3boxevRoDh48SEBAwAU9t4jUHotRV1f8iYiIiJhAZ25ERETEoajciIiIiENRuRERERGHonIjIiIiDkXlRkRERByKyo2IiIg4FJUbERERcSgqNyIiIuJQVG5ERETEoajciIiIiENRuRERERGHonIjIiIiDuX/ARvOupKD4uUxAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "d4.plot()\n", "decorate_dice('One die')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Cdf` also provides `step`, which plots the Cdf as a step function." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def step(self, **options):\n", " \"\"\"Plot the Cdf as a step function.\n", "\n", " Args:\n", " options: passed to pd.Series.plot\n", " \"\"\"\n", " underride(options, drawstyle=\"steps-post\")\n", " self.plot(**options)\n", "\n" ] } ], "source": [ "psource(Cdf.step)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAweklEQVR4nO3df1RVdb7/8dfhKL9S8Dcokfg7sRSF9OKMPyqMm+Zod33TylGjtCxdS+NWV9IgrWSa0myK0imZZmpuOXnNuleDjFLHkaJAkvJH/kLJ5FcmR9FAOfv7R6szQwKCARs/PB9r7T/OZ38+e7/3Z+3FebH3Puc4LMuyBAAAYAgvuwsAAABoTIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAkPT444/L4XBUawsLC9Ndd91lT0EALhnhBkCT+eqrr/Tb3/5WISEh8vHxUY8ePTRt2jR99dVXdpcGwGBt7C4AgJnWr1+vO+64Q506ddI999yjXr16KT8/X2vWrNG6dev01ltv6dZbb7W7zDrt27dPXl78Dwhcbgg3ABrdwYMHNX36dPXu3Vvbtm1T165dPevmz5+vUaNGafr06dq1a5d69+5tY6V18/HxsbsEAJeAf0kANLpnnnlGZ86c0R//+MdqwUaSunTpotWrV6u8vFy///3vPe0/PfNy4MAB3XXXXerQoYMCAwMVFxenM2fOXLCPN954Q5GRkfLz81OnTp10++23q6CgoF71bd++Xdddd518fX3Vp08frV69usZ+NT1zc/LkSS1YsEChoaHy8fFR37599fTTT8vtdtdr3wCaHlduADS6//3f/1VYWJhGjRpV4/rRo0crLCxMGzduvGDdlClT1KtXLyUnJysnJ0evvvqqunXrpqefftrT56mnntJjjz2mKVOmaNasWSopKdELL7yg0aNHa+fOnerQoUOtteXl5emmm25S165d9fjjj+v8+fNKSkpSUFDQRY/rzJkzGjNmjI4dO6b77rtPV111lXbs2KGEhAQdP35cK1euvOg2ADQDCwAa0cmTJy1J1qRJk+rs95vf/MaSZLlcLsuyLCspKcmSZN19993V+t16661W586dPa/z8/Mtp9NpPfXUU9X65eXlWW3atLmg/ecmT55s+fr6WkeOHPG07d6923I6ndbP/yT27NnTmjlzpuf1E088YV1xxRXW119/Xa3fwoULLafTaR09erTOfQNoHtyWAtCoTp06JUlq3759nf1+Wu9yuaq1z5kzp9rrUaNG6bvvvvP0W79+vdxut6ZMmaLS0lLPEhwcrH79+unjjz+udZ9VVVVKT0/X5MmTddVVV3naBw4cqNjY2Ise29tvv61Ro0apY8eO1fYdExOjqqoqbdu27aLbAND0uC0FoFH9FFp+Cjm1qS0E/WvokKSOHTtKkr7//nsFBARo//79sixL/fr1q3G7bdu2rXWfJSUlOnv2bI1jBwwYoE2bNtVZ8/79+7Vr164LniP6SXFxcZ3jATQPwg2ARhUYGKju3btr165ddfbbtWuXQkJCFBAQUK3d6XTW2N+yLEmS2+2Ww+HQ+++/X2Pfdu3aXWLlF+d2uzVu3Dg98sgjNa7v379/k+0bQP0RbgA0ultuuUWvvPKKtm/frl//+tcXrP/73/+u/Px83XfffQ3edp8+fWRZlnr16tXgMNG1a1f5+flp//79F6zbt29fvfZ9+vRpxcTENGi/AJoXz9wAaHQPP/yw/Pz8dN999+m7776rtu7EiROaM2eO/P399fDDDzd42//xH/8hp9OpJUuWeK7m/MSyrAv296+cTqdiY2O1YcMGHT161NO+Z88epaenX3TfU6ZMUWZmZo19T548qfPnzzfgSAA0Fa7cAGh0/fr105///GdNmzZN11577QXfUFxaWqo333xTffr0afC2+/TpoyeffFIJCQnKz8/X5MmT1b59ex0+fFjvvPOO7r33Xj300EO1jl+yZInS0tI0atQoPfDAAzp//rxeeOEFDRo06KK30h5++GG99957uuWWW3TXXXcpMjJS5eXlysvL07p165Sfn68uXbo0+JgANC7CDYAmcdttt+nqq69WcnKyJ9B07txZ119/vR599FFdc801l7zthQsXqn///nruuee0ZMkSSVJoaKhuuukm/eY3v6lz7ODBg5Wenq74+HglJibqyiuv1JIlS3T8+PGLhht/f39t3bpVy5Yt09tvv62//OUvCggIUP/+/bVkyRIFBgZe8jEBaDwO6+fXdQEAAC5jPHMDAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGCUVvc9N263W99++63at28vh8NhdzkAAKAeLMvSqVOn1KNHD3l51X1tptWFm2+//VahoaF2lwEAAC5BQUGBrrzyyjr7tLpw0759e0k/Ts7Pf40YAAC0TC6XS6GhoZ738bq0unDz062ogIAAwg0AAJeZ+jxSwgPFAADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGAUW8PNtm3bNHHiRPXo0UMOh0MbNmy46JgtW7Zo2LBh8vHxUd++ffXaa681eZ0AAODyYWu4KS8v15AhQ5SSklKv/ocPH9aECRN0/fXXKzc3VwsWLNCsWbOUnp7exJUCAIDLha0/nHnzzTfr5ptvrnf/VatWqVevXlq+fLkkaeDAgdq+fbuee+45xcbGNlWZAACgHizL0tlzVZIkv7bOev3IZVO4rJ65yczMVExMTLW22NhYZWZm1jqmoqJCLper2gIAABrf2XNVCk9MV3hiuifk2OGyCjeFhYUKCgqq1hYUFCSXy6WzZ8/WOCY5OVmBgYGeJTQ0tDlKBQAANrmsws2lSEhIUFlZmWcpKCiwuyQAANCEbH3mpqGCg4NVVFRUra2oqEgBAQHy8/OrcYyPj498fHyaozwAANACXFZXbqKjo5WRkVGtbfPmzYqOjrapIgAA0NLYGm5Onz6t3Nxc5ebmSvrxo965ubk6evSopB9vKc2YMcPTf86cOTp06JAeeeQR7d27Vy+99JL+9re/6cEHH7SjfAAA0ALZGm4+//xzDR06VEOHDpUkxcfHa+jQoUpMTJQkHT9+3BN0JKlXr17auHGjNm/erCFDhmj58uV69dVX+Rg4AADwsPWZm7Fjx8qyrFrX1/Ttw2PHjtXOnTubsCoAAHA5u6yeuQEAALgYwg0AADAK4QYAABiFcAMAAIxCuAEAAEYh3AAAAKMQbgAAgFEINwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGAUwg0AADAK4QYAABiFcAMAAIxCuAEAAEYh3AAAAKMQbgAAgFEINwAAwCiEGwAAYBTbw01KSorCwsLk6+urESNGKCsrq9a+586d09KlS9WnTx/5+vpqyJAhSktLa8ZqAQBAS2druFm7dq3i4+OVlJSknJwcDRkyRLGxsSouLq6x/+LFi7V69Wq98MIL2r17t+bMmaNbb71VO3fubObKAQBAS2VruFmxYoVmz56tuLg4hYeHa9WqVfL391dqamqN/V9//XU9+uijGj9+vHr37q37779f48eP1/Lly5u5cgAA0FLZFm4qKyuVnZ2tmJiYfxbj5aWYmBhlZmbWOKaiokK+vr7V2vz8/LR9+/YmrRUAAFw+bAs3paWlqqqqUlBQULX2oKAgFRYW1jgmNjZWK1as0P79++V2u7V582atX79ex48fr3U/FRUVcrlc1RYAAGAu2x8obojnn39e/fr109VXXy1vb2/NmzdPcXFx8vKq/TCSk5MVGBjoWUJDQ5uxYgAA0NxsCzddunSR0+lUUVFRtfaioiIFBwfXOKZr167asGGDysvLdeTIEe3du1ft2rVT7969a91PQkKCysrKPEtBQUGjHgcAAGhZbAs33t7eioyMVEZGhqfN7XYrIyND0dHRdY719fVVSEiIzp8/r//5n//RpEmTau3r4+OjgICAagsAADBXGzt3Hh8fr5kzZyoqKkrDhw/XypUrVV5erri4OEnSjBkzFBISouTkZEnSp59+qmPHjikiIkLHjh3T448/LrfbrUceecTOwwAAAC2IreFm6tSpKikpUWJiogoLCxUREaG0tDTPQ8ZHjx6t9jzNDz/8oMWLF+vQoUNq166dxo8fr9dff10dOnSw6QgAAEBL47Asy7K7iObkcrkUGBiosrIyblEBANCIzlSeV3hiuiRp99JY+Xs33jWUhrx/X1aflgIAALgYwg0AADAK4QYAABiFcAMAAIxCuAEAAEYh3AAAAKMQbgAAgFEINwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGAUwg0AADAK4QYAABiFcAMAAIxCuAEAAEYh3AAAAKMQbgAAgFEINwAAwCiEGwAAYBTCDQAAMIrt4SYlJUVhYWHy9fXViBEjlJWVVWf/lStXasCAAfLz81NoaKgefPBB/fDDD81ULQAAaOlsDTdr165VfHy8kpKSlJOToyFDhig2NlbFxcU19v/v//5vLVy4UElJSdqzZ4/WrFmjtWvX6tFHH23mygEAQEtla7hZsWKFZs+erbi4OIWHh2vVqlXy9/dXampqjf137NihX/3qV7rzzjsVFhamm266SXfcccdFr/YAAIDWw7ZwU1lZqezsbMXExPyzGC8vxcTEKDMzs8YxI0eOVHZ2tifMHDp0SJs2bdL48eObpWYAANDytbFrx6WlpaqqqlJQUFC19qCgIO3du7fGMXfeeadKS0v161//WpZl6fz585ozZ06dt6UqKipUUVHhee1yuRrnAAAAQItk+wPFDbFlyxYtW7ZML730knJycrR+/Xpt3LhRTzzxRK1jkpOTFRgY6FlCQ0ObsWIAANDcbLty06VLFzmdThUVFVVrLyoqUnBwcI1jHnvsMU2fPl2zZs2SJF177bUqLy/Xvffeq0WLFsnL68KslpCQoPj4eM9rl8tFwAEAwGC2Xbnx9vZWZGSkMjIyPG1ut1sZGRmKjo6uccyZM2cuCDBOp1OSZFlWjWN8fHwUEBBQbQEAAOay7cqNJMXHx2vmzJmKiorS8OHDtXLlSpWXlysuLk6SNGPGDIWEhCg5OVmSNHHiRK1YsUJDhw7ViBEjdODAAT322GOaOHGiJ+QAAIDWzdZwM3XqVJWUlCgxMVGFhYWKiIhQWlqa5yHjo0ePVrtSs3jxYjkcDi1evFjHjh1T165dNXHiRD311FN2HQIAAGhhHFZt93MM5XK5FBgYqLKyMm5RAQDQiM5Unld4YrokaffSWPl7N941lIa8f19Wn5YCAAC4GMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGAUwg0AADAK4QYAABiFcAMAAIxCuAEAAEYh3AAAAKM03m+RAwAuG5Zl6ey5KrvLgGHOVLaMc4pwAwCtjGVZ+n+rMpV95Hu7SwGaBLelAKCVOXuuimCDJhXVs6P82jpt2z9XbgCgFft8cYz8ve17E4KZ/No65XA4bNs/4QYAWjF/b6f8vXkrgFm4LQUAAIxCuAEAAEYh3AAAAKMQbgAAgFEINwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwSosINykpKQoLC5Ovr69GjBihrKysWvuOHTtWDofjgmXChAnNWDEAAGipbA83a9euVXx8vJKSkpSTk6MhQ4YoNjZWxcXFNfZfv369jh8/7lm+/PJLOZ1O3Xbbbc1cOQAAaIlsDzcrVqzQ7NmzFRcXp/DwcK1atUr+/v5KTU2tsX+nTp0UHBzsWTZv3ix/f3/CDQAAkGRzuKmsrFR2drZiYmI8bV5eXoqJiVFmZma9trFmzRrdfvvtuuKKK2pcX1FRIZfLVW0BAADmsjXclJaWqqqqSkFBQdXag4KCVFhYeNHxWVlZ+vLLLzVr1qxa+yQnJyswMNCzhIaG/uK6AQBAy2X7balfYs2aNbr22ms1fPjwWvskJCSorKzMsxQUFDRjhQAAoLm1sXPnXbp0kdPpVFFRUbX2oqIiBQcH1zm2vLxcb731lpYuXVpnPx8fH/n4+PziWgEAwOXB1is33t7eioyMVEZGhqfN7XYrIyND0dHRdY59++23VVFRod/+9rdNXSYAALiM2HrlRpLi4+M1c+ZMRUVFafjw4Vq5cqXKy8sVFxcnSZoxY4ZCQkKUnJxcbdyaNWs0efJkde7c2Y6yAQBAC2V7uJk6dapKSkqUmJiowsJCRUREKC0tzfOQ8dGjR+XlVf0C0759+7R9+3Z98MEHdpQMAABaMIdlWZbdRTQnl8ulwMBAlZWVKSAgwO5yAKDZnak8r/DEdEnS7qWx8ve2/f9c4KIa8v59WX9aCgAA4OcINwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGaVC4mTFjhk6dOuV5/cUXX+jcuXONXhQAAMClalC4+etf/6qzZ896Xo8aNUoFBQWNXhQAAMClalC4sSyrztcAAAB245kbAABglDYNHbB7924VFhZK+vHKzd69e3X69OlqfQYPHtw41QEAADRQg8PNjTfeWO121C233CJJcjgcsixLDodDVVVVjVchAABAAzQo3Bw+fLip6gAAAGgUDQo3PXv2bKo6AAAAGkWDb0tJ0v79+/Xuu+8qPz9fDodDvXr10uTJk9W7d+/Grg8AAKBBGhxukpOTlZiYKLfbrW7dusmyLJWUlGjhwoVatmyZHnrooaaoEwAAoF4a9FHwjz/+WIsXL9aiRYtUWlqq48ePq7Cw0BNuFi5cqG3btjVVrQAAABfVoCs3q1at0qxZs/T4449Xa+/UqZOWLl2qwsJCvfzyyxo9enRj1ggAAFBvDbpyk5WVpenTp9e6fvr06frkk09+cVEAAACXqkHhpqioSGFhYbWu79Wrl+cL/gAAAOzQoHDzww8/yNvbu9b1bdu2VWVl5S8uCgAA4FI1+NNSr776qtq1a1fjulOnTv3iggAAAH6JBoWbq666Sq+88spF+wAAANilQeEmPz+/icoAAABoHA165uajjz5SeHi4XC7XBevKyso0aNAg/f3vf2+04gAAABqqQeFm5cqVmj17tgICAi5YFxgYqPvuu08rVqxoUAEpKSkKCwuTr6+vRowYoaysrDr7nzx5UnPnzlX37t3l4+Oj/v37a9OmTQ3aJwAAMFeDws0XX3yhf//3f691/U033aTs7Ox6b2/t2rWKj49XUlKScnJyNGTIEMXGxqq4uLjG/pWVlRo3bpzy8/O1bt067du3T6+88opCQkIachgAAMBgDXrmpqioSG3btq19Y23aqKSkpN7bW7FihWbPnq24uDhJP34D8saNG5WamqqFCxde0D81NVUnTpzQjh07PHXU9b07AACg9WnQlZuQkBB9+eWXta7ftWuXunfvXq9tVVZWKjs7WzExMf8sxstLMTExyszMrHHMe++9p+joaM2dO1dBQUG65pprtGzZMlVVVdW6n4qKCrlcrmoLAAAwV4PCzfjx4/XYY4/phx9+uGDd2bNnlZSUpFtuuaVe2yotLVVVVZWCgoKqtQcFBdX6LceHDh3SunXrVFVVpU2bNumxxx7T8uXL9eSTT9a6n+TkZAUGBnqW0NDQetUHAAAuTw26LbV48WKtX79e/fv317x58zRgwABJ0t69e5WSkqKqqiotWrSoSQqVJLfbrW7duumPf/yjnE6nIiMjdezYMT3zzDNKSkqqcUxCQoLi4+M9r10uFwEHAACDNSjcBAUFaceOHbr//vuVkJAgy7IkSQ6HQ7GxsUpJSbngSkxtunTpIqfTqaKiomrtRUVFCg4OrnFM9+7d1bZtWzmdTk/bwIEDVVhYqMrKyhp/GsLHx0c+Pj71PUQAAHCZa9BtKUnq2bOnNm3apNLSUn366af65JNPVFpaqk2bNqlXr1713o63t7ciIyOVkZHhaXO73crIyFB0dHSNY371q1/pwIEDcrvdnravv/5a3bt3r/M3rwAAQOvR4HDzk44dO+q6667T8OHD1bFjx0vaRnx8vF555RX9+c9/1p49e3T//fervLzc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63/84x9WmzZtrGeffdbas2ePlZSUZLVt29bKy8uz4xCazaXM1ZIlS6z09HTr4MGDVnZ2tnX77bdbvr6+1ldffWXHITSrhQsXWlu3brUOHz5s7dq1y1q4cKHlcDisDz74wLIszqt/1dC5as3n1c/9/NNSLeW8ItzU008fVf75MnPmTMuyLGvmzJnWmDFjLhgTERFheXt7W71797b+9Kc/NXvddmnofD399NNWnz59LF9fX6tTp07W2LFjrY8++sie4ptRTXMkqdq5MmbMGM+8/eRvf/ub1b9/f8vb29saNGiQtXHjxuYt3AaXMlcLFiywrrrqKsvb29sKCgqyxo8fb+Xk5DR/8Ta4++67rZ49e1re3t5W165drRtvvNHzZm1ZnFf/qqFz1ZrPq5/7ebhpKeeVw7Isq2mvDQEAADQfnrkBAABGIdwAAACjEG4AAIBRCDcAAMAohBsAAGAUwg0AADAK4QYAABiFcAMAAIxCuAHQZAoKCnT33XerR48e8vb2Vs+ePTV//nx999139d5Gfn6+HA6HcnNzm65QAEYh3ABoEocOHVJUVJT279+vN998UwcOHNCqVauUkZGh6OhonThxwu4SARiKcAOgScydO1fe3t764IMPNGbMGF111VW6+eab9eGHH+rYsWNatGiRJMnhcGjDhg3Vxnbo0EGvvfaaJHl+/Xvo0KFyOBwaO3asp19qaqoGDRokHx8fde/eXfPmzfOsO3r0qCZNmqR27dopICBAU6ZMUVFRkWf9448/roiICKWmpuqqq65Su3bt9MADD6iqqkq///3vFRwcrG7duumpp56qVtvJkyc1a9Ysde3aVQEBAbrhhhv0xRdfNOLMAfilCDcAGt2JEyeUnp6uBx54QH5+ftXWBQcHa9q0aVq7dq3q89N2WVlZkqQPP/xQx48f1/r16yVJL7/8subOnat7771XeXl5eu+999S3b19Jktvt1qRJk3TixAlt3bpVmzdv1qFDhzR16tRq2z548KDef/99paWl6c0339SaNWs0YcIEffPNN9q6dauefvppLV68WJ9++qlnzG233abi4mK9//77ys7O1rBhw3TjjTdyJQpoQdrYXQAA8+zfv1+WZWngwIE1rh84cKC+//57lZSUXHRbXbt2lSR17txZwcHBnvYnn3xS//mf/6n58+d72q677jpJUkZGhvLy8nT48GGFhoZKkv7yl79o0KBB+uyzzzz93G63UlNT1b59e4WHh+v666/Xvn37tGnTJnl5eWnAgAF6+umn9fHHH2vEiBHavn27srKyVFxcLB8fH0nSs88+qw0bNmjdunW69957L2G2ADQ2wg2AJlOfKzOXori4WN9++61uvPHGGtfv2bNHoaGhnmAjSeHh4erQoYP27NnjCTdhYWFq3769p09QUJCcTqe8vLyqtRUXF0uSvvjiC50+fVqdO3eutr+zZ8/q4MGDjXZ8AH4Zwg2ARte3b185HA7t2bNHt9566wXr9+zZo44dO6pr165yOBwXhKBz587Vuf2f3+q6VG3btq322uFw1NjmdrslSadPn1b37t21ZcuWC7bVoUOHRqkJwC/HMzcAGl3nzp01btw4vfTSSzp79my1dYWFhfrrX/+qqVOnyuFwqGvXrjp+/Lhn/f79+3XmzBnPa29vb0lSVVWVp619+/YKCwtTRkZGjfsfOHCgCgoKVFBQ4GnbvXu3Tp48qfDw8Es+rmHDhqmwsFBt2rRR3759qy1dunS55O0CaFyEGwBN4sUXX1RFRYViY2O1bds2FRQUKC0tTePGjVNISIjnU0g33HCDXnzxRe3cuVOff/655syZU+3qSbdu3eTn56e0tDQVFRWprKxM0o+fdlq+fLn+8Ic/aP/+/crJydELL7wgSYqJidG1116radOmKScnR1lZWZoxY4bGjBmjqKioSz6mmJgYRUdHa/Lkyfrggw+Un5+vHTt2aNGiRfr8889/wWwBaEyEGwBNol+/fvr888/Vu3dvTZkyRX369NG9996r66+/XpmZmerUqZMkafny5QoNDdWoUaN055136qGHHpK/v79nO23atNEf/vAHrV69Wj169NCkSZMkSTNnztTKlSv10ksvadCgQbrlllu0f/9+ST/eSnr33XfVsWNHjR49WjExMerdu7fWrl37i47J4XBo06ZNGj16tOLi4tS/f3/dfvvtOnLkiIKCgn7RtgE0HofVVE/8AQAA2IArNwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwCuEGAAAY5f8Dh24RSg6KuDYAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "d4.step()\n", "decorate_dice('One die')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Make Cdf from sequence\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/14).\n", "\n", "The following function makes a `Cdf` object from a sequence of values." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " @staticmethod\n", " def from_seq(seq, normalize=True, sort=True, **options):\n", " \"\"\"Make a CDF from a sequence of values.\n", "\n", " Args:\n", " seq: iterable\n", " normalize: whether to normalize the Cdf, default True\n", " sort: whether to sort the Cdf by values, default True\n", " options: passed to the pd.Series constructor\n", "\n", " Returns: CDF object\n", " \"\"\"\n", " # if normalize==True, normalize AFTER making the Cdf\n", " # so the last element is exactly 1.0\n", " pmf = Pmf.from_seq(seq, normalize=False, sort=sort, **options)\n", " return pmf.make_cdf(normalize=normalize)\n", "\n" ] } ], "source": [ "psource(Cdf.from_seq)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
a0.2
e0.4
l0.8
n1.0
\n", "
" ], "text/plain": [ "a 0.2\n", "e 0.4\n", "l 0.8\n", "n 1.0\n", "Name: , dtype: float64" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cdf = Cdf.from_seq(list('allen'))\n", "cdf" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.2
20.6
30.8
51.0
\n", "
" ], "text/plain": [ "1 0.2\n", "2 0.6\n", "3 0.8\n", "5 1.0\n", "Name: , dtype: float64" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cdf = Cdf.from_seq(np.array([1, 2, 2, 3, 5]))\n", "cdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Selection\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/15).\n", "\n", "`Cdf` inherits [] from Series, so you can look up a quantile and get its cumulative probability." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.25" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4[1]" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4[4]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Cdf` objects are mutable, but in general the result is not a valid Cdf." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.25
20.50
30.75
41.00
51.25
\n", "
" ], "text/plain": [ "1 0.25\n", "2 0.50\n", "3 0.75\n", "4 1.00\n", "5 1.25\n", "dtype: float64" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4[5] = 1.25\n", "d4" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.2
20.4
30.6
40.8
51.0
\n", "
" ], "text/plain": [ "1 0.2\n", "2 0.4\n", "3 0.6\n", "4 0.8\n", "5 1.0\n", "dtype: float64" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.normalize()\n", "d4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Evaluating CDFs\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/16).\n", "\n", "Evaluating a `Cdf` forward maps from a quantity to its cumulative probability." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "d6 = Cdf.from_seq([1,2,3,4,5,6])" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(0.5)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.forward(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`forward` interpolates, so it works for quantities that are not in the distribution." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(0.5)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.forward(3.5)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(0.)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.forward(0)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(1.)" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.forward(7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`__call__` is a synonym for `forward`, so you can call the `Cdf` like a function (which it is)." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(0.16666667)" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6(1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`forward` can take an array of quantities, too." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "def decorate_cdf(title):\n", " \"\"\"Labels the axes.\n", " \n", " title: string\n", " \"\"\"\n", " plt.xlabel('Quantity')\n", " plt.ylabel('CDF')\n", " plt.title(title)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+fklEQVR4nO3deXhU5d3/8c9kmUlCNiA7BMIqmxAFQUAEJRoRsVytiCsIihs8BfPwq1KBgG0J7VMRrCyiAj5WCy6VulAQEBSFPigIShFI2ItkY0lCgARmzu8PmMExATPZzknyfl3XXJdzcs7MdwKST+77/p7bZhiGIQAAgHrCz+wCAAAAqhPhBgAA1CuEGwAAUK8QbgAAQL1CuAEAAPUK4QYAANQrhBsAAFCvEG4AAEC9QrgBAAD1CuEGgKWsX79eNptN69evN7uUch04cEA2m01Lliwx5f2XLFkim82mAwcOmPL+QF1AuAEsyv1DrLzHM888Y3Z5qGEzZszQ8uXLzS4DqJMCzC4AwJU999xzatWqldexLl26mFQNasuMGTN01113aejQoV7HH3zwQd1zzz1yOBzmFAbUAYQbwOIGDRqkHj16VPvrFhcXq1GjRtX+uj/HMAydPXtWwcHBtf7e9YG/v7/8/f3NLgOwNKalgDru008/Vb9+/dSoUSNFRkbqF7/4hb7//nuvc6ZNmyabzaadO3fqvvvuU+PGjXXDDTfogw8+kM1m07fffus597333pPNZtMvf/lLr9fo2LGjhg8f7nm+ePFi3XzzzYqJiZHD4VCnTp00f/78MvUlJSXpjjvu0KpVq9SjRw8FBwfr5ZdfliT95z//0dChQ9WoUSPFxMToqaeeUklJSYU/+5EjRzR69GjFxsbK4XCoc+fOWrRokefrOTk5CggI0PTp08tcu3v3btlsNr300kuSpOPHj2vixIm6+uqrFRoaqvDwcA0aNEjbt2//2ToGDBigAQMGlDn+0EMPKSkpyevYn//8Z/Xp00dNmzZVcHCwunfvrnfffdfrHJvNpuLiYr3++uueqciHHnpI0uXX3MybN0+dO3eWw+FQQkKCxo4dq5MnT5aps0uXLtq5c6duuukmhYSEqFmzZvrTn/70s58RqEsYuQEsrqCgQPn5+V7HoqKiJElr1qzRoEGD1Lp1a02bNk1nzpzRX/7yF/Xt21dbt24t84N12LBhateunWbMmCHDMHTDDTfIZrPp888/V9euXSVJGzZskJ+fn7744gvPdXl5edq1a5fGjRvnOTZ//nx17txZd955pwICAvThhx/qySeflMvl0tixY73ed/fu3br33nv12GOPacyYMbrqqqt05swZDRw4UIcOHdKvf/1rJSQk6I033tCnn35aoe9LTk6Orr/+etlsNo0bN07R0dH65z//qYcffliFhYWaMGGCYmNj1b9/f7399ttKT0/3un7ZsmXy9/fXsGHDJEn79u3T8uXLNWzYMLVq1Uo5OTl6+eWX1b9/f+3cuVMJCQkVquvnzJkzR3feeafuv/9+lZaWaunSpRo2bJg++ugjDR48WJL0xhtv6JFHHlHPnj316KOPSpLatGlz2decNm2apk+frpSUFD3xxBPavXu35s+fr6+++kpffvmlAgMDPeeeOHFCt912m375y1/q7rvv1rvvvqunn35aV199tQYNGlQtnxEwnQHAkhYvXmxIKvfhlpycbMTExBjHjh3zHNu+fbvh5+dnjBgxwnMsPT3dkGTce++9Zd6nc+fOxt133+15fu211xrDhg0zJBnff/+9YRiG8fe//92QZGzfvt1z3unTp8u8VmpqqtG6dWuvYy1btjQkGStXrvQ6Pnv2bEOS8fbbb3uOFRcXG23btjUkGevWrbvi9+fhhx824uPjjfz8fK/j99xzjxEREeGp7+WXXzYkGd99953XeZ06dTJuvvlmz/OzZ88aTqfT65z9+/cbDofDeO6557yOSTIWL17sOda/f3+jf//+ZWocOXKk0bJlS69jP/2+lZaWGl26dPGqxTAMo1GjRsbIkSPLvKb778X+/fsNwzCM3Nxcw263G7feeqtX/S+99JIhyVi0aJFXnZKM//3f//UcKykpMeLi4oxf/epXZd4LqKuYlgIsbu7cuVq9erXXQ5KOHj2qbdu26aGHHlKTJk0853ft2lW33HKLVqxYUea1Hn/88TLH+vXrpw0bNkiSioqKtH37dj366KOKioryHN+wYYMiIyO9FjL/eM2Me3Spf//+2rdvnwoKCrzeo1WrVkpNTfU6tmLFCsXHx+uuu+7yHAsJCfGMVFyJYRh67733NGTIEBmGofz8fM8jNTVVBQUF2rp1qyTpl7/8pQICArRs2TLP9Tt27NDOnTu9ptkcDof8/C78k+h0OnXs2DGFhobqqquu8rxWdfjx9+3EiRMqKChQv379Kv0ea9asUWlpqSZMmOCpX5LGjBmj8PBwffzxx17nh4aG6oEHHvA8t9vt6tmzp/bt21ep9wesiHADWFzPnj2VkpLi9ZCkgwcPSpKuuuqqMtd07NhR+fn5Ki4u9jr+064r6UK4OXr0qLKysrRx40bZbDb17t3bK/Rs2LBBffv29frh+eWXXyolJcWz1ic6Olq//e1vJanccPNTBw8eVNu2bWWz2byOl/d5fiovL08nT57UwoULFR0d7fUYNWqUJCk3N1fShSm8gQMH6u233/Zcv2zZMgUEBHitK3K5XHrhhRfUrl07ORwORUVFKTo6Wt9++22Zz1MVH330ka6//noFBQWpSZMmio6O1vz58yv9Hpf7e2C329W6dWvP192aN29e5nveuHFjnThxolLvD1gRa26ABqS8DqUbbrhBkvT5559r3759uvbaa9WoUSP169dPL774ok6dOqVvvvlGf/jDHzzX7N27VwMHDlSHDh00a9YsJSYmym63a8WKFXrhhRfkcrl+9n2rwv36DzzwgEaOHFnuOe41RJJ0zz33aNSoUdq2bZuSk5P19ttva+DAgZ61S9KF1uspU6Zo9OjR+t3vfqcmTZrIz89PEyZMKPN5fspms8kwjDLHnU6n1/MNGzbozjvv1I033qh58+YpPj5egYGBWrx4sd56660Kf/6quFynVXn1A3UV4Qaoo1q2bCnpwmLdn9q1a5eioqIq1OrdokULtWjRQhs2bNC+ffvUr18/SdKNN96otLQ0vfPOO3I6nbrxxhs913z44YcqKSnRBx98oBYtWniOr1u3zqf6d+zYIcMwvEYSyvs8PxUdHa2wsDA5nU7PSNaVDB06VI899phnamrPnj2aNGmS1znvvvuubrrpJr322mtex0+ePOkVgsrTuHHjcqd1fjpq8t577ykoKEirVq3yuk/N4sWLy1z709GVy/nx34PWrVt7jpeWlmr//v0V+v4A9Q3TUkAdFR8fr+TkZL3++uteLb87duzQJ598ottvv73Cr9WvXz99+umn2rx5syfcJCcnKywsTDNnzvS0LLu5f/v/8W/7BQUF5f6Qvpzbb79dP/zwg1cb9OnTp7Vw4cKfvdbf31+/+tWv9N5772nHjh1lvp6Xl+f1PDIyUqmpqXr77be1dOlS2e32MjfH8/f3LzN68c477+jIkSM/W0+bNm20a9cur/fdvn27vvzyyzLvYbPZvEZ0Dhw4UO6diBs1alSmlbs8KSkpstvtevHFF73qf+2111RQUODpwAIaEkZugDrsf/7nfzRo0CD17t1bDz/8sKcVPCIiQtOmTavw6/Tr109vvvmmbDabZ5rK399fffr00apVqzRgwADZ7XbP+bfeeqvsdruGDBmixx57TKdOndIrr7yimJgYHT16tELvOWbMGL300ksaMWKEtmzZovj4eL3xxhsKCQmp0PUzZ87UunXr1KtXL40ZM0adOnXS8ePHtXXrVq1Zs0bHjx/3On/48OF64IEHNG/ePKWmpioyMtLr63fccYeee+45jRo1Sn369NF3332nN99802s05HJGjx6tWbNmKTU1VQ8//LByc3O1YMECde7cWYWFhZ7zBg8erFmzZum2227Tfffdp9zcXM2dO1dt27b1uteQJHXv3l1r1qzRrFmzlJCQoFatWqlXr15l3js6OlqTJk3S9OnTddttt+nOO+/U7t27NW/ePF133XVei4eBBsO8Ri0AV+Ju+f3qq6+ueN6aNWuMvn37GsHBwUZ4eLgxZMgQY+fOnV7nuFvB8/Lyyn2Nf//734Yko2PHjl7Hf//73xuSjClTppS55oMPPjC6du1qBAUFGUlJScYf//hHY9GiRV5tyoZxoRV88ODB5b7vwYMHjTvvvNMICQkxoqKijPHjxxsrV66sUCu4YRhGTk6OMXbsWCMxMdEIDAw04uLijIEDBxoLFy4sc25hYaERHBxsSDL++te/lvn62bNnjf/+7/824uPjjeDgYKNv377Gpk2byrR5l9cKbhiG8de//tVo3bq1YbfbjeTkZGPVqlXltoK/9tprRrt27QyHw2F06NDBWLx4sefP58d27dpl3HjjjZ6a3W3hP20Fd3vppZeMDh06GIGBgUZsbKzxxBNPGCdOnPA6p3///kbnzp3LfPby6gTqMpthsIoMAADUH6y5AQAA9QrhBgAA1CuEGwAAUK8QbgAAQL1CuAEAAPUK4QYAANQrDe4mfi6XSz/88IPCwsIqfHtzAABgLsMwVFRUpISEBK9NfMvT4MLNDz/8oMTERLPLAAAAlXD48GE1b978iuc0uHATFhYm6cI3Jzw83ORqAABARRQWFioxMdHzc/xKGly4cU9FhYeHE24AAKhjKrKkhAXFAACgXiHcAACA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Wv3hD39QRESE7Ha7QkJCFBcXV+572O12RUREyGazeZ0TGhqq1NRULV68WNddd50kafHixerfv79at25dofoB1A5GbgDUuJ8bmbHb7RV6nWXLlqlv376Ki4tTaGioJk+erEOHDnmdk5SU5Ak2khQfH6/c3Fzfiy7HmDFj9Le//U1nz55VaWmp3nrrLY0ePbpaXhtA9SHcAKgxbdu2lc1m0/fff1/u17///ntFR0crMjJSNputTAj68XqaTZs26f7779ftt9+ujz76SN98842effZZlZaWel0TGBjo9dxms8nlclXL5xkyZIgcDofef/99ffjhhzp37pzuuuuuanltANWHaSkANaZp06a65ZZbNG/ePD311FNe626ys7P15ptvauzYsZKk6OhoHT161PP1zMxMnT592vN848aNatmypWcBsiQdPHjQ55rsdrucTmelzgkICNDIkSO1ePFi2e123XPPPWXWEgEwHyM3AGrUSy+9pJKSEqWmpurzzz/X4cOHtXLlSt1yyy1q3769pk6dKkm6+eab9dJLL+mbb77R119/rccff9xrFKZdu3Y6dOiQli5dqr179+rFF1/U+++/73M9SUlJ+r//+z8dOHBA+fn55Y7qJCUl6dSpU1q7dq3y8/O9QtYjjzyiTz/9VCtXrmRKCrAowg2AGtWuXTt99dVXat26te6++261bNlSgwYNUvv27fXll18qNDRUkvT8888rMTFR/fr103333aeJEycqJCTE8zp33nmnnnrqKY0bN07JycnauHFjpVqwJ06cKH9/f3Xq1EnR0dFl1uxIFzqmHn/8cQ0fPlzR0dH605/+5PV5+vTpow4dOqhXr16V+I4AqGk2o6I9mABQTdLT0zVr1iytXr1a119/vdnl+MQwDLVr105PPvmk0tLSzC4HQDlYcwOg1k2fPl1JSUn617/+pZ49e8rPr24MIufl5Wnp0qXKzs7m3jaAhTFyAwAVZLPZFBUVpTlz5ui+++4zuxwAl8HIDQBUEL8LAnVD3RgLBgAAqCDCDQAAqFcINwAAoF4h3AAAgHqFcAMAAOoVwg0AAKhXCDcAAKBeIdwAAIB6hXADAADqlf8P7BN8y94xEAcAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "qs = np.linspace(0, 7)\n", "ps = d6(qs)\n", "plt.plot(qs, ps)\n", "decorate_cdf('Forward evaluation')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Cdf` also provides `inverse`, which computes the inverse `Cdf`:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(3.)" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.inverse(0.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`quantile` is a synonym for `inverse`" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(3.)" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.quantile(0.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`inverse` and `quantile` work with arrays " ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "image/png": "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e++9ys3N1U033aQrrrhCBw8e1HPPPafu3bv7j/e73/1Or7/+um6//XaNHj1aPXv2VHFxsT7//HOtWrVKBw4cUHx8fJWvHx0drfnz52vEiBG69tprNWzYMDVt2lSHDh3SW2+9pb59++r555/3j2/WrJluvPFGzZ49W0VFRZUCXceOHdWuXTtNnDhRR44cUXR0tP7nf/7noueh3HvvvXrmmWd07733qlevXvrwww+1Z8+eSuNuv/12LVmyRDExMercubM2bdqk9957T02aNAkY1717dwUHB2vmzJkqKCiQy+XSTTfdpGbNmlV6zfvuu08vvviiRo8erW3btik5OVmrVq3Sxx9/rDlz5igqKuqizgEwlo13agG4CBe6FTwiIqLS2PNvWS7n8/mspKQkS5L1hz/8ocrjuN1ua+bMmdbVV19tuVwuKy4uzurZs6f11FNPWQUFBf5xkqxx48ZV2n/VqlXWwIEDrWbNmllOp9Nq1aqVdf/991tHjx4NGFdUVGRNmjTJat++veV0Oq34+HirT58+1rPPPmu53e4ffT/Wr19vpaWlWTExMVZYWJjVrl07a/To0dbWrVsrjV24cKElyYqKirJOnTpVaftXX31lpaamWpGRkVZ8fLw1duxY69NPP610m3dV72tJSYl1zz33WDExMVZUVJQ1dOhQ69ixY5VuBc/Ly7PGjBljxcfHW5GRkVZaWpq1e/duq3Xr1taoUaMq1du2bVsrODg44Lbw828FtyzLysnJ8b+u0+m0unTpUunW9PJbwf/zP/+z0rmfXydgEodlMaMMAACYgzk3AADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGuew+xM/n8+m7775TVFTUT/qYeQAAUHcsy1JRUZFatGhR6Utjz3fZhZvvvvuu0pcAAgCAhuHw4cO64oorfnDMZRduyj+W/PDhw4qOjra5GgAAcDEKCwuVlJR0UV8vctmFm/JLUdHR0YQbAAAamIuZUsKEYgAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUQg3AADAKIQbAABgFMINAAAwiq3h5sMPP9TgwYPVokULORwOrV69+kf32bBhg6699lq5XC61b99eixcvvuR1AgCAhsPWcFNcXKxu3bpp3rx5FzX+22+/1W233aYbb7xRO3fu1MMPP6x7771X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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ps = np.linspace(0, 1)\n", "qs = d6.quantile(ps)\n", "plt.plot(qs, ps)\n", "decorate_cdf('Inverse evaluation')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These functions provide a simple way to make a Q-Q plot.\n", "\n", "Here are two samples from the same distribution." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "cdf1 = Cdf.from_seq(np.random.normal(size=100))\n", "cdf2 = Cdf.from_seq(np.random.normal(size=100))\n", "\n", "cdf1.plot()\n", "cdf2.plot()\n", "decorate_cdf('Two random samples')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's how we compute the Q-Q plot." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "def qq_plot(cdf1, cdf2):\n", " \"\"\"Compute results for a Q-Q plot.\n", " \n", " Evaluates the inverse Cdfs for a \n", " range of cumulative probabilities.\n", " \n", " cdf1: Cdf\n", " cdf2: Cdf\n", " \n", " Returns: tuple of arrays\n", " \"\"\"\n", " ps = np.linspace(0, 1)\n", " q1 = cdf1.quantile(ps)\n", " q2 = cdf2.quantile(ps)\n", " return q1, q2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The result is near the identity line, which suggests that the samples are from the same distribution." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "image/png": "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ZkcD0AiNPv306quv6vXXX9d1110nSbrjjjs0duxYVVRU6JFHHnFaQABoCZU1dbr//S36ZFuWJOmuYV00fURXrnACXEijS82BAwc0ePBg+/PBgwdr5cqVGj58uGpqajRt2jRn5AMApztSUqlb39qozemF8va0aO7v+mpc/2izYwFookaXmrCwMKWnpys+Pt7+Wu/evbVy5UpdeumlyszMdEY+AHCq71LzdO/CzcotqVKIn7deuaG/LkjsYHYsAM3Q6Dk1F110kT766KMTXu/Zs6dWrFihzz77zKHBAMDZXlyVquvfWK/ckip17RSgRXdeSKEBXFijR2pmzJihjRs3nnRbr169tHLlSn344YcOCwYAzrQrq1jzvtgjSbpqQLQeHtNbvlZueQC4skaP1PTt21eTJk065fbevXtrzpw5Dgl1Oi+++KLi4+PVrl07nX/++fr++++d/jUBuJ91+/MlSRcnh+nxcSkUGsANNGmdGrMtXLhQ06dP15w5c/Tjjz8qJSVFI0eO1JEjR8yOBsDF/JB2VJI43QS4EZcqNU899ZSmTJmiSZMmqWfPnnrllVfk5+enf/7zn2ZHA+BCDMPQhrQCSdKAuPYmpwHgKC5Taqqrq7Vx40YNHz7c/pqHh4eGDx+utWvXnvQ9VVVVKi4ubvAAgEMF5TpSUiVvT4tSYkLMjgPAQVym1OTl5amurk6dOnVq8HqnTp2UnZ190vfMnTtXwcHB9kdMTExLRAXQym04duqpT+dgtfNmLg3gLppcaubMmeMyt0OYOXOmioqK7I/09HSzIwEwkc1maNXuI3rjvwckSefFh5qcCIAjNfku3UuWLNGjjz6qIUOG6Oabb9bvf/97+fj4OCNbA2FhYfL09FROTk6D13NychQREXHS9/j4+LRINgCtk81maO+RUm08eFQbDx7Vuv35yiiskCR5elg0omenMxwBgCtpcqnZvHmzNm3apPnz5+vee+/V1KlTdc0112jy5Mk677zznJFRkmS1WtW/f3+tWLFCY8eOlSTZbDatWLFCd911l9O+LgDXUVpVqy3phdp48Kh+OHhUmw4dVUllbYN9Att56eoBMbpxUJziOviblBSAM1gMwzCa++aamhp9/PHHmj9/vr744gt1795dN998syZOnKjg4GBH5pRUf0n3hAkT9Oqrr2rgwIF65pln9P7772v37t0nzLU5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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "q1, q2 = qq_plot(cdf1, cdf2)\n", "plt.plot(q1, q2)\n", "plt.xlabel('Quantity 1')\n", "plt.ylabel('Quantity 2')\n", "plt.title('Q-Q plot');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's how we compute a P-P plot" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "def pp_plot(cdf1, cdf2):\n", " \"\"\"Compute results for a P-P plot.\n", " \n", " Evaluates the Cdfs for all quantities in either Cdf.\n", " \n", " cdf1: Cdf\n", " cdf2: Cdf\n", " \n", " Returns: tuple of arrays\n", " \"\"\"\n", " qs = cdf1.index.union(cdf2)\n", " p1 = cdf1(qs)\n", " p2 = cdf2(qs)\n", " return p1, p2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And here's what it looks like." ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "image/png": "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goIChYSEKD8/X8HBwY33RQAAgNM05Pe3qXtuysvLtXXrViUkJFQts1qtSkhIUHp6eo3rpKenVxsvSYmJibWOLysrU0FBQbUHAADwXqaWm9zcXNntdkVERFRbHhERoezs7BrXyc7ObtD4BQsWKCQkpOoRFRXVOOEBAIBbMv2cG2ebNWuW8vPzqx7Hjh0zOxIAAHAiU+9QHB4eLh8fH+Xk5FRbnpOTo8jIyBrXiYyMbNB4m80mm83WOIEBAIDbM3XPjb+/vwYPHqy0tLSqZQ6HQ2lpaYqPj69xnfj4+GrjJWnDhg21jgcAAE2L6XNLJSUlacqUKRoyZIiGDRumxYsXq6ioSFOnTpUkTZ48We3bt9eCBQskSffff79GjRqlF154Qdddd51WrVqlLVu26KWXXjLzawAAADdhermZMGGCzpw5o7lz5yo7O1uxsbFav3591UnDWVlZslp/2ME0fPhwvfHGG5ozZ44ef/xxde/eXe+995769etn1lcAAABuxPT73Lhafn6+QkNDdezYMe5zAwCAhygoKFBUVJTy8vIUEhJS51jT99y4WmFhoSRxSTgAAB6osLDwkuWmye25cTgcOnnypIKCgmSxWC77fb5vkOwBcj62teuwrV2L7e06bGvXcda2NgxDhYWFateuXbXTVWrS5PbcWK1WdejQodHeLzg4mH8oLsK2dh22tWuxvV2Hbe06ztjWl9pj8z2vv4kfAABoWig3AADAq1BuLpPNZlNycjJ3P3YBtrXrsK1di+3tOmxr13GHbd3kTigGAADejT03AADAq1BuAACAV6HcAAAAr0K5AQAAXoVyU4eUlBRFR0crICBAcXFx2rx5c53j3377bfXq1UsBAQHq37+/UlNTXZTU8zVkW7/88su68sor1bJlS7Vs2VIJCQmX/LPBDxr69/p7q1atksVi0fjx450b0Is0dFvn5eVp+vTpatu2rWw2m3r06MHPkQZo6PZevHixevbsqWbNmikqKkoPPvigSktLXZTWM33++ecaN26c2rVrJ4vFovfee++S62zcuFGDBg2SzWZTt27dtHLlSqfnlIEarVq1yvD39zdWrFhhfPPNN8add95phIaGGjk5OTWO/+qrrwwfHx/jueeeM/bs2WPMmTPH8PPzM3bt2uXi5J6nodt60qRJRkpKirF9+3Zj7969xm9/+1sjJCTEOH78uIuT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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "p1, p2 = pp_plot(cdf1, cdf2)\n", "plt.plot(p1, p2)\n", "plt.xlabel('Cdf 1')\n", "plt.ylabel('Cdf 2')\n", "plt.title('P-P plot');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Statistics\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/17).\n", "\n", "`Cdf` overrides the statistics methods to compute `mean`, `median`, etc." ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def mean(self):\n", " \"\"\"Expected value.\n", "\n", " Returns: float\n", " \"\"\"\n", " return self.make_pmf().mean()\n", "\n" ] } ], "source": [ "psource(Cdf.mean)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.5" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.mean()" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def var(self):\n", " \"\"\"Variance.\n", "\n", " Returns: float\n", " \"\"\"\n", " return self.make_pmf().var()\n", "\n" ] } ], "source": [ "psource(Cdf.var)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.916666666666667" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.var()" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def std(self):\n", " \"\"\"Standard deviation.\n", "\n", " Returns: float\n", " \"\"\"\n", " return self.make_pmf().std()\n", "\n" ] } ], "source": [ "psource(Cdf.std)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.7078251276599332" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.std()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sampling\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/18).\n", "\n", "`choice` chooses a random values from the Cdf, following the API of `np.random.choice`" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def choice(self, *args, **kwargs):\n", " \"\"\"Makes a random sample.\n", "\n", " Uses the probabilities as weights unless `p` is provided.\n", "\n", " Args:\n", " args: same as np.random.choice\n", " options: same as np.random.choice\n", "\n", " Returns: NumPy array\n", " \"\"\"\n", " pmf = self.make_pmf()\n", " return pmf.choice(*args, **kwargs)\n", "\n" ] } ], "source": [ "psource(Cdf.choice)" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([6, 4, 4, 2, 5, 1, 5, 2, 6, 2])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.choice(size=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`sample` chooses a random values from the `Cdf`, following the API of `pd.Series.sample`" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def sample(self, n=1):\n", " \"\"\"Samples with replacement using probabilities as weights.\n", "\n", " Args:\n", " n: number of values\n", "\n", " Returns: NumPy array\n", " \"\"\"\n", " ps = np.random.random(n)\n", " return self.inverse(ps)\n", "\n" ] } ], "source": [ "psource(Cdf.sample)" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([5., 3., 4., 5., 4., 6., 5., 3., 2., 5.])" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.sample(n=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arithmetic\n", "\n", "For comments or questions about this section, see [this issue](https://github.com/AllenDowney/EmpyricalDistributions/issues/9).\n", "\n", "`Cdf` provides `add_dist`, which computes the distribution of the sum.\n", "\n", "The implementation uses outer products to compute the convolution of the two distributions." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def add_dist(self, x):\n", " \"\"\"Distribution of the sum of values drawn from self and x.\n", "\n", " Args:\n", " x: Distribution, scalar, or sequence\n", "\n", " Returns: new Distribution, same subtype as self\n", " \"\"\"\n", " pmf = self.make_pmf()\n", " res = pmf.add_dist(x)\n", " return self.make_same(res)\n", "\n" ] } ], "source": [ "psource(Cdf.add_dist)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " def make_same(self, dist):\n", " \"\"\"Convert the given dist to Cdf.\n", "\n", " Args:\n", " dist: Distribution\n", "\n", " Returns: Cdf\n", " \"\"\"\n", " return dist.make_cdf()\n", "\n" ] } ], "source": [ "psource(Cdf.make_same)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's the distribution of the sum of two dice." ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
20.027778
30.083333
40.166667
50.277778
60.416667
70.583333
80.722222
90.833333
100.916667
110.972222
121.000000
\n", "
" ], "text/plain": [ "2 0.027778\n", "3 0.083333\n", "4 0.166667\n", "5 0.277778\n", "6 0.416667\n", "7 0.583333\n", "8 0.722222\n", "9 0.833333\n", "10 0.916667\n", "11 0.972222\n", "12 1.000000\n", "dtype: float64" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6 = Cdf.from_seq([1,2,3,4,5,6])\n", "\n", "twice = d6.add_dist(d6)\n", "twice" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7.000000000000002" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAtg0lEQVR4nO3de1SVdaLG8WezYSMkIF7YqKFYWnlLTZRBMytJxszyzKpMHXFZ1jRZqZzOUVOx6SJa6bBKk7FymjkryzmdspvpEJmXESMhnFpewrwxFqijggIKs/d7/mi1ZxhBQYGX/eP7WWuv1v6977v3s99V7Kffe9kOy7IsAQAAGCLA7gAAAAANiXIDAACMQrkBAABGodwAAACjUG4AAIBRKDcAAMAolBsAAGAUyg0AADAK5QYAABiFcgOgxXE4HHrqqad8z9944w05HA4dPHjQtkwAGg7lBsBlczgcdXp8/vnndkcF0AIE2h0AgP/7n//5n2rP//jHPyozM/O88Z49ezZlrDqbNGmS7rvvPgUHB9sdBUADoNwAuGy//OUvqz3fvn27MjMzzxtvrpxOp5xOp90xADQQDksBaHS/+MUvdMMNN1QbGzNmjBwOhz744APf2BdffCGHw6FPPvnEN7Z//37dc889atu2rUJDQ/Wzn/1MH3/8cZ3e99y5c5o5c6Y6dOigsLAw3Xnnnfrb3/523nq1nXPzySefaPjw4QoLC1N4eLgGDRqk1atXV1vniy++0M9//nNFREQoNDRUw4cP11/+8pc65QPQOCg3ABrdsGHDtHPnTpWWlkqSLMvSX/7yFwUEBGjLli2+9bZs2aKAgAANHTpUklRcXKwhQ4Zow4YNeuSRR/Tcc8/p7NmzuvPOO/Xee+9d9H2nTp2q9PR0jRw5UosWLVJQUJBGjx5dp8xvvPGGRo8erRMnTmjOnDlatGiR+vfvr/Xr1/vW+eyzz3TTTTeptLRUCxYs0MKFC3Xq1CndeuutysnJqc8uAtCQLABoYNOmTbP+9c/Ll19+aUmy1q1bZ1mWZf31r3+1JFn33HOPFR8f71vvzjvvtAYMGOB7PmPGDEuStWXLFt/Y6dOnrW7dulmxsbGWx+OpNUN+fr4lyXrkkUeqjU+YMMGSZC1YsMA39vvf/96SZB04cMCyLMs6deqUFRYWZsXHx1sVFRXVtvd6vb5/9ujRw0pKSvKNWZZllZeXW926dbNuu+22i+0mAI2EmRsAjW7AgAFq3bq1Nm/eLOnHGZorr7xSycnJysvLU3l5uSzL0tatWzVs2DDfduvWrdPgwYN14403+sZat26thx56SAcPHtSuXbtqfc9169ZJkh5//PFq4zNmzLho3szMTJ0+fVqzZ89Wq1atqi1zOBySpPz8fBUUFGjChAn6+9//ruPHj+v48eMqKyvTiBEjtHnzZnm93ou+F4CGxwnFABqd0+lUQkKC7xDUli1bNGzYMN14443yeDzavn273G63Tpw4Ua3cHDp0SPHx8ee93k9XXR06dEh9+vSp8T0PHTqkgIAAXX311dXGr7322ovm/e677ySp1teWpIKCAknS5MmTa12npKREkZGRF30/AA2LcgOgSdx4442+c2a2bNmiuXPnqk2bNurTp4+2bNkit9stSdXKTXP206zMCy+8oP79+9e4TuvWrZswEYCfUG4ANIlhw4apsrJSb731lo4cOeIrMTfddJOv3FxzzTW+kiNJXbt21d69e897rT179viW16Zr167yer367rvvqs3W1PR6/+6n2Z5vvvlG3bt3v+A64eHhSkxMvOhrAmg6nHMDoEnEx8crKChIixcvVtu2bdW7d29JP5ae7du3a9OmTefN2tx+++3KyclRdna2b6ysrEwrV65UbGysevXqVev7jRo1SpL00ksvVRtPT0+/aNaRI0cqLCxMaWlpOnv2bLVllmVJkgYOHKirr75aL774os6cOXPeaxw7duyi7wOgcTBzA6BJhIaGauDAgdq+fbvvHjfSjzM3ZWVlKisrO6/czJ49W2+99ZZGjRqlxx9/XG3bttUf/vAHHThwQP/3f/+ngIDa//+sf//+Gj9+vF555RWVlJRoyJAhysrK0r59+y6aNTw8XL/97W81depUDRo0SBMmTFBkZKR27typ8vJy/eEPf1BAQIBee+01jRo1Sr1799aUKVPUuXNnHTlyRBs3blR4eLg+/PDDy9tpAC4J5QZAk/lpluZfr36Kjo5W9+7dtW/fvvPKjdvt1rZt2zRr1iy9/PLLOnv2rK6//np9+OGHdbpfzapVq9ShQwe9+eabWrt2rW699VZ9/PHHiomJuei2DzzwgKKiorRo0SI988wzCgoK0nXXXaeZM2f61rn55puVnZ2tZ555RsuWLdOZM2cUHR2t+Ph4/epXv6rH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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "twice.step()\n", "decorate_dice('Two dice')\n", "twice.mean()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To add a constant to a distribution, you could construct a deterministic `Pmf`" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
20.166667
30.333333
40.500000
50.666667
60.833333
71.000000
\n", "
" ], "text/plain": [ "2 0.166667\n", "3 0.333333\n", "4 0.500000\n", "5 0.666667\n", "6 0.833333\n", "7 1.000000\n", "dtype: float64" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "const = Cdf.from_seq([1])\n", "d6.add_dist(const)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But `add_dist` also handles constants as a special case:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
20.166667
30.333333
40.500000
50.666667
60.833333
71.000000
\n", "
" ], "text/plain": [ "2 0.166667\n", "3 0.333333\n", "4 0.500000\n", "5 0.666667\n", "6 0.833333\n", "7 1.000000\n", "dtype: float64" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.add_dist(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other arithmetic operations are also implemented" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
-30.041667
-20.125000
-10.250000
00.416667
10.583333
20.750000
30.875000
40.958333
51.000000
\n", "
" ], "text/plain": [ "-3 0.041667\n", "-2 0.125000\n", "-1 0.250000\n", " 0 0.416667\n", " 1 0.583333\n", " 2 0.750000\n", " 3 0.875000\n", " 4 0.958333\n", " 5 1.000000\n", "dtype: float64" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4 = Cdf.from_seq([1,2,3,4])\n", "d6.sub_dist(d4)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
10.0625
20.1875
30.3125
40.5000
60.6250
80.7500
90.8125
120.9375
161.0000
\n", "
" ], "text/plain": [ "1 0.0625\n", "2 0.1875\n", "3 0.3125\n", "4 0.5000\n", "6 0.6250\n", "8 0.7500\n", "9 0.8125\n", "12 0.9375\n", "16 1.0000\n", "dtype: float64" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.mul_dist(d4)" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
probs
0.2500000.0625
0.3333330.1250
0.5000000.2500
0.6666670.3125
0.7500000.3750
1.0000000.6250
1.3333330.6875
1.5000000.7500
2.0000000.8750
3.0000000.9375
4.0000001.0000
\n", "
" ], "text/plain": [ "0.250000 0.0625\n", "0.333333 0.1250\n", "0.500000 0.2500\n", "0.666667 0.3125\n", "0.750000 0.3750\n", "1.000000 0.6250\n", "1.333333 0.6875\n", "1.500000 0.7500\n", "2.000000 0.8750\n", "3.000000 0.9375\n", "4.000000 1.0000\n", "dtype: float64" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.div_dist(d4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Comparison operators\n", "\n", "`Pmf` implements comparison operators that return probabilities.\n", "\n", "You can compare a `Pmf` to a scalar:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.3333333333333333" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.lt_dist(3)" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.75" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.ge_dist(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or compare `Pmf` objects:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.25" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.gt_dist(d6)" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.41666666666666663" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d6.le_dist(d4)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.16666666666666666" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d4.eq_dist(d6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Interestingly, this way of comparing distributions is [nontransitive]()." ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "A = Cdf.from_seq([2, 2, 4, 4, 9, 9])\n", "B = Cdf.from_seq([1, 1, 6, 6, 8, 8])\n", "C = Cdf.from_seq([3, 3, 5, 5, 7, 7])" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5555555555555556" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.gt_dist(B)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5555555555555556" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B.gt_dist(C)" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5555555555555556" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.gt_dist(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copyright 2019 Allen Downey\n", "\n", "BSD 3-clause license: https://opensource.org/licenses/BSD-3-Clause" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 2 }