diff --git a/000-launch-notebook.bat b/000-launch-notebook.bat new file mode 100644 index 000000000..89710e0e2 --- /dev/null +++ b/000-launch-notebook.bat @@ -0,0 +1,2 @@ +cd C:\Users\w_gon\projects\wgong\DSPG_Data-Science-Play-Ground\PythonDataScienceHandbook +jupyter notebook \ No newline at end of file diff --git a/notebooks/.gitignore b/notebooks/.gitignore new file mode 100644 index 000000000..583bdcb51 --- /dev/null +++ b/notebooks/.gitignore @@ -0,0 +1 @@ +checkpoint/ diff --git a/notebooks/03.01-Introducing-Pandas-Objects.ipynb b/notebooks/03.01-Introducing-Pandas-Objects.ipynb index bdee556f5..b415dc2d9 100644 --- a/notebooks/03.01-Introducing-Pandas-Objects.ipynb +++ b/notebooks/03.01-Introducing-Pandas-Objects.ipynb @@ -19,6 +19,17 @@ "< [Data Manipulation with Pandas](03.00-Introduction-to-Pandas.ipynb) | [Contents](Index.ipynb) | [Data Indexing and Selection](03.02-Data-Indexing-and-Selection.ipynb) >" ] }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -39,10 +50,8 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, + "execution_count": 2, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -62,9 +71,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -97,9 +104,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -126,9 +131,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -155,9 +158,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -177,9 +178,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -226,9 +225,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -261,9 +258,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -290,9 +285,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -318,9 +311,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -353,9 +344,7 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -394,9 +383,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -423,9 +410,7 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -472,9 +457,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -504,9 +487,7 @@ { "cell_type": "code", "execution_count": 15, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -536,9 +517,7 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -568,9 +547,7 @@ { "cell_type": "code", "execution_count": 17, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -622,9 +599,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -659,9 +634,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -735,9 +708,7 @@ { "cell_type": "code", "execution_count": 20, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -764,9 +735,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -804,9 +773,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -859,9 +826,7 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -917,6 +882,143 @@ "pd.DataFrame(population, columns=['population'])" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### From a list of Series objects\n", + "\n", + "- https://stackoverflow.com/questions/23521511/pandas-creating-dataframe-from-series" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "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", + "
ab
012
134
\n", + "
" + ], + "text/plain": [ + " a b\n", + "0 1 2\n", + "1 3 4" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = ['a','b']\n", + "list_of_series = [pd.Series([1,2],index=cols), pd.Series([3,4],index=cols)]\n", + "df = pd.DataFrame(list_of_series, columns=cols)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "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", + "
abc
01.02.0NaN
13.0NaN4.0
\n", + "
" + ], + "text/plain": [ + " a b c\n", + "0 1.0 2.0 NaN\n", + "1 3.0 NaN 4.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list_of_series = [pd.Series([1,2],index=['a','b']), pd.Series([3,4],index=['a','c'])]\n", + "df = pd.concat(list_of_series, axis=1).transpose()\n", + "df" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -930,9 +1032,7 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -994,9 +1094,7 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1055,9 +1153,7 @@ { "cell_type": "code", "execution_count": 26, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1133,9 +1229,7 @@ { "cell_type": "code", "execution_count": 27, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1200,9 +1294,7 @@ { "cell_type": "code", "execution_count": 28, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1224,9 +1316,7 @@ { "cell_type": "code", "execution_count": 29, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1291,9 +1381,7 @@ { "cell_type": "code", "execution_count": 30, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1324,9 +1412,7 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1346,9 +1432,7 @@ { "cell_type": "code", "execution_count": 32, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1375,9 +1459,7 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1401,9 +1483,7 @@ { "cell_type": "code", "execution_count": 34, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "ename": "TypeError", @@ -1442,9 +1522,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "indA = pd.Index([1, 3, 5, 7, 9])\n", @@ -1454,9 +1532,7 @@ { "cell_type": "code", "execution_count": 36, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1476,9 +1552,7 @@ { "cell_type": "code", "execution_count": 37, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1498,9 +1572,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1550,9 +1622,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.05-Hierarchical-Indexing.ipynb b/notebooks/03.05-Hierarchical-Indexing.ipynb index 43e3475c4..8a63fdfd5 100644 --- a/notebooks/03.05-Hierarchical-Indexing.ipynb +++ b/notebooks/03.05-Hierarchical-Indexing.ipynb @@ -2,13 +2,11 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "\n", "\n", + "\n", "*This notebook contains an excerpt from the [Python Data Science Handbook](http://shop.oreilly.com/product/0636920034919.do) by Jake VanderPlas; the content is available [on GitHub](https://github.com/jakevdp/PythonDataScienceHandbook).*\n", "\n", "*The text is released under the [CC-BY-NC-ND license](https://creativecommons.org/licenses/by-nc-nd/3.0/us/legalcode), and code is released under the [MIT license](https://opensource.org/licenses/MIT). If you find this content useful, please consider supporting the work by [buying the book](http://shop.oreilly.com/product/0636920034919.do)!*" @@ -16,13 +14,23 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "\n", - "< [Handling Missing Data](03.04-Missing-Values.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) >" + "< [Handling Missing Data](03.04-Missing-Values.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) >\n", + "\n", + "\"Open\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" ] }, { @@ -34,10 +42,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Up to this point we've been focused primarily on one-dimensional and two-dimensional data, stored in Pandas ``Series`` and ``DataFrame`` objects, respectively.\n", "Often it is useful to go beyond this and store higher-dimensional data–that is, data indexed by more than one or two keys.\n", @@ -52,11 +57,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", @@ -65,10 +66,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## A Multiply Indexed Series\n", "\n", @@ -78,10 +76,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### The bad way\n", "\n", @@ -92,11 +87,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -128,10 +119,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "With this indexing scheme, you can straightforwardly index or slice the series based on this multiple index:" ] @@ -139,11 +127,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -166,10 +150,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "But the convenience ends there. For example, if you need to select all values from 2010, you'll need to do some messy (and potentially slow) munging to make it happen:" ] @@ -177,11 +158,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -203,20 +180,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "This produces the desired result, but is not as clean (or as efficient for large datasets) as the slicing syntax we've grown to love in Pandas." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### The Better Way: Pandas MultiIndex\n", "Fortunately, Pandas provides a better way.\n", @@ -227,17 +198,18 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "MultiIndex(levels=[['California', 'New York', 'Texas'], [2000, 2010]],\n", - " labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])" + "MultiIndex([('California', 2000),\n", + " ('California', 2010),\n", + " ( 'New York', 2000),\n", + " ( 'New York', 2010),\n", + " ( 'Texas', 2000),\n", + " ( 'Texas', 2010)],\n", + " )" ] }, "execution_count": 5, @@ -252,10 +224,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Notice that the ``MultiIndex`` contains multiple *levels* of indexing–in this case, the state names and the years, as well as multiple *labels* for each data point which encode these levels.\n", "\n", @@ -265,11 +234,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -295,10 +260,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Here the first two columns of the ``Series`` representation show the multiple index values, while the third column shows the data.\n", "Notice that some entries are missing in the first column: in this multi-index representation, any blank entry indicates the same value as the line above it." @@ -306,10 +268,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Now to access all data for which the second index is 2010, we can simply use the Pandas slicing notation:" ] @@ -317,11 +276,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -343,10 +298,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The result is a singly indexed array with just the keys we're interested in.\n", "This syntax is much more convenient (and the operation is much more efficient!) than the home-spun tuple-based multi-indexing solution that we started with.\n", @@ -355,10 +307,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### MultiIndex as extra dimension\n", "\n", @@ -369,16 +318,25 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -426,10 +384,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Naturally, the ``stack()`` method provides the opposite operation:" ] @@ -437,11 +392,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -466,10 +417,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Seeing this, you might wonder why would we would bother with hierarchical indexing at all.\n", "The reason is simple: just as we were able to use multi-indexing to represent two-dimensional data within a one-dimensional ``Series``, we can also use it to represent data of three or more dimensions in a ``Series`` or ``DataFrame``.\n", @@ -479,16 +427,25 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -561,10 +518,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "In addition, all the ufuncs and other functionality discussed in [Operating on Data in Pandas](03.03-Operations-in-Pandas.ipynb) work with hierarchical indices as well.\n", "Here we compute the fraction of people under 18 by year, given the above data:" @@ -573,16 +527,25 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -630,20 +593,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "This allows us to easily and quickly manipulate and explore even high-dimensional data." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Methods of MultiIndex Creation\n", "\n", @@ -653,16 +610,25 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -676,24 +642,24 @@ " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", "
a10.5542330.3560720.8445320.500134
20.9252440.2194740.8560650.426294
b10.4417590.6100540.9775350.483796
20.1714950.8866880.6699580.873121
\n", @@ -701,10 +667,10 @@ ], "text/plain": [ " data1 data2\n", - "a 1 0.554233 0.356072\n", - " 2 0.925244 0.219474\n", - "b 1 0.441759 0.610054\n", - " 2 0.171495 0.886688" + "a 1 0.844532 0.500134\n", + " 2 0.856065 0.426294\n", + "b 1 0.977535 0.483796\n", + " 2 0.669958 0.873121" ] }, "execution_count": 12, @@ -721,10 +687,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The work of creating the ``MultiIndex`` is done in the background.\n", "\n", @@ -734,21 +697,17 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "California 2000 33871648\n", " 2010 37253956\n", - "New York 2000 18976457\n", - " 2010 19378102\n", "Texas 2000 20851820\n", " 2010 25145561\n", + "New York 2000 18976457\n", + " 2010 19378102\n", "dtype: int64" ] }, @@ -769,20 +728,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Nevertheless, it is sometimes useful to explicitly create a ``MultiIndex``; we'll see a couple of these methods here." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Explicit MultiIndex constructors\n", "\n", @@ -793,17 +746,16 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "MultiIndex(levels=[['a', 'b'], [1, 2]],\n", - " labels=[[0, 0, 1, 1], [0, 1, 0, 1]])" + "MultiIndex([('a', 1),\n", + " ('a', 2),\n", + " ('b', 1),\n", + " ('b', 2)],\n", + " )" ] }, "execution_count": 14, @@ -817,10 +769,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "You can construct it from a list of tuples giving the multiple index values of each point:" ] @@ -828,17 +777,16 @@ { "cell_type": "code", "execution_count": 15, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "MultiIndex(levels=[['a', 'b'], [1, 2]],\n", - " labels=[[0, 0, 1, 1], [0, 1, 0, 1]])" + "MultiIndex([('a', 1),\n", + " ('a', 2),\n", + " ('b', 1),\n", + " ('b', 2)],\n", + " )" ] }, "execution_count": 15, @@ -852,10 +800,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "You can even construct it from a Cartesian product of single indices:" ] @@ -863,17 +808,16 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "MultiIndex(levels=[['a', 'b'], [1, 2]],\n", - " labels=[[0, 0, 1, 1], [0, 1, 0, 1]])" + "MultiIndex([('a', 1),\n", + " ('a', 2),\n", + " ('b', 1),\n", + " ('b', 2)],\n", + " )" ] }, "execution_count": 16, @@ -887,56 +831,21 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Similarly, you can construct the ``MultiIndex`` directly using its internal encoding by passing ``levels`` (a list of lists containing available index values for each level) and ``labels`` (a list of lists that reference these labels):" ] }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "MultiIndex(levels=[['a', 'b'], [1, 2]],\n", - " labels=[[0, 0, 1, 1], [0, 1, 0, 1]])" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.MultiIndex(levels=[['a', 'b'], [1, 2]],\n", - " labels=[[0, 0, 1, 1], [0, 1, 0, 1]])" - ] - }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Any of these objects can be passed as the ``index`` argument when creating a ``Series`` or ``Dataframe``, or be passed to the ``reindex`` method of an existing ``Series`` or ``DataFrame``." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### MultiIndex level names\n", "\n", @@ -947,11 +856,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -978,20 +883,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "With more involved datasets, this can be a useful way to keep track of the meaning of various index values." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### MultiIndex for columns\n", "\n", @@ -1001,17 +900,30 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "execution_count": 8, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -1046,40 +958,40 @@ " \n", " \n", " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
2013134.034.533.038.131.038.732.036.735.037.2
244.037.750.035.029.036.737.840.037.645.038.6
2014130.037.439.037.861.036.942.036.733.036.644.036.0
247.037.848.037.351.036.535.453.038.438.036.8
\n", @@ -1089,13 +1001,13 @@ "subject Bob Guido Sue \n", "type HR Temp HR Temp HR Temp\n", "year visit \n", - "2013 1 31.0 38.7 32.0 36.7 35.0 37.2\n", - " 2 44.0 37.7 50.0 35.0 29.0 36.7\n", - "2014 1 30.0 37.4 39.0 37.8 61.0 36.9\n", - " 2 47.0 37.8 48.0 37.3 51.0 36.5" + "2013 1 34.0 34.5 33.0 38.1 31.0 37.2\n", + " 2 29.0 37.8 40.0 37.6 45.0 38.6\n", + "2014 1 42.0 36.7 33.0 36.6 44.0 36.0\n", + " 2 48.0 35.4 53.0 38.4 38.0 36.8" ] }, - "execution_count": 19, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -1119,10 +1031,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Here we see where the multi-indexing for both rows and columns can come in *very* handy.\n", "This is fundamentally four-dimensional data, where the dimensions are the subject, the measurement type, the year, and the visit number.\n", @@ -1132,11 +1041,7 @@ { "cell_type": "code", "execution_count": 20, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1204,20 +1109,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "For complicated records containing multiple labeled measurements across multiple times for many subjects (people, countries, cities, etc.) use of hierarchical rows and columns can be extremely convenient!" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Indexing and Slicing a MultiIndex\n", "\n", @@ -1227,10 +1126,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Multiply indexed Series\n", "\n", @@ -1240,11 +1136,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1270,10 +1162,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "We can access single elements by indexing with multiple terms:" ] @@ -1281,11 +1170,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1304,10 +1189,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The ``MultiIndex`` also supports *partial indexing*, or indexing just one of the levels in the index.\n", "The result is another ``Series``, with the lower-level indices maintained:" @@ -1316,11 +1198,7 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1342,10 +1220,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Partial slicing is available as well, as long as the ``MultiIndex`` is sorted (see discussion in [Sorted and Unsorted Indices](#Sorted-and-unsorted-indices)):" ] @@ -1353,11 +1228,7 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1381,10 +1252,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "With sorted indices, partial indexing can be performed on lower levels by passing an empty slice in the first index:" ] @@ -1392,11 +1260,7 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1419,10 +1283,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Other types of indexing and selection (discussed in [Data Indexing and Selection](03.02-Data-Indexing-and-Selection.ipynb)) work as well; for example, selection based on Boolean masks:" ] @@ -1430,11 +1291,7 @@ { "cell_type": "code", "execution_count": 26, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1457,10 +1314,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Selection based on fancy indexing also works:" ] @@ -1468,11 +1322,7 @@ { "cell_type": "code", "execution_count": 27, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1496,10 +1346,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Multiply indexed DataFrames\n", "\n", @@ -1509,17 +1356,30 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "execution_count": 9, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -1554,40 +1414,40 @@ " \n", " \n", " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
2013134.034.533.038.131.038.732.036.735.037.2
244.037.750.035.029.036.737.840.037.645.038.6
2014130.037.439.037.861.036.942.036.733.036.644.036.0
247.037.848.037.351.036.535.453.038.438.036.8
\n", @@ -1597,13 +1457,13 @@ "subject Bob Guido Sue \n", "type HR Temp HR Temp HR Temp\n", "year visit \n", - "2013 1 31.0 38.7 32.0 36.7 35.0 37.2\n", - " 2 44.0 37.7 50.0 35.0 29.0 36.7\n", - "2014 1 30.0 37.4 39.0 37.8 61.0 36.9\n", - " 2 47.0 37.8 48.0 37.3 51.0 36.5" + "2013 1 34.0 34.5 33.0 38.1 31.0 37.2\n", + " 2 29.0 37.8 40.0 37.6 45.0 38.6\n", + "2014 1 42.0 36.7 33.0 36.6 44.0 36.0\n", + " 2 48.0 35.4 53.0 38.4 38.0 36.8" ] }, - "execution_count": 28, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -1614,50 +1474,303 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Remember that columns are primary in a ``DataFrame``, and the syntax used for multiply indexed ``Series`` applies to the columns.\n", "For example, we can recover Guido's heart rate data with a simple operation:" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Start access from Columns" + ] + }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "year visit\n", - "2013 1 32.0\n", - " 2 50.0\n", - "2014 1 39.0\n", - " 2 48.0\n", - "Name: (Guido, HR), dtype: float64" + "(type HR Temp\n", + " year visit \n", + " 2013 1 33.0 38.1\n", + " 2 40.0 37.6\n", + " 2014 1 33.0 36.6\n", + " 2 53.0 38.4,\n", + " pandas.core.frame.DataFrame)" ] }, - "execution_count": 29, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "health_data['Guido', 'HR']" + "x = health_data['Guido']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(year visit\n", + " 2013 1 33.0\n", + " 2 40.0\n", + " 2014 1 33.0\n", + " 2 53.0\n", + " Name: (Guido, HR), dtype: float64,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data['Guido', 'HR']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(visit\n", + " 1 33.0\n", + " 2 40.0\n", + " Name: (Guido, HR), dtype: float64,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data['Guido', 'HR'][2013]\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(33.0, numpy.float64)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data['Guido', 'HR'][2013,1]\n", + "x, type(x)" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, + "source": [ + "#### Start access from Rows" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(subject Bob Guido Sue \n", + " type HR Temp HR Temp HR Temp\n", + " visit \n", + " 1 34.0 34.5 33.0 38.1 31.0 37.2\n", + " 2 29.0 37.8 40.0 37.6 45.0 38.6,\n", + " pandas.core.frame.DataFrame)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013]\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(type HR Temp\n", + " visit \n", + " 1 34.0 34.5\n", + " 2 29.0 37.8,\n", + " pandas.core.frame.DataFrame)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013, 'Bob']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(subject type\n", + " Bob HR 34.0\n", + " Temp 34.5\n", + " Guido HR 33.0\n", + " Temp 38.1\n", + " Sue HR 31.0\n", + " Temp 37.2\n", + " Name: (2013, 1), dtype: float64,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013,1]\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(type\n", + " HR 34.0\n", + " Temp 34.5\n", + " Name: (2013, 1), dtype: float64,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013,1]['Bob']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(34.0, numpy.float64)" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013,1]['Bob']['HR']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(34.0, numpy.float64)" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[2013,1]['Bob', 'HR']\n", + "x, type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(year visit\n", + " 2013 1 34.0\n", + " 2 29.0\n", + " 2014 1 42.0\n", + " 2 48.0\n", + " Name: (Bob, HR), dtype: float64,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = health_data.loc[:, ('Bob', 'HR')]\n", + "x, type(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ "Also, as with the single-index case, we can use the ``loc``, ``iloc``, and ``ix`` indexers introduced in [Data Indexing and Selection](03.02-Data-Indexing-and-Selection.ipynb). For example:" ] @@ -1665,11 +1778,7 @@ { "cell_type": "code", "execution_count": 30, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1730,10 +1839,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "These indexers provide an array-like view of the underlying two-dimensional data, but each individual index in ``loc`` or ``iloc`` can be passed a tuple of multiple indices. For example:" ] @@ -1741,11 +1847,7 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1769,10 +1871,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Working with slices within these index tuples is not especially convenient; trying to create a slice within a tuple will lead to a syntax error:" ] @@ -1780,11 +1879,7 @@ { "cell_type": "code", "execution_count": 32, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "ename": "SyntaxError", @@ -1801,10 +1896,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "You could get around this by building the desired slice explicitly using Python's built-in ``slice()`` function, but a better way in this context is to use an ``IndexSlice`` object, which Pandas provides for precisely this situation.\n", "For example:" @@ -1813,11 +1905,7 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1886,20 +1974,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "There are so many ways to interact with data in multiply indexed ``Series`` and ``DataFrame``s, and as with many tools in this book the best way to become familiar with them is to try them out!" ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Rearranging Multi-Indices\n", "\n", @@ -1910,10 +1992,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Sorted and unsorted indices\n", "\n", @@ -1927,11 +2006,7 @@ { "cell_type": "code", "execution_count": 34, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -1960,10 +2035,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "If we try to take a partial slice of this index, it will result in an error:" ] @@ -1971,11 +2043,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1996,10 +2064,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Although it is not entirely clear from the error message, this is the result of the MultiIndex not being sorted.\n", "For various reasons, partial slices and other similar operations require the levels in the ``MultiIndex`` to be in sorted (i.e., lexographical) order.\n", @@ -2010,11 +2075,7 @@ { "cell_type": "code", "execution_count": 36, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2041,10 +2102,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "With the index sorted in this way, partial slicing will work as expected:" ] @@ -2052,11 +2110,7 @@ { "cell_type": "code", "execution_count": 37, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2080,10 +2134,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Stacking and unstacking indices\n", "\n", @@ -2093,11 +2144,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2154,11 +2201,7 @@ { "cell_type": "code", "execution_count": 39, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2216,10 +2259,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "The opposite of ``unstack()`` is ``stack()``, which here can be used to recover the original series:" ] @@ -2227,11 +2267,7 @@ { "cell_type": "code", "execution_count": 40, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2257,10 +2293,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "### Index setting and resetting\n", "\n", @@ -2272,11 +2305,7 @@ { "cell_type": "code", "execution_count": 41, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2354,10 +2383,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Often when working with data in the real world, the raw input data looks like this and it's useful to build a ``MultiIndex`` from the column values.\n", "This can be done with the ``set_index`` method of the ``DataFrame``, which returns a multiply indexed ``DataFrame``:" @@ -2366,11 +2392,7 @@ { "cell_type": "code", "execution_count": 42, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2443,20 +2465,14 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "In practice, I find this type of reindexing to be one of the more useful patterns when encountering real-world datasets." ] }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Data Aggregations on Multi-Indices\n", "\n", @@ -2469,11 +2485,7 @@ { "cell_type": "code", "execution_count": 43, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2573,10 +2585,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Perhaps we'd like to average-out the measurements in the two visits each year. We can do this by naming the index level we'd like to explore, in this case the year:" ] @@ -2584,11 +2593,7 @@ { "cell_type": "code", "execution_count": 44, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2664,10 +2669,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "By further making use of the ``axis`` keyword, we can take the mean among levels on the columns as well:" ] @@ -2675,11 +2677,7 @@ { "cell_type": "code", "execution_count": 45, - "metadata": { - "collapsed": false, - "deletable": true, - "editable": true - }, + "metadata": {}, "outputs": [ { "data": { @@ -2731,10 +2729,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "Thus in two lines, we've been able to find the average heart rate and temperature measured among all subjects in all visits each year.\n", "This syntax is actually a short cut to the ``GroupBy`` functionality, which we will discuss in [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb).\n", @@ -2743,10 +2738,7 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "## Aside: Panel Data\n", "\n", @@ -2764,13 +2756,12 @@ }, { "cell_type": "markdown", - "metadata": { - "deletable": true, - "editable": true - }, + "metadata": {}, "source": [ "\n", - "< [Handling Missing Data](03.04-Missing-Values.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) >" + "< [Handling Missing Data](03.04-Missing-Values.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) >\n", + "\n", + "\"Open\n" ] } ], @@ -2791,9 +2782,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.06-Concat-And-Append.ipynb b/notebooks/03.06-Concat-And-Append.ipynb index 93e0aa729..05db96109 100644 --- a/notebooks/03.06-Concat-And-Append.ipynb +++ b/notebooks/03.06-Concat-And-Append.ipynb @@ -6,6 +6,7 @@ "source": [ "\n", "\n", + "\n", "*This notebook contains an excerpt from the [Python Data Science Handbook](http://shop.oreilly.com/product/0636920034919.do) by Jake VanderPlas; the content is available [on GitHub](https://github.com/jakevdp/PythonDataScienceHandbook).*\n", "\n", "*The text is released under the [CC-BY-NC-ND license](https://creativecommons.org/licenses/by-nc-nd/3.0/us/legalcode), and code is released under the [MIT license](https://opensource.org/licenses/MIT). If you find this content useful, please consider supporting the work by [buying the book](http://shop.oreilly.com/product/0636920034919.do)!*" @@ -16,7 +17,9 @@ "metadata": {}, "source": [ "\n", - "< [Hierarchical Indexing](03.05-Hierarchical-Indexing.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Merge and Join](03.07-Merge-and-Join.ipynb) >" + "< [Hierarchical Indexing](03.05-Hierarchical-Indexing.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Merge and Join](03.07-Merge-and-Join.ipynb) >\n", + "\n", + "\"Open\n" ] }, { @@ -42,9 +45,18 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true - }, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", @@ -60,15 +72,26 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, + "execution_count": 3, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -81,34 +104,34 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", "
0A0B0C0A0=16B0=10C0=12
1A1B1C1A1=17B1=15C1=19
2A2B2C2A2=17B2=17C2=11
\n", "
" ], "text/plain": [ - " A B C\n", - "0 A0 B0 C0\n", - "1 A1 B1 C1\n", - "2 A2 B2 C2" + " A B C\n", + "0 A0=16 B0=10 C0=12\n", + "1 A1=17 B1=15 C1=19\n", + "2 A2=17 B2=17 C2=11" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -116,7 +139,7 @@ "source": [ "def make_df(cols, ind):\n", " \"\"\"Quickly make a DataFrame\"\"\"\n", - " data = {c: [str(c) + str(i) for i in ind]\n", + " data = {c: [f\"{c}{i}={np.random.randint(10,20)}\" for i in ind]\n", " for c in cols}\n", " return pd.DataFrame(data, ind)\n", "\n", @@ -133,10 +156,8 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true - }, + "execution_count": 4, + "metadata": {}, "outputs": [], "source": [ "class display(object):\n", @@ -148,12 +169,18 @@ " self.args = args\n", " \n", " def _repr_html_(self):\n", - " return '\\n'.join(self.template.format(a, eval(a)._repr_html_())\n", - " for a in self.args)\n", + " try:\n", + " res = '\\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res\n", " \n", " def __repr__(self):\n", - " return '\\n\\n'.join(a + '\\n' + repr(eval(a))\n", - " for a in self.args)\n", + " try:\n", + " res = '\\n\\n'.join(a + '\\n' + repr(eval(a)) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res\n", " " ] }, @@ -176,10 +203,8 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, "outputs": [ { "data": { @@ -187,7 +212,7 @@ "array([1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -209,10 +234,8 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 6, + "metadata": {}, "outputs": [ { "data": { @@ -221,7 +244,7 @@ " [3, 4, 3, 4]])" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -232,6 +255,46 @@ "np.concatenate([x, x], axis=1)" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "x\n", + "[[1, 2], [3, 4]]\n", + "\n", + "y1\n", + "array([[1, 2, 1, 2],\n", + " [3, 4, 3, 4]])\n", + "\n", + "y2\n", + "array([[1, 2],\n", + " [3, 4],\n", + " [1, 2],\n", + " [3, 4]])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y1 = np.concatenate([x, x], axis=1)\n", + "y2 = np.concatenate([x, x], axis=0)\n", + "display(\"x\", \"y1\", \"y2\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -258,9 +321,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -295,9 +356,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -430,9 +489,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -567,9 +624,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -714,9 +769,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -747,9 +800,7 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -880,9 +931,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1025,9 +1074,7 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1176,9 +1223,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1315,9 +1360,7 @@ { "cell_type": "code", "execution_count": 15, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1468,9 +1511,7 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1606,7 +1647,9 @@ "metadata": {}, "source": [ "\n", - "< [Hierarchical Indexing](03.05-Hierarchical-Indexing.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Merge and Join](03.07-Merge-and-Join.ipynb) >" + "< [Hierarchical Indexing](03.05-Hierarchical-Indexing.ipynb) | [Contents](Index.ipynb) | [Combining Datasets: Merge and Join](03.07-Merge-and-Join.ipynb) >\n", + "\n", + "\"Open\n" ] } ], @@ -1627,9 +1670,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.07-Merge-and-Join.ipynb b/notebooks/03.07-Merge-and-Join.ipynb index aa91fa060..3f44253c8 100644 --- a/notebooks/03.07-Merge-and-Join.ipynb +++ b/notebooks/03.07-Merge-and-Join.ipynb @@ -6,6 +6,7 @@ "source": [ "\n", "\n", + "\n", "*This notebook contains an excerpt from the [Python Data Science Handbook](http://shop.oreilly.com/product/0636920034919.do) by Jake VanderPlas; the content is available [on GitHub](https://github.com/jakevdp/PythonDataScienceHandbook).*\n", "\n", "*The text is released under the [CC-BY-NC-ND license](https://creativecommons.org/licenses/by-nc-nd/3.0/us/legalcode), and code is released under the [MIT license](https://opensource.org/licenses/MIT). If you find this content useful, please consider supporting the work by [buying the book](http://shop.oreilly.com/product/0636920034919.do)!*" @@ -16,7 +17,20 @@ "metadata": {}, "source": [ "\n", - "< [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) | [Contents](Index.ipynb) | [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb) >" + "< [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) | [Contents](Index.ipynb) | [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb) >\n", + "\n", + "\"Open\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" ] }, { @@ -40,9 +54,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", @@ -57,12 +69,18 @@ " self.args = args\n", " \n", " def _repr_html_(self):\n", - " return '\\n'.join(self.template.format(a, eval(a)._repr_html_())\n", - " for a in self.args)\n", + " try:\n", + " res = '\\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res\n", " \n", " def __repr__(self):\n", - " return '\\n\\n'.join(a + '\\n' + repr(eval(a))\n", - " for a in self.args)" + " try:\n", + " res = '\\n\\n'.join(a + '\\n' + repr(eval(a)) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res" ] }, { @@ -103,15 +121,26 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1

\n", + "\n", "\n", " \n", " \n", @@ -147,6 +176,19 @@ " \n", "
\n", "

df2

\n", + "\n", "
\n", " \n", " \n", @@ -220,14 +262,25 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -313,15 +366,26 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df3

\n", + "\n", "
\n", " \n", " \n", @@ -362,6 +426,19 @@ " \n", "
\n", "

df4

\n", + "\n", "
\n", " \n", " \n", @@ -392,6 +469,19 @@ " \n", "
\n", "

pd.merge(df3, df4)

\n", + "\n", "
\n", " \n", " \n", @@ -497,15 +587,26 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1

\n", + "\n", "
\n", " \n", " \n", @@ -541,6 +642,19 @@ " \n", "
\n", "

df5

\n", + "\n", "
\n", " \n", " \n", @@ -586,6 +700,19 @@ " \n", "
\n", "

pd.merge(df1, df5)

\n", + "\n", "
\n", " \n", " \n", @@ -727,15 +854,26 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1

\n", + "\n", "
\n", " \n", " \n", @@ -771,6 +909,19 @@ " \n", "
\n", "

df2

\n", + "\n", "
\n", " \n", " \n", @@ -806,6 +957,19 @@ " \n", "
\n", "

pd.merge(df1, df2, on='employee')

\n", + "\n", "
\n", " \n", " \n", @@ -897,15 +1061,26 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1

\n", + "\n", "
\n", " \n", " \n", @@ -941,6 +1116,19 @@ " \n", "
\n", "

df3

\n", + "\n", "
\n", " \n", " \n", @@ -976,6 +1164,19 @@ " \n", "
\n", "

pd.merge(df1, df3, left_on=\"employee\", right_on=\"name\")

\n", + "\n", "
\n", " \n", " \n", @@ -1064,14 +1265,25 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -1140,15 +1352,26 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1a

\n", + "\n", "
\n", " \n", " \n", @@ -1183,6 +1406,19 @@ " \n", "
\n", "

df2a

\n", + "\n", "
\n", " \n", " \n", @@ -1255,15 +1491,26 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1a

\n", + "\n", "
\n", " \n", " \n", @@ -1298,6 +1545,19 @@ " \n", "
\n", "

df2a

\n", + "\n", "
\n", " \n", " \n", @@ -1332,6 +1592,19 @@ " \n", "
\n", "

pd.merge(df1a, df2a, left_index=True, right_index=True)

\n", + "\n", "
\n", " \n", " \n", @@ -1347,11 +1620,6 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", @@ -1362,6 +1630,11 @@ " \n", " \n", " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1391,9 +1664,9 @@ "pd.merge(df1a, df2a, left_index=True, right_index=True)\n", " group hire_date\n", "employee \n", - "Lisa Engineering 2004\n", "Bob Accounting 2008\n", "Jake Engineering 2012\n", + "Lisa Engineering 2004\n", "Sue HR 2014" ] }, @@ -1417,15 +1690,26 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1a

\n", + "\n", "
LisaEngineering2004
BobAccounting20082012
LisaEngineering2004
SueHR2014
\n", " \n", " \n", @@ -1460,6 +1744,19 @@ " \n", "
\n", "

df2a

\n", + "\n", "
\n", " \n", " \n", @@ -1494,6 +1791,19 @@ " \n", "
\n", "

df1a.join(df2a)

\n", + "\n", "
\n", " \n", " \n", @@ -1578,15 +1888,26 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df1a

\n", + "\n", "
\n", " \n", " \n", @@ -1621,6 +1942,19 @@ " \n", "
\n", "

df3

\n", + "\n", "
\n", " \n", " \n", @@ -1656,6 +1990,19 @@ " \n", "
\n", "

pd.merge(df1a, df3, left_index=True, right_on='name')

\n", + "\n", "
\n", " \n", " \n", @@ -1753,16 +2100,27 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df6

\n", + "\n", "
\n", " \n", " \n", @@ -1793,6 +2151,19 @@ " \n", "
\n", "

df7

\n", + "\n", "
\n", " \n", " \n", @@ -1818,6 +2189,19 @@ " \n", "
\n", "

pd.merge(df6, df7)

\n", + "\n", "
\n", " \n", " \n", @@ -1856,7 +2240,7 @@ "0 Mary bread wine" ] }, - "execution_count": 13, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -1882,15 +2266,26 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, + "execution_count": 18, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -1916,7 +2311,7 @@ "0 Mary bread wine" ] }, - "execution_count": 14, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -1935,16 +2330,27 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, + "execution_count": 19, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df6

\n", + "\n", "
\n", " \n", " \n", @@ -1975,6 +2381,19 @@ " \n", "
\n", "

df7

\n", + "\n", "
\n", " \n", " \n", @@ -2000,6 +2419,19 @@ " \n", "
\n", "

pd.merge(df6, df7, how='outer')

\n", + "\n", "
\n", " \n", " \n", @@ -2059,7 +2491,7 @@ "3 Joseph NaN beer" ] }, - "execution_count": 15, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -2078,16 +2510,27 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": 20, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df6

\n", + "\n", "
\n", " \n", " \n", @@ -2118,6 +2561,19 @@ " \n", "
\n", "

df7

\n", + "\n", "
\n", " \n", " \n", @@ -2143,6 +2599,19 @@ " \n", "
\n", "

pd.merge(df6, df7, how='left')

\n", + "\n", "
\n", " \n", " \n", @@ -2195,7 +2664,7 @@ "2 Mary bread wine" ] }, - "execution_count": 16, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -2231,16 +2700,27 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, + "execution_count": 21, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df8

\n", + "\n", "
\n", " \n", " \n", @@ -2276,6 +2756,19 @@ " \n", "
\n", "

df9

\n", + "\n", "
\n", " \n", " \n", @@ -2311,6 +2804,19 @@ " \n", "
\n", "

pd.merge(df8, df9, on=\"name\")

\n", + "\n", "
\n", " \n", " \n", @@ -2373,7 +2879,7 @@ "3 Sue 4 2" ] }, - "execution_count": 17, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -2396,16 +2902,27 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, + "execution_count": 22, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

df8

\n", + "\n", "
\n", " \n", " \n", @@ -2441,6 +2958,19 @@ " \n", "
\n", "

df9

\n", + "\n", "
\n", " \n", " \n", @@ -2476,6 +3006,19 @@ " \n", "
\n", "

pd.merge(df8, df9, on=\"name\", suffixes=[\"_L\", \"_R\"])

\n", + "\n", "
\n", " \n", " \n", @@ -2538,7 +3081,7 @@ "3 Sue 4 2" ] }, - "execution_count": 18, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -2576,9 +3119,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Following are shell commands to download the data\n", @@ -2596,16 +3137,27 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, + "execution_count": 23, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "

pop.head()

\n", + "\n", "
\n", " \n", " \n", @@ -2658,6 +3210,19 @@ " \n", "
\n", "

areas.head()

\n", + "\n", "
\n", " \n", " \n", @@ -2698,6 +3263,19 @@ " \n", "
\n", "

abbrevs.head()

\n", + "\n", "
\n", " \n", " \n", @@ -2763,7 +3341,7 @@ "4 California CA" ] }, - "execution_count": 20, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -2790,15 +3368,34 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": 24, + "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":3: FutureWarning: In a future version of pandas all arguments of DataFrame.drop except for the argument 'labels' will be keyword-only\n", + " merged = merged.drop('abbreviation', 1) # drop duplicate info\n" + ] + }, { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -2864,7 +3461,7 @@ "4 AL under18 2011 1125763.0 Alabama" ] }, - "execution_count": 21, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -2885,10 +3482,8 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, + "execution_count": 25, + "metadata": {}, "outputs": [ { "data": { @@ -2901,7 +3496,7 @@ "dtype: bool" ] }, - "execution_count": 22, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -2919,15 +3514,26 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, + "execution_count": 26, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -2993,7 +3599,7 @@ "2452 PR total 1993 NaN NaN" ] }, - "execution_count": 23, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -3014,10 +3620,8 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, + "execution_count": 27, + "metadata": {}, "outputs": [ { "data": { @@ -3025,7 +3629,7 @@ "array(['PR', 'USA'], dtype=object)" ] }, - "execution_count": 24, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -3044,10 +3648,8 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, + "execution_count": 28, + "metadata": {}, "outputs": [ { "data": { @@ -3060,7 +3662,7 @@ "dtype: bool" ] }, - "execution_count": 25, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -3083,15 +3685,26 @@ }, { "cell_type": "code", - "execution_count": 26, - "metadata": { - "collapsed": false - }, + "execution_count": 29, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -3163,7 +3776,7 @@ "4 AL under18 2011 1125763.0 Alabama 52423.0" ] }, - "execution_count": 26, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -3182,10 +3795,8 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, + "execution_count": 30, + "metadata": {}, "outputs": [ { "data": { @@ -3199,7 +3810,7 @@ "dtype: bool" ] }, - "execution_count": 27, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -3217,10 +3828,8 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, + "execution_count": 31, + "metadata": {}, "outputs": [ { "data": { @@ -3228,7 +3837,7 @@ "array(['United States'], dtype=object)" ] }, - "execution_count": 28, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -3247,15 +3856,26 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false - }, + "execution_count": 32, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -3327,7 +3947,7 @@ "4 AL under18 2011 1125763.0 Alabama 52423.0" ] }, - "execution_count": 29, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -3347,15 +3967,26 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 33, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -3427,7 +4058,7 @@ "197 CA total 2010 37333601.0 California 163707.0" ] }, - "execution_count": 30, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -3447,10 +4078,8 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": { - "collapsed": false - }, + "execution_count": 34, + "metadata": {}, "outputs": [], "source": [ "data2010.set_index('state', inplace=True)\n", @@ -3459,10 +4088,8 @@ }, { "cell_type": "code", - "execution_count": 32, - "metadata": { - "collapsed": false - }, + "execution_count": 35, + "metadata": {}, "outputs": [ { "data": { @@ -3476,7 +4103,7 @@ "dtype: float64" ] }, - "execution_count": 32, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -3498,10 +4125,8 @@ }, { "cell_type": "code", - "execution_count": 33, - "metadata": { - "collapsed": false - }, + "execution_count": 36, + "metadata": {}, "outputs": [ { "data": { @@ -3515,7 +4140,7 @@ "dtype: float64" ] }, - "execution_count": 33, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -3539,7 +4164,9 @@ "metadata": {}, "source": [ "\n", - "< [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) | [Contents](Index.ipynb) | [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb) >" + "< [Combining Datasets: Concat and Append](03.06-Concat-And-Append.ipynb) | [Contents](Index.ipynb) | [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb) >\n", + "\n", + "\"Open\n" ] } ], @@ -3560,9 +4187,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.09-Pivot-Tables.ipynb b/notebooks/03.09-Pivot-Tables.ipynb index 2710ff8f2..e26fe7e52 100644 --- a/notebooks/03.09-Pivot-Tables.ipynb +++ b/notebooks/03.09-Pivot-Tables.ipynb @@ -19,6 +19,17 @@ "< [Aggregation and Grouping](03.08-Aggregation-and-Grouping.ipynb) | [Contents](Index.ipynb) | [Vectorized String Operations](03.10-Working-With-Strings.ipynb) >" ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -48,10 +59,8 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, + "execution_count": 2, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -62,15 +71,26 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, + "execution_count": 3, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -195,15 +215,15 @@ "3 1 1 female 35.0 1 0 53.1000 S First \n", "4 0 3 male 35.0 0 0 8.0500 S Third \n", "\n", - " who adult_male deck embark_town alive alone \n", - "0 man True NaN Southampton no False \n", - "1 woman False C Cherbourg yes False \n", - "2 woman False NaN Southampton yes True \n", - "3 woman False C Southampton yes False \n", - "4 man True NaN Southampton no True " + " who adult_male deck embark_town alive alone \n", + "0 man True NaN Southampton no False \n", + "1 woman False C Cherbourg yes False \n", + "2 woman False NaN Southampton yes True \n", + "3 woman False C Southampton yes False \n", + "4 man True NaN Southampton no True " ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -231,15 +251,26 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, + "execution_count": 4, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -271,7 +302,7 @@ "male 0.188908" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -293,15 +324,26 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -341,7 +383,7 @@ "male 0.368852 0.157407 0.135447" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -370,15 +412,26 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 6, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -418,7 +471,7 @@ "male 0.368852 0.157407 0.135447" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -449,15 +502,54 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "count 714.000000\n", + "mean 29.699118\n", + "std 14.526497\n", + "min 0.420000\n", + "25% 20.125000\n", + "50% 28.000000\n", + "75% 38.000000\n", + "max 80.000000\n", + "Name: age, dtype: float64" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "titanic['age'].describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -477,30 +569,42 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
femalefemale(0, 18]0.9090911.0000000.511628
(18, 80]0.9729730.9000000.423729(18, 50]0.9672130.9122810.413793
male(50, 80]1.0000000.6666671.000000
male(0, 18]0.8000000.6000000.215686
(18, 80]0.3750000.0714290.133663(18, 50]0.4428570.0694440.139896
(50, 80]0.1923080.0833330.000000
\n", @@ -510,18 +614,20 @@ "class First Second Third\n", "sex age \n", "female (0, 18] 0.909091 1.000000 0.511628\n", - " (18, 80] 0.972973 0.900000 0.423729\n", + " (18, 50] 0.967213 0.912281 0.413793\n", + " (50, 80] 1.000000 0.666667 1.000000\n", "male (0, 18] 0.800000 0.600000 0.215686\n", - " (18, 80] 0.375000 0.071429 0.133663" + " (18, 50] 0.442857 0.069444 0.139896\n", + " (50, 80] 0.192308 0.083333 0.000000" ] }, - "execution_count": 6, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "age = pd.cut(titanic['age'], [0, 18, 80])\n", + "age = pd.cut(titanic['age'], [0, 18, 50, 80])\n", "titanic.pivot_table('survived', ['sex', age], 'class')" ] }, @@ -534,21 +640,36 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -574,7 +695,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -584,16 +705,25 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -603,37 +733,50 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", "
fare[0, 14.454](-0.001, 14.454](14.454, 512.329]
femalefemale(0, 18]NaN1.0000000.318182
(18, 80](18, 50]NaN0.8800000.4444440.9729730.9142860.9166670.4285710.9672130.9090910.391304
male(50, 80]NaN0.0000001.0000001.0000001.000000NaN
male(0, 18]NaN0.0000000.178571
(18, 80](18, 50]0.00.0980390.1250000.3913040.0303030.0952380.1317370.4696970.0333330.192308
(50, 80]NaN0.1111110.0000000.1923080.000000NaN
\n", "
" ], "text/plain": [ - "fare [0, 14.454] (14.454, 512.329] \\\n", - "class First Second Third First Second \n", - "sex age \n", - "female (0, 18] NaN 1.000000 0.714286 0.909091 1.000000 \n", - " (18, 80] NaN 0.880000 0.444444 0.972973 0.914286 \n", - "male (0, 18] NaN 0.000000 0.260870 0.800000 0.818182 \n", - " (18, 80] 0.0 0.098039 0.125000 0.391304 0.030303 \n", + "fare (-0.001, 14.454] (14.454, 512.329] \\\n", + "class First Second Third First \n", + "sex age \n", + "female (0, 18] NaN 1.000000 0.714286 0.909091 \n", + " (18, 50] NaN 0.916667 0.428571 0.967213 \n", + " (50, 80] NaN 0.000000 1.000000 1.000000 \n", + "male (0, 18] NaN 0.000000 0.260870 0.800000 \n", + " (18, 50] 0.0 0.095238 0.131737 0.469697 \n", + " (50, 80] NaN 0.111111 0.000000 0.192308 \n", "\n", - "fare \n", - "class Third \n", - "sex age \n", - "female (0, 18] 0.318182 \n", - " (18, 80] 0.391304 \n", - "male (0, 18] 0.178571 \n", - " (18, 80] 0.192308 " + "fare \n", + "class Second Third \n", + "sex age \n", + "female (0, 18] 1.000000 0.318182 \n", + " (18, 50] 0.909091 0.391304 \n", + " (50, 80] 1.000000 NaN \n", + "male (0, 18] 0.818182 0.178571 \n", + " (18, 50] 0.033333 0.192308 \n", + " (50, 80] 0.000000 NaN " ] }, - "execution_count": 7, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -675,15 +818,30 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, + "execution_count": 15, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -716,18 +874,18 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", "
106.12579821.97012116.11881091.070.072.0917072
male67.22612719.74178212.66163345.017.047.0451747
\n", @@ -737,18 +895,111 @@ " fare survived \n", "class First Second Third First Second Third\n", "sex \n", - "female 106.125798 21.970121 16.118810 91.0 70.0 72.0\n", - "male 67.226127 19.741782 12.661633 45.0 17.0 47.0" + "female 106.125798 21.970121 16.118810 91 70 72\n", + "male 67.226127 19.741782 12.661633 45 17 47" ] }, - "execution_count": 8, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "titanic.pivot_table(index='sex', columns='class',\n", - " aggfunc={'survived':sum, 'fare':'mean'})" + " aggfunc={'survived':sum, 'fare':'mean'}) # note: sum is a function" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "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", + "
faresurvived
classFirstSecondThirdFirstSecondThird
sex
female106.12579821.97012116.118810917072
male67.22612719.74178212.661633451747
\n", + "
" + ], + "text/plain": [ + " fare survived \n", + "class First Second Third First Second Third\n", + "sex \n", + "female 106.125798 21.970121 16.118810 91 70 72\n", + "male 67.226127 19.741782 12.661633 45 17 47" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "titanic.pivot_table(index='sex', columns='class',\n", + " aggfunc={'survived':'sum', 'fare':'mean'})" ] }, { @@ -770,15 +1021,26 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -830,7 +1092,7 @@ "All 0.629630 0.472826 0.242363 0.383838" ] }, - "execution_count": 9, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -861,9 +1123,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# shell command to download the data:\n", @@ -891,9 +1151,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -984,9 +1242,7 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1066,9 +1322,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1132,9 +1386,7 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')" @@ -1150,9 +1402,7 @@ { "cell_type": "code", "execution_count": 17, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# set 'day' column to integer; it originally was a string due to nulls\n", @@ -1170,9 +1420,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# create a datetime index from the year, month, day\n", @@ -1193,9 +1441,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1231,9 +1477,7 @@ { "cell_type": "code", "execution_count": 20, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1268,9 +1512,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1305,9 +1547,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1366,9 +1606,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.10-Working-With-Strings.ipynb b/notebooks/03.10-Working-With-Strings.ipynb index 1c64eff95..773cc192b 100644 --- a/notebooks/03.10-Working-With-Strings.ipynb +++ b/notebooks/03.10-Working-With-Strings.ipynb @@ -19,6 +19,17 @@ "< [Pivot Tables](03.09-Pivot-Tables.ipynb) | [Contents](Index.ipynb) | [Working with Time Series](03.11-Working-with-Time-Series.ipynb) >" ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -44,12 +55,49 @@ "We saw in previous sections how tools like NumPy and Pandas generalize arithmetic operations so that we can easily and quickly perform the same operation on many array elements. For example:" ] }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "class display(object):\n", + " \"\"\"Display HTML representation of multiple objects\"\"\"\n", + " template = \"\"\"
\n", + "

{0}

{1}\n", + "
\"\"\"\n", + " def __init__(self, *args):\n", + " self.args = args\n", + " \n", + " def _repr_html_(self):\n", + " try:\n", + " res = '\\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res\n", + " \n", + " def __repr__(self):\n", + " try:\n", + " res = '\\n\\n'.join(a + '\\n' + repr(eval(a)) for a in self.args)\n", + " except:\n", + " res = None\n", + " return res" + ] + }, { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -63,7 +111,6 @@ } ], "source": [ - "import numpy as np\n", "x = np.array([2, 3, 5, 7, 11, 13])\n", "x * 2" ] @@ -78,10 +125,8 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, + "execution_count": 3, + "metadata": {}, "outputs": [ { "data": { @@ -89,7 +134,7 @@ "['Peter', 'Paul', 'Mary', 'Guido']" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -109,21 +154,19 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, + "execution_count": 4, + "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'NoneType' object has no attribute 'capitalize'", "output_type": "error", "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'peter'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Paul'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'MARY'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'gUIDO'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcapitalize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'peter'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Paul'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'MARY'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'gUIDO'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcapitalize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'capitalize'" + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;34m'peter'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'Paul'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'MARY'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'gUIDO'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;33m[\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcapitalize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;34m'peter'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'Paul'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'MARY'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'gUIDO'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;33m[\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcapitalize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'capitalize'" ] } ], @@ -142,10 +185,8 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, "outputs": [ { "data": { @@ -158,13 +199,13 @@ "dtype: object" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import pandas as pd\n", + "\n", "names = pd.Series(data)\n", "names" ] @@ -178,10 +219,8 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 6, + "metadata": {}, "outputs": [ { "data": { @@ -194,7 +233,7 @@ "dtype: object" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -210,6 +249,32 @@ "Using tab completion on this ``str`` attribute will list all the vectorized string methods available to Pandas." ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "names.str?" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['__annotations__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__frozen', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_data', '_doc_args', '_freeze', '_get_series_list', '_index', '_inferred_dtype', '_is_categorical', '_is_string', '_name', '_orig', '_parent', '_validate', '_wrap_result', 'capitalize', 'casefold', 'cat', 'center', 'contains', 'count', 'decode', 'encode', 'endswith', 'extract', 'extractall', 'find', 'findall', 'fullmatch', 'get', 'get_dummies', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'islower', 'isnumeric', 'isspace', 'istitle', 'isupper', 'join', 'len', 'ljust', 'lower', 'lstrip', 'match', 'normalize', 'pad', 'partition', 'repeat', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'slice', 'slice_replace', 'split', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'wrap', 'zfill']\n" + ] + } + ], + "source": [ + "print(dir(names.str))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -222,10 +287,8 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, + "execution_count": 11, + "metadata": {}, "outputs": [], "source": [ "monte = pd.Series(['Graham Chapman', 'John Cleese', 'Terry Gilliam',\n", @@ -249,16 +312,15 @@ "|``strip()`` | ``rindex()`` | ``isdigit()`` | ``rsplit()`` | \n", "|``rstrip()`` | ``capitalize()`` | ``isspace()`` | ``partition()`` | \n", "|``lstrip()`` | ``swapcase()`` | ``istitle()`` | ``rpartition()`` |\n", + "|-------------|------------------|------------------|------------------|\n", "\n", "Notice that these have various return values. Some, like ``lower()``, return a series of strings:" ] }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, + "execution_count": 13, + "metadata": {}, "outputs": [ { "data": { @@ -272,7 +334,7 @@ "dtype: object" ] }, - "execution_count": 7, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -290,10 +352,8 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, + "execution_count": 14, + "metadata": {}, "outputs": [ { "data": { @@ -307,7 +367,7 @@ "dtype: int64" ] }, - "execution_count": 8, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -325,10 +385,8 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, + "execution_count": 15, + "metadata": {}, "outputs": [ { "data": { @@ -342,7 +400,7 @@ "dtype: bool" ] }, - "execution_count": 9, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -360,10 +418,8 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { @@ -377,7 +433,7 @@ "dtype: object" ] }, - "execution_count": 10, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -424,9 +480,7 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -449,6 +503,32 @@ "monte.str.extract('([A-Za-z]+)', expand=False)" ] }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 [Graham, Chapman]\n", + "1 [John, Cleese]\n", + "2 [Terry, Gilliam]\n", + "3 [Eric, Idle]\n", + "4 [Terry, Jones]\n", + "5 [Michael, Palin]\n", + "dtype: object" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "monte.str.split('\\s')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -458,14 +538,39 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, + "execution_count": 19, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ + "(0 [Graham Chapman]\n", + " 1 []\n", + " 2 [Terry Gilliam]\n", + " 3 []\n", + " 4 [Terry Jones]\n", + " 5 [Michael Palin]\n", + " dtype: object,\n", + " pandas.core.series.Series)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "text/plain": [ + "monte\n", + "0 Graham Chapman\n", + "1 John Cleese\n", + "2 Terry Gilliam\n", + "3 Eric Idle\n", + "4 Terry Jones\n", + "5 Michael Palin\n", + "dtype: object\n", + "\n", + "x\n", "0 [Graham Chapman]\n", "1 []\n", "2 [Terry Gilliam]\n", @@ -475,15 +580,187 @@ "dtype: object" ] }, - "execution_count": 12, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = monte.str.findall(r'^[^AEIOU].*[^aeiou]$')\n", + "x, type(x)\n", + "display('monte', 'x')" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "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", + "
name
0Graham Chapman
1John Cleese
2Terry Gilliam
3Eric Idle
4Terry Jones
5Michael Palin
\n", + "
" + ], + "text/plain": [ + " name\n", + "0 Graham Chapman\n", + "1 John Cleese\n", + "2 Terry Gilliam\n", + "3 Eric Idle\n", + "4 Terry Jones\n", + "5 Michael Palin" + ] + }, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "monte.str.findall(r'^[^AEIOU].*[^aeiou]$')" + "df = pd.DataFrame(monte, columns=['name'])\n", + "df" ] }, + { + "cell_type": "code", + "execution_count": 25, + "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", + "
namenames
0Graham Chapman[Graham, Chapman]
1John Cleese[John, Cleese]
2Terry Gilliam[Terry, Gilliam]
3Eric Idle[Eric, Idle]
4Terry Jones[Terry, Jones]
5Michael Palin[Michael, Palin]
\n", + "
" + ], + "text/plain": [ + " name names\n", + "0 Graham Chapman [Graham, Chapman]\n", + "1 John Cleese [John, Cleese]\n", + "2 Terry Gilliam [Terry, Gilliam]\n", + "3 Eric Idle [Eric, Idle]\n", + "4 Terry Jones [Terry, Jones]\n", + "5 Michael Palin [Michael, Palin]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df['names'] = df['name'].str.split('\\s')\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -525,14 +802,22 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, + "execution_count": 26, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ + "monte\n", + "0 Graham Chapman\n", + "1 John Cleese\n", + "2 Terry Gilliam\n", + "3 Eric Idle\n", + "4 Terry Jones\n", + "5 Michael Palin\n", + "dtype: object\n", + "\n", + "x\n", "0 Gra\n", "1 Joh\n", "2 Ter\n", @@ -542,13 +827,14 @@ "dtype: object" ] }, - "execution_count": 13, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "monte.str[0:3]" + "x = monte.str[0:3]\n", + "display('monte', 'x')" ] }, { @@ -564,9 +850,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -602,69 +886,80 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, + "execution_count": 27, + "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", "
infonameinfo
0B|C|DGraham ChapmanB|C|D
1B|DJohn CleeseB|D
2A|CTerry GilliamA|C
3B|DEric IdleB|D
4B|CTerry JonesB|C
5B|C|DMichael PalinB|C|D
\n", "
" ], "text/plain": [ - " info name\n", - "0 B|C|D Graham Chapman\n", - "1 B|D John Cleese\n", - "2 A|C Terry Gilliam\n", - "3 B|D Eric Idle\n", - "4 B|C Terry Jones\n", - "5 B|C|D Michael Palin" + " name info\n", + "0 Graham Chapman B|C|D\n", + "1 John Cleese B|D\n", + "2 Terry Gilliam A|C\n", + "3 Eric Idle B|D\n", + "4 Terry Jones B|C\n", + "5 Michael Palin B|C|D" ] }, - "execution_count": 15, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -685,15 +980,26 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": 28, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -761,7 +1067,7 @@ "5 0 1 1 1" ] }, - "execution_count": 16, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -779,6 +1085,13 @@ "We won't dive further into these methods here, but I encourage you to read through [\"Working with Text Data\"](http://pandas.pydata.org/pandas-docs/stable/text.html) in the Pandas online documentation, or to refer to the resources listed in [Further Resources](03.13-Further-Resources.ipynb)." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -795,15 +1108,33 @@ ] }, { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### An update\n", + "\n", + "#### Allrecipes.com\n", + "\n", + "https://www.allrecipes.com/recipe/164254/chinese-mabo-tofu/\n", + "\n", + "#### kaggle - food.com\n", + "\n", + "https://www.kaggle.com/datasets/shuyangli94/food-com-recipes-and-user-interactions\n", + "\n", + "\n", + "#### recipedb\n", + "As of 2022-04-15, https://github.com/fictivekin/openrecipes is no longer maintained.\n", + "\n", + "On 25 November 2020, this article https://academic.oup.com/database/article/doi/10.1093/database/baaa077/6006228\n", + "describes a similar effort at https://cosylab.iiitd.edu.in/recipedb/\n" + ] + }, + { + "cell_type": "raw", + "metadata": {}, "source": [ - "# !curl -O http://openrecipes.s3.amazonaws.com/recipeitems-latest.json.gz\n", - "# !gunzip recipeitems-latest.json.gz" + "!curl -O http://openrecipes.s3.amazonaws.com/recipeitems-latest.json.gz\n", + "!gunzip recipeitems-latest.json.gz" ] }, { @@ -815,26 +1146,210 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, + "execution_count": 38, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "ValueError: Trailing data\n" + " Volume in drive C has no label.\n", + " Volume Serial Number is 8A04-0EBD\n", + "\n", + " Directory of C:\\Users\\w_gon\\projects\\wgong\\DSPG_Data-Science-Play-Ground\\PythonDataScienceHandbook\\notebooks\\data\n", + "\n", + "04/15/2022 05:59 PM 898,015 openrecipes.json\n", + " 1 File(s) 898,015 bytes\n", + " 0 Dir(s) 397,138,731,008 bytes free\n" ] } ], + "source": [ + "!dir data\\openrecipes.json" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How to fix \"Trailing Data\" error\n", + "- https://stackoverflow.com/questions/30088006/loading-a-file-with-more-than-one-line-of-json-into-pandas\n", + "\n", + "add `, lines=True` to read_json() call" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "recipes = pd.read_json(\"data\\\\openrecipes-small.json\", lines=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "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", + "
nameingredientsurlimagecookTimerecipeYielddatePublishedprepTimedescription
0Easter Leftover Sandwich12 whole Hard Boiled Eggs\\n1/2 cup Mayonnaise\\...http://thepioneerwoman.com/cooking/2013/04/eas...http://static.thepioneerwoman.com/cooking/file...PT82013-04-01PT15MGot leftover Easter eggs? Got leftover East...
1Pasta with Pesto Cream Sauce3/4 cups Fresh Basil Leaves\\n1/2 cup Grated Pa...http://thepioneerwoman.com/cooking/2011/06/pas...http://static.thepioneerwoman.com/cooking/file...PT10M82011-06-06PT6MI finally have basil in my garden. Basil I can...
\n", + "
" + ], + "text/plain": [ + " name \\\n", + "0 Easter Leftover Sandwich \n", + "1 Pasta with Pesto Cream Sauce \n", + "\n", + " ingredients \\\n", + "0 12 whole Hard Boiled Eggs\\n1/2 cup Mayonnaise\\... \n", + "1 3/4 cups Fresh Basil Leaves\\n1/2 cup Grated Pa... \n", + "\n", + " url \\\n", + "0 http://thepioneerwoman.com/cooking/2013/04/eas... \n", + "1 http://thepioneerwoman.com/cooking/2011/06/pas... \n", + "\n", + " image cookTime recipeYield \\\n", + "0 http://static.thepioneerwoman.com/cooking/file... PT 8 \n", + "1 http://static.thepioneerwoman.com/cooking/file... PT10M 8 \n", + "\n", + " datePublished prepTime description \n", + "0 2013-04-01 PT15M Got leftover Easter eggs? Got leftover East... \n", + "1 2011-06-06 PT6M I finally have basil in my garden. Basil I can... " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recipes" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], "source": [ "try:\n", - " recipes = pd.read_json('recipeitems-latest.json')\n", + " recipes = pd.read_json('data/openrecipes.json.gz', lines=True)\n", "except ValueError as e:\n", " print(\"ValueError:\", e)" ] }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((1042, 9),\n", + " name \\\n", + " 0 Easter Leftover Sandwich \n", + " 1 Pasta with Pesto Cream Sauce \n", + " 2 Herb Roasted Pork Tenderloin with Preserves \n", + " 3 Chicken Florentine Pasta \n", + " 4 Perfect Iced Coffee \n", + " \n", + " ingredients \\\n", + " 0 12 whole Hard Boiled Eggs\\n1/2 cup Mayonnaise\\... \n", + " 1 3/4 cups Fresh Basil Leaves\\n1/2 cup Grated Pa... \n", + " 2 2 whole Pork Tenderloins\\n Salt And Pepper, to... \n", + " 3 1 pound Penne\\n4 whole Boneless, Skinless Chic... \n", + " 4 1 pound Ground Coffee (good, Rich Roast)\\n8 qu... \n", + " \n", + " url \\\n", + " 0 http://thepioneerwoman.com/cooking/2013/04/eas... \n", + " 1 http://thepioneerwoman.com/cooking/2011/06/pas... \n", + " 2 http://thepioneerwoman.com/cooking/2011/09/her... \n", + " 3 http://thepioneerwoman.com/cooking/2012/04/chi... \n", + " 4 http://thepioneerwoman.com/cooking/2011/06/per... \n", + " \n", + " image cookTime recipeYield \\\n", + " 0 http://static.thepioneerwoman.com/cooking/file... PT 8 \n", + " 1 http://static.thepioneerwoman.com/cooking/file... PT10M 8 \n", + " 2 http://static.thepioneerwoman.com/cooking/file... PT15M 12 \n", + " 3 http://static.thepioneerwoman.com/cooking/file... PT20M 10 \n", + " 4 http://static.thepioneerwoman.com/cooking/file... PT 24 \n", + " \n", + " datePublished prepTime description \n", + " 0 2013-04-01 PT15M Got leftover Easter eggs? Got leftover East... \n", + " 1 2011-06-06 PT6M I finally have basil in my garden. Basil I can... \n", + " 2 2011-09-15 PT5M This was yummy. And easy. And pretty! And it t... \n", + " 3 2012-04-23 PT10M I made this for a late lunch Saturday, and it ... \n", + " 4 2011-06-13 PT8H Iced coffee is my life. When I wake up, often ... )" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recipes.shape, recipes.head(5)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -847,9 +1362,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -897,9 +1410,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -927,9 +1438,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -975,9 +1484,7 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1014,9 +1521,7 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1044,18 +1549,16 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, + "execution_count": 10, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "3524" + "11" ] }, - "execution_count": 25, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -1073,18 +1576,16 @@ }, { "cell_type": "code", - "execution_count": 26, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10526" + "79" ] }, - "execution_count": 26, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1103,9 +1604,7 @@ { "cell_type": "code", "execution_count": 27, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1144,10 +1643,8 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": true - }, + "execution_count": 12, + "metadata": {}, "outputs": [], "source": [ "spice_list = ['salt', 'pepper', 'oregano', 'sage', 'parsley',\n", @@ -1163,29 +1660,40 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false - }, + "execution_count": 13, + "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", @@ -1197,7 +1705,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1217,14 +1725,14 @@ " \n", " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1259,15 +1767,22 @@ "" ], "text/plain": [ - " cumin oregano paprika parsley pepper rosemary sage salt tarragon thyme\n", - "0 False False False False False False True False False False\n", - "1 False False False False False False False False False False\n", - "2 True False False False True False False True False False\n", - "3 False False False False False False False False False False\n", - "4 False False False False False False False False False False" + " salt pepper oregano sage parsley rosemary tarragon thyme paprika \\\n", + "0 False False False False False False False False False \n", + "1 False False False False False False False False False \n", + "2 False False False False False False False False False \n", + "3 False False False False False False False False False \n", + "4 False False False False False False False False False \n", + "\n", + " cumin \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False " ] }, - "execution_count": 29, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -1289,18 +1804,16 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 14, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10" + "0" ] }, - "execution_count": 30, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -1320,9 +1833,7 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1394,9 +1905,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/03.11-Working-with-Time-Series.ipynb b/notebooks/03.11-Working-with-Time-Series.ipynb index 7fb30aa85..cfed761f3 100644 --- a/notebooks/03.11-Working-with-Time-Series.ipynb +++ b/notebooks/03.11-Working-with-Time-Series.ipynb @@ -19,6 +19,17 @@ "< [Vectorized String Operations](03.10-Working-With-Strings.ipynb) | [Contents](Index.ipynb) | [High-Performance Pandas: eval() and query()](03.12-Performance-Eval-and-Query.ipynb) >" ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# This allows multiple outputs from a single jupyter notebook cell:\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -61,15 +72,22 @@ "\n", "Python's basic objects for working with dates and times reside in the built-in ``datetime`` module.\n", "Along with the third-party ``dateutil`` module, you can use it to quickly perform a host of useful functionalities on dates and times.\n", - "For example, you can manually build a date using the ``datetime`` type:" + "For example, you can manually build a date using the ``datetime`` type:\n", + "\n", + "\n", + "#### dateparser\n", + "\n", + "- https://dateparser.readthedocs.io/en/latest/\n", + "\n", + "a pretty robust pkg dealing with date parsing\n", + "\n", + "see example at https://github.com/wgong/py4kids/blob/master/lesson-99-misc/find_dates.py" ] }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, + "execution_count": 2, + "metadata": {}, "outputs": [ { "data": { @@ -77,7 +95,7 @@ "datetime.datetime(2015, 7, 4, 0, 0)" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -96,10 +114,8 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, + "execution_count": 3, + "metadata": {}, "outputs": [ { "data": { @@ -107,7 +123,7 @@ "datetime.datetime(2015, 7, 4, 0, 0)" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -118,21 +134,55 @@ "date" ] }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import dateparser as dp\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\dateparser\\date_parser.py:35: PytzUsageWarning: The localize method is no longer necessary, as this time zone supports the fold attribute (PEP 495). For more details on migrating to a PEP 495-compliant implementation, see https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html\n", + " date_obj = stz.localize(date_obj)\n" + ] + }, + { + "data": { + "text/plain": [ + "datetime.datetime(2015, 7, 4, 0, 0)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "date = dp.parse(\"4th of July, 2015\")\n", + "date" + ] + }, { "cell_type": "markdown", - "metadata": { - "collapsed": false - }, + "metadata": {}, "source": [ "Once you have a ``datetime`` object, you can do things like printing the day of the week:" ] }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, + "execution_count": 6, + "metadata": {}, "outputs": [ { "data": { @@ -140,7 +190,7 @@ "'Saturday'" ] }, - "execution_count": 3, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -175,18 +225,16 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 7, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array(datetime.date(2015, 7, 4), dtype='datetime64[D]')" + "array('2015-07-04', dtype='datetime64[D]')" ] }, - "execution_count": 4, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -206,20 +254,19 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 8, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['2015-07-04', '2015-07-05', '2015-07-06', '2015-07-07',\n", " '2015-07-08', '2015-07-09', '2015-07-10', '2015-07-11',\n", - " '2015-07-12', '2015-07-13', '2015-07-14', '2015-07-15'], dtype='datetime64[D]')" + " '2015-07-12', '2015-07-13', '2015-07-14', '2015-07-15'],\n", + " dtype='datetime64[D]')" ] }, - "execution_count": 5, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -245,10 +292,8 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, + "execution_count": 9, + "metadata": {}, "outputs": [ { "data": { @@ -256,7 +301,7 @@ "numpy.datetime64('2015-07-04')" ] }, - "execution_count": 6, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -274,10 +319,8 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, + "execution_count": 10, + "metadata": {}, "outputs": [ { "data": { @@ -285,7 +328,7 @@ "numpy.datetime64('2015-07-04T12:00')" ] }, - "execution_count": 7, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -304,10 +347,8 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { @@ -315,7 +356,7 @@ "numpy.datetime64('2015-07-04T12:59:59.500000000')" ] }, - "execution_count": 8, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -377,10 +418,8 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, + "execution_count": 12, + "metadata": {}, "outputs": [ { "data": { @@ -388,7 +427,7 @@ "Timestamp('2015-07-04 00:00:00')" ] }, - "execution_count": 9, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -401,10 +440,8 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, + "execution_count": 13, + "metadata": {}, "outputs": [ { "data": { @@ -412,7 +449,7 @@ "'Saturday'" ] }, - "execution_count": 10, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -430,10 +467,8 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, + "execution_count": 14, + "metadata": {}, "outputs": [ { "data": { @@ -444,7 +479,7 @@ " dtype='datetime64[ns]', freq=None)" ] }, - "execution_count": 11, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -472,10 +507,8 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, + "execution_count": 15, + "metadata": {}, "outputs": [ { "data": { @@ -487,7 +520,7 @@ "dtype: int64" ] }, - "execution_count": 12, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -508,10 +541,8 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { @@ -522,7 +553,7 @@ "dtype: int64" ] }, - "execution_count": 13, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -540,10 +571,8 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, + "execution_count": 17, + "metadata": {}, "outputs": [ { "data": { @@ -553,7 +582,7 @@ "dtype: int64" ] }, - "execution_count": 14, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -594,10 +623,8 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, + "execution_count": 18, + "metadata": {}, "outputs": [ { "data": { @@ -607,7 +634,7 @@ " dtype='datetime64[ns]', freq=None)" ] }, - "execution_count": 15, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -627,20 +654,18 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": 19, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PeriodIndex(['2015-07-03', '2015-07-04', '2015-07-06', '2015-07-07',\n", " '2015-07-08'],\n", - " dtype='int64', freq='D')" + " dtype='period[D]')" ] }, - "execution_count": 16, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -658,10 +683,8 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, + "execution_count": 20, + "metadata": {}, "outputs": [ { "data": { @@ -669,7 +692,7 @@ "TimedeltaIndex(['0 days', '1 days', '3 days', '4 days', '5 days'], dtype='timedelta64[ns]', freq=None)" ] }, - "execution_count": 17, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -692,10 +715,8 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, + "execution_count": 21, + "metadata": {}, "outputs": [ { "data": { @@ -705,7 +726,7 @@ " dtype='datetime64[ns]', freq='D')" ] }, - "execution_count": 18, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -723,10 +744,8 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, + "execution_count": 22, + "metadata": {}, "outputs": [ { "data": { @@ -736,7 +755,7 @@ " dtype='datetime64[ns]', freq='D')" ] }, - "execution_count": 19, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -755,10 +774,8 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, + "execution_count": 23, + "metadata": {}, "outputs": [ { "data": { @@ -770,7 +787,7 @@ " dtype='datetime64[ns]', freq='H')" ] }, - "execution_count": 20, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -789,20 +806,18 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": 24, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PeriodIndex(['2015-07', '2015-08', '2015-09', '2015-10', '2015-11', '2015-12',\n", " '2016-01', '2016-02'],\n", - " dtype='int64', freq='M')" + " dtype='period[M]')" ] }, - "execution_count": 21, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -820,20 +835,20 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, + "execution_count": 25, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "TimedeltaIndex(['00:00:00', '01:00:00', '02:00:00', '03:00:00', '04:00:00',\n", - " '05:00:00', '06:00:00', '07:00:00', '08:00:00', '09:00:00'],\n", + "TimedeltaIndex(['0 days 00:00:00', '0 days 01:00:00', '0 days 02:00:00',\n", + " '0 days 03:00:00', '0 days 04:00:00', '0 days 05:00:00',\n", + " '0 days 06:00:00', '0 days 07:00:00', '0 days 08:00:00',\n", + " '0 days 09:00:00'],\n", " dtype='timedelta64[ns]', freq='H')" ] }, - "execution_count": 22, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -917,20 +932,19 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, + "execution_count": 26, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "TimedeltaIndex(['00:00:00', '02:30:00', '05:00:00', '07:30:00', '10:00:00',\n", - " '12:30:00', '15:00:00', '17:30:00', '20:00:00'],\n", + "TimedeltaIndex(['0 days 00:00:00', '0 days 02:30:00', '0 days 05:00:00',\n", + " '0 days 07:30:00', '0 days 10:00:00', '0 days 12:30:00',\n", + " '0 days 15:00:00', '0 days 17:30:00', '0 days 20:00:00'],\n", " dtype='timedelta64[ns]', freq='150T')" ] }, - "execution_count": 23, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -949,10 +963,8 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, + "execution_count": 27, + "metadata": {}, "outputs": [ { "data": { @@ -962,7 +974,7 @@ " dtype='datetime64[ns]', freq='B')" ] }, - "execution_count": 24, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -994,26 +1006,86 @@ "Here we will load Google's closing price history:" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### pandas-datareader\n", + "https://pypi.org/project/pandas-datareader/" + ] + }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting pandas-datareader\n", + " Using cached pandas_datareader-0.10.0-py3-none-any.whl (109 kB)\n", + "Requirement already satisfied: requests>=2.19.0 in c:\\anaconda3\\lib\\site-packages (from pandas-datareader) (2.27.1)\n", + "Requirement already satisfied: pandas>=0.23 in c:\\anaconda3\\lib\\site-packages (from pandas-datareader) (1.3.3)\n", + "Requirement already satisfied: lxml in c:\\anaconda3\\lib\\site-packages (from pandas-datareader) (4.6.1)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\anaconda3\\lib\\site-packages (from requests>=2.19.0->pandas-datareader) (2020.6.20)\n", + "Requirement already satisfied: idna<4,>=2.5; python_version >= \"3\" in c:\\anaconda3\\lib\\site-packages (from requests>=2.19.0->pandas-datareader) (2.10)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0; python_version >= \"3\" in c:\\anaconda3\\lib\\site-packages (from requests>=2.19.0->pandas-datareader) (2.0.12)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\\anaconda3\\lib\\site-packages (from requests>=2.19.0->pandas-datareader) (1.25.11)\n", + "Requirement already satisfied: numpy>=1.17.3 in c:\\anaconda3\\lib\\site-packages (from pandas>=0.23->pandas-datareader) (1.21.2)\n", + "Requirement already satisfied: python-dateutil>=2.7.3 in c:\\anaconda3\\lib\\site-packages (from pandas>=0.23->pandas-datareader) (2.8.1)\n", + "Requirement already satisfied: pytz>=2017.3 in c:\\anaconda3\\lib\\site-packages (from pandas>=0.23->pandas-datareader) (2020.1)\n", + "Requirement already satisfied: six>=1.5 in c:\\anaconda3\\lib\\site-packages (from python-dateutil>=2.7.3->pandas>=0.23->pandas-datareader) (1.15.0)\n", + "Installing collected packages: pandas-datareader\n", + "Successfully installed pandas-datareader-0.10.0\n" + ] + } + ], + "source": [ + "!pip install pandas-datareader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pandas_datareader import data" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
cuminsaltpepperoreganopaprikasageparsleypepperrosemarysagesalttarragonthymepaprikacumin
FalseFalseFalseTrueFalseFalseFalseFalse
2TrueFalseFalseFalseTrueFalseFalseTrueFalseFalseFalseFalseFalse
\n", " \n", " \n", " \n", - " \n", " \n", " \n", + " \n", " \n", " \n", + " \n", " \n", " \n", " \n", @@ -1022,76 +1094,258 @@ " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
OpenHighLowOpenCloseVolumeAdj Close
Date
2004-08-1949.9651.9847.9350.12NaN51.83570947.80083149.81329049.98265544871361.049.982655
2004-08-2050.6954.4950.2054.10NaN54.33633450.06235550.31640253.95277022942874.053.952770
2004-08-2355.3256.6854.4754.65NaN56.52811854.32138855.16821754.49573518342897.054.495735
2004-08-2455.5655.7451.7352.38NaN55.59162951.59162155.41230052.23919715319808.052.239197
2004-08-2552.4353.9551.8952.95NaN53.79835151.74604452.28402752.8020869232276.052.802086
\n", "
" ], "text/plain": [ - " Open High Low Close Volume\n", - "Date \n", - "2004-08-19 49.96 51.98 47.93 50.12 NaN\n", - "2004-08-20 50.69 54.49 50.20 54.10 NaN\n", - "2004-08-23 55.32 56.68 54.47 54.65 NaN\n", - "2004-08-24 55.56 55.74 51.73 52.38 NaN\n", - "2004-08-25 52.43 53.95 51.89 52.95 NaN" + " High Low Open Close Volume Adj Close\n", + "Date \n", + "2004-08-19 51.835709 47.800831 49.813290 49.982655 44871361.0 49.982655\n", + "2004-08-20 54.336334 50.062355 50.316402 53.952770 22942874.0 53.952770\n", + "2004-08-23 56.528118 54.321388 55.168217 54.495735 18342897.0 54.495735\n", + "2004-08-24 55.591629 51.591621 55.412300 52.239197 15319808.0 52.239197\n", + "2004-08-25 53.798351 51.746044 52.284027 52.802086 9232276.0 52.802086" ] }, - "execution_count": 25, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from pandas_datareader import data\n", - "\n", "goog = data.DataReader('GOOG', start='2004', end='2016',\n", - " data_source='google')\n", + " data_source='yahoo')\n", + "# NotImplementedError: data_source='google' is not implemented\n", "goog.head()" ] }, + { + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HighLowOpenCloseVolumeAdj Close
Date
2021-10-1131.09000030.51000030.70999930.58000017432600.030.054453
2021-10-1231.26000030.54999930.79999931.13999925183500.030.604828
2021-10-1332.32000031.38999931.43000032.15000236491500.031.597471
2021-10-1432.93000032.41000032.59999832.84999825068100.032.285439
2021-10-1532.73000031.87999932.15000232.52000019730700.031.961113
.....................
2022-04-0839.81000138.90000238.93000039.66999821648500.039.669998
2022-04-1140.38000139.00000040.20999939.45000120697500.039.450001
2022-04-1240.52999939.45000140.00000039.79999922313700.039.799999
2022-04-1340.88000139.98000040.23000040.68999922805800.040.689999
2022-04-1440.95000140.16000040.52000040.86000121680800.040.860001
\n", + "

130 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " High Low Open Close Volume Adj Close\n", + "Date \n", + "2021-10-11 31.090000 30.510000 30.709999 30.580000 17432600.0 30.054453\n", + "2021-10-12 31.260000 30.549999 30.799999 31.139999 25183500.0 30.604828\n", + "2021-10-13 32.320000 31.389999 31.430000 32.150002 36491500.0 31.597471\n", + "2021-10-14 32.930000 32.410000 32.599998 32.849998 25068100.0 32.285439\n", + "2021-10-15 32.730000 31.879999 32.150002 32.520000 19730700.0 31.961113\n", + "... ... ... ... ... ... ...\n", + "2022-04-08 39.810001 38.900002 38.930000 39.669998 21648500.0 39.669998\n", + "2022-04-11 40.380001 39.000000 40.209999 39.450001 20697500.0 39.450001\n", + "2022-04-12 40.529999 39.450001 40.000000 39.799999 22313700.0 39.799999\n", + "2022-04-13 40.880001 39.980000 40.230000 40.689999 22805800.0 40.689999\n", + "2022-04-14 40.950001 40.160000 40.520000 40.860001 21680800.0 40.860001\n", + "\n", + "[130 rows x 6 columns]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gdx = data.DataReader('GDX', start='2021-10-10', end='2023-01-01',\n", + " data_source='yahoo')\n", + "gdx" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -1101,10 +1355,8 @@ }, { "cell_type": "code", - "execution_count": 26, - "metadata": { - "collapsed": true - }, + "execution_count": 34, + "metadata": {}, "outputs": [], "source": [ "goog = goog['Close']" @@ -1119,10 +1371,8 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, + "execution_count": 35, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -1132,16 +1382,14 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, + "execution_count": 36, + "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeQAAAFRCAYAAAClqd4/AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xt8U/X9P/BXrm3TpFfKHVoo5dpCoQULFUTnBa/z1k1Q\ntim6gc6pdU50OHRz8z42N6/z9rNeAKc4p191IiAKyh3KtVwKFFoovbdJ2jRNzu+PJCc5uSdt07R9\nPR+PPZacc5J8OK1953N7v2WCIAggIiKiHiXv6QYQERERAzIREVFUYEAmIiKKAgzIREREUYABmYiI\nKAowIBMREUUBZaALOjo68OCDD6KyshJKpRJ/+tOfoFAosHTpUsjlcmRlZWH58uUAgNWrV2PVqlVQ\nqVRYvHgx5s6d293tJyIi6hMCBuRvvvkGVqsVK1euxObNm7FixQqYzWYUFxcjPz8fy5cvx9q1a5Gb\nm4uSkhKsWbMGbW1tmD9/PgoLC6FSqSLx7yAiIurVAg5ZZ2RkwGKxQBAEtLS0QKlU4sCBA8jPzwcA\nzJkzB5s3b0ZpaSny8vKgVCqh1WqRkZGBsrKybv8HEBER9QUBe8jx8fE4ffo05s2bh8bGRrz88svY\nvn275Lxer4fBYIBOpxOPazQatLS0dE+riYiI+piAAfmtt97C7Nmzcd9996G6uhoLFy6E2WwWzxsM\nBiQkJECr1UKv13scJyIiosACDlknJiZCq9UCAHQ6HTo6OjBx4kRs3boVALBx40bk5eUhJycHO3bs\nQHt7O1paWlBeXo6srCy/793RYemCfwIREVHvJwtUXMJoNOLhhx9GTU0NOjo68POf/xyTJk3CsmXL\nYDabkZmZiccffxwymQwffPABVq1aBUEQsGTJElx88cV+P7ymJvwh7bQ0Xade31/xvoWP9y48vG/h\n470LTzTft7Q0nc9zAQNyd2JAjjzet/Dx3oWH9y18vHfhieb75i8gMzEIERFRFGBAJiIiigIMyERE\nRFGAAZmIiCgCLFar3/MMyERERBHwjw/3+j3PgExERBQBpcfq/J5nQCYiIooCDMhERETd5Kttp3Db\nk+tw4mxzwGsZkImIiLrJ+18fAQD88a3tAa5kQCYiIooKDMhERETdoNnQHtL1DMhERETd4KWP94V0\nPQMyERFRNyg71RjS9QzIREREUYABmYiIKAowIBMREXWDlISYkK5nQCYiIuoG9c2mkK5nQCYiIupi\nHRb/lZ28UXZDO4iIiPotQRDw5Ls7xedP/qoAn35/EnOmDPX7OgZkIiKiLvRt6RmUV9lyV0/JTMXA\nZA1uu2JCwNdxyJqIiKgLlVU49x9XnNMH/ToGZCIioi4klzkfN7QEv7CLAZmIiCgKMCATERF1IX2r\nWXx85cz0oF/HgExERNSF9hyrEx8naYNPDsKATERE1EX2H6+XPB+fnhz0a7ntiYiIqIt8sOGo+HjF\n3ecjMV4d9GsDBuQ1a9bgo48+gkwmg8lkwqFDh/Duu+/iL3/5C+RyObKysrB8+XIAwOrVq7Fq1Sqo\nVCosXrwYc+fODf1fQ0RE1EtVVDu3OYUSjIEgAvJ1112H6667DgDwxz/+ETfeeCNeeOEFFBcXIz8/\nH8uXL8fatWuRm5uLkpISrFmzBm1tbZg/fz4KCwuhUqlC/OcQERH1Tgq5DBargBvnZob82qDnkPfu\n3YujR4+iqKgI+/fvR35+PgBgzpw52Lx5M0pLS5GXlwelUgmtVouMjAyUlZWF3CAiIqLeauyIJADA\npdNHhPzaoAPyq6++irvvvtvjeHx8PPR6PQwGA3Q6nXhco9GgpaUl5AYRERH1VvpWM2LVCigVoa+Z\nDmpRV0tLC06cOIHp06cDAORy5wcZDAYkJCRAq9VCr9d7HPcnOVkDpVIRcqMd0tJ0gS8iD7xv4eO9\nCw/vW/h478LTU/dNJpdBpVSE9flBBeRt27ahoKBAfD5hwgRs27YN06dPx8aNG1FQUICcnBysWLEC\n7e3tMJlMKC8vR1ZWlt/3bWgwhtxgh7Q0HWpq2AMPFe9b+HjvwsP7Fj7eu/D05H0zmy0QBMHn5/sL\n1EEF5OPHj2PECOd4+IMPPohHHnkEZrMZmZmZmDdvHmQyGRYuXIgFCxZAEAQUFxdDrQ5thRkREVFv\n55rLOhRBBeRFixZJnmdkZKCkpMTjuqKiIhQVFYXXEiIiol7OKgAyWXgRmZm6iIiIuoggCECYPWQG\nZCIioq4iAHL2kImIiHqWVRDCfi0DMhERURcKd1EXAzIREZEfgiDgdI3eNj8cxLVc1EVERNQNvtt7\nBn94fSs++/5kwGvDH7BmQCYiIvLrcEUjAGD9rsqA1wqdWNTFeshERER+JCfEAgAaWkx+r2vUmwJe\n4w97yERERH6k6GIkz80dFpg7rB7XrVp3tFOfwx4yERGRH66Vm1avP4ovtlQAAN5YepHkurP14ddn\nANhDJiIi8ktwWarlCMbedHjpNYeCAZmIiMifIJdOm8yWTn0MAzIREZEfrvF4cmaq87jbvuTaprZO\nfQ4DMhERUZCsVmcQtlg7s+vYEwMyERFRkBr1zm1NFoszIO8+Utvp9+YqayIiIj9ch6ZP1xjEx1ZB\nwIbdldh9pBalx+o6/TkMyERERH74Gpi2CgLe/qLM4/iVM9PD+hwGZCIiIn98ROQn393pceyB+VMx\nIT05rI/hHDIREZEfvnrIlS7D1wAQH6sMOxgDDMhERET+BVF2EQBS7Tmvw8WATERE1AU0sZ2bBWZA\nJiIi8sO9fzw1a4DX6zSxqk59DgMyERGRH64j1oNTNIhVK7xep1Z2LqQyIBMREQVh0qgU/PmO83wu\n8lIyIBMREXUfR2KQC6YMhUwm83mdSsGATERE1G08esQ+usiqTvaQg1oS9uqrr2LdunUwm81YsGAB\npk+fjqVLl0IulyMrKwvLly8HAKxevRqrVq2CSqXC4sWLMXfu3E41joiIeo9mYzsamk0YlBKHWHXf\nyzvlp3MMAFB2socc8I5t3boVu3btwsqVK2E0GvHGG2/giSeeQHFxMfLz87F8+XKsXbsWubm5KCkp\nwZo1a9DW1ob58+ejsLAQKlXnVp0REVHv8OKafTh8qhHD07T446IZPd2criP2iG0R2Vfg7WwPOeCr\nv/vuO4wdOxZ33nknlixZgrlz5+LAgQPIz88HAMyZMwebN29GaWkp8vLyoFQqodVqkZGRgbIyzxyf\nRETU9xw+1YjDpxoBAKdr9Fixeo+kVGFv5vhXOHrIvgKvPEAPOpCAPeSGhgZUVVXhlVdewalTp7Bk\nyRJYrVbxfHx8PPR6PQwGA3Q6nXhco9GgpaWlc60jIqJewT2v897yOhw53YhxI8NPJRk17Iu6HPHW\nVw+5w9K5LyABA3JSUhIyMzOhVCoxatQoxMTEoLq6WjxvMBiQkJAArVYLvV7vcZyIiPq2VlOH9+Pt\nlgi3pHu4jVh79JCVChk6LAI6LFZ0RsCAnJeXh5KSEvziF79AdXU1WltbUVBQgK1bt2LGjBnYuHEj\nCgoKkJOTgxUrVqC9vR0mkwnl5eXIysry+97JyRoold43WAcjLU0X+CLywPsWPt678PC+ha833Luq\nWmdnbNr4gdh56BwAIE6jDrr95g4L3v3iEKaOG4gpWWmSc6VHa3CqWo8rC0cF3aauvG/x8TEAgKRE\nDdLSdEh0yVk9N284tuw7gw6LBaoYZac+N2BAnjt3LrZv344bb7wRgiDg0UcfxbBhw7Bs2TKYzWZk\nZmZi3rx5kMlkWLhwIRYsWABBEFBcXAy1Wu33vRsajGE3PC1Nh5oaDomHivctfLx34eF9C19vuXef\nf3ccADAkVYNrZ2WIAbmu3hB0+0v+V4b1Oyvx4fqjeGPpRZJzv39pMwAge2RSUPmiu/q+6fUmAEBT\nUytqalrQbjKL526amwlzewc27T2LeJUi4Of6C9hBrUv/7W9/63GspKTE41hRURGKioqCeUsiIuoD\napta8bE9ICsVcqhUzuHcVlPwQ9bf7qkSHzcb25GgsXXojp9pFo836k2dLuDQKY4ha5c5ZLVKgaK5\nY5A5LBGzJg3u1NszMQgREYXtiXeci7muPX8U1C7TkIY2s7eXeJUxxLnm6MutFdh/vB7V9Ub86f9t\nF49/W1rl7aXdToB0UZf7HHJCvBpzc4dBrQp/ChYIsodMRETkTUOLSXwsk8skwUrfGjggWwUBK9ce\nwdHTTeKxz3+owOc/VHhc++XWU/jpRf7XJnUL+6oux7anzuas9oU9ZCIiCovrcDIAZI9KgTZOhcvP\nGwkAMAQRkPccqcXaHaclxwalaLqukV3AuZnJFpE7m7PaFwZkIiIKi+twMuDcn3t1YQYA4Pv91e4v\n8eAejAFIcl246+zWonA4iks4esiTMwdgQGIsbrtiQpd+DgMyERGF7Eydwee5mBDmUg+ebPA4VtPY\n5vP6h1/9Iej3dldVaxCziYXCUQ9Zbo/Imlglnl4yC+dPHhJ2W7xhQCYiopBt3ON7gZVMJoM2ThUw\nMIeTWrO2yXewDmTZa1vw5Ls7xR5vsBztlHc2N2YADMhERBSyXUdq/Z5P1sXAZLZIFmu5s/gZmnYV\n77bVqcXYHtTrXJk7nFuwdpTV4JNNx4N+bYc9ICsYkImIKJoY28w419Dq9xrHfPJf3tnhca7Z2A5z\nh8Uj9/OfvFSI0sap8Pw9s5E9OkU8Zu4IfR65xehcYPbix/vw8bfH0dbuPeWnO/aQiYgoKrV5yVGd\nPliagcq1dnCdyzBzi7Ed9z7/Hf7x4V5xW1Tm0AS8sfQiDBkQL3mPhxfm4U+3nweZTIafXTauU212\nDcgO5g4rztQZ8Nhb21Bd7ztzpJU9ZCIiikbeikYU/2SK5LlrL/bv/94jPnbMAe87Xo9H39wGwLlf\nWS6TBrwxwxKRGG/L2DUgMU48bglj7tnbMLfJbME7/zuMk2db8Obnh3y+9tS5Fq/t62oMyEREFDR9\nqxmPvLbF43h8nEry/NQ5Z8GJM3XO3qdr9i5HlajL7PuWAeC1312IwuzBWHjpWI/PmDbWVnTC2NaB\nv32wB2UVniu0ffHWQ243W8X5aX/z0vtP2D4nnC8CoWBAJiKioP3m79+KjwclO3ut/nqPFquA+mZb\nz7hJ7xn4UnQxzveRy7Doqom4cNpwj+uStbbrSsvrUHqsDk+9tyvoduu9pPE0mS3Q2nNm+8sqNmKg\nFgAwzG1IvasxIBMRUVhyMlN9nrvrumzJ8+/2ngEANBs8A3JaUpzHMW8UClvQD2cut93sOcxe09gK\nrb1n760H7eC4xvH53YUBmYiIguKeJWuyn4CcN26g1+MtXnqiOo3/Ur0OjoDoGOoGgO/3nQ34unMN\nRsmwucPL/9kPdRB5qS0RWtTF4hJERBQURy8ye3QKrikchcyhCUjWxSB7VEqAVzp566nGqoPL7KWU\n24LnWZcV0f/69ABmZvsve7j0Fd/ZvYJJTmKxWqGQyyDr5kVdDMhERBQUo30edkBiHMYMSwQAPHdX\nYVCvdYQyk5eArAyyWIPS3kPeUVYjOW4VhKBXQKcP0iFRq0bpsToMSo6D2a3XLwiCR+A1d1iDbmNn\ncMiaiIgCMndY8MzK3QAATUz4fbl2sy0Aui4IC5avVJy3P7Ueu71kDms2tEsydAHA3Tfk4N6iKUjS\nqlHd0IqtB50FML7adgqLnlqPTXvPwNBmxukaPc41tqKt3YLYmM7VOg4Ge8hERBTQnqN14oKsuE4E\nJ0cP+Q+/mI6axlaPHqo//uaan/+wFG8svUh8XtvYit+9/L3HPHes2hb2mg223r5rIYv3vz4CAHj9\ns4MYlKIRk4XoNCpxYVd3Yg+ZiIgCatSbxMfBzqVenO/cunT8jC25hmMOWa2SY+QgHTKHJgbdBtdV\nzsm6GMyZIq22dPxMM1pNHbBaBdTYE5CUHquTXOOYr7YGKDDhmrmr1WQRA3l3YkAmIqKAKmud5RZd\ng7M/1xSOEh/vPlqLrQercaiiETIACnno4UflMo+bNy4N2aOkvd8n392Ju1ZsxJuf7ve5ItqRj/qC\n3KFBf26HxQpNBIasGZCJiMivr3ecxje7neUWb5iTGdTr3IPiy//ZDwAIN99V9mhnAFYrFcgfPxD3\n/zRXPOZI1/nxN8c8tmi5CzU3dmwn5s2DxYBMRER+ffjNMfHx8DQtYoLcphSrVuDCacO6rB0qlz3D\njv3Dk0alYEJ6sse1xjZpJafJmal49s5Z4nOZTOY1PeflBSM9jgFAbIDazl2BAZmIiPzKHJogPv6j\nlxKJvtiCXueqNPmidgmQjtSWrk6cbZE8//m88UhJiJUcG5Si8Xhd0dwxWOil91zjUrGquzAgExGR\nXyb7VqVnlswKcKV3w9OkATNB0/kVyzqX97hshmev1rW4BWBbBOYuY7AOCrkMVxSkI0GjwnWzbXPe\nF04dhld+OxeLfzxJvPbwqcZOtzkQbnsiIiIPtY2tqG5sxZAUDY6faUZqQgxSE2MDv9AL9xzQU8YM\n6HT7XANysi4G2aNTsK+8XjxW3+Ls0V43Z7TX99DEqvCv310IALhxrnReXKWUY5jLF4kkbXDpPTuD\nAZmIiCSMbR343cvfS47VNQe3stqbAQmxOOkyhOxtSDhU7nuSE92e17u0N32Q55B2MIYNiMfMSYPw\n/f5qjA5he1a4GJCJiEjisx9OdOn7zTtvJHYcdqa77Io0lO6JOkYM0gEuhSZcC1BYg8894uHWKyYg\nY0gCZk8eEvjiTgoqIF9//fXQam3fMIYPH47Fixdj6dKlkMvlyMrKwvLlywEAq1evxqpVq6BSqbB4\n8WLMnTu32xpORETdo9XkmW86lAIS7jKHJeLWy8fjzc8PdaZZEu4BOc7Pym8hQBIQf5QKOS7JHxH2\n60P6rEAXtLfbUqW9/fbb4rElS5aguLgY+fn5WL58OdauXYvc3FyUlJRgzZo1aGtrw/z581FYWAiV\nqvvTjRERUddReqn7e+sVEzr1nrlZAzByhxY3XhjcHmZfHr/9PNQ2tSHObV+wv33H471si4pGAQPy\noUOHYDQasWjRIlgsFtx33304cOAA8vPzAQBz5szBpk2bIJfLkZeXB6VSCa1Wi4yMDJSVlSE7OzvA\nJxARUTRZu/205PnApDivq5RDodOo8ehtwW+Z8mXogHgMHRDvcdxs8d4LfvbOWR7BO1oFbGVsbCwW\nLVqEoqIinDhxAnfccYek+x8fHw+9Xg+DwQCdTice12g0aGlp8faWRETUiyy5Nvo7Vu5VnQAgb2ya\nx97jaBYwIGdkZCA9PV18nJSUhAMHDojnDQYDEhISoNVqodfrPY4TEVHv9NxdhYiLUUSksEJnWbz0\nkOPjor/drgK29sMPP8Thw4exfPlyVFdXQ6/Xo7CwEFu3bsWMGTOwceNGFBQUICcnBytWrEB7eztM\nJhPKy8uRlZXl972TkzVQKsNPR5aWpgt8EXngfQsf7114eN/C1xP3Li05DjKZDGNHd36/cKSo7MPS\ncrkMMSoFWk0d0Glje9XvXsCAfOONN+Khhx7CggULIJfL8eSTTyIpKQnLli2D2WxGZmYm5s2bZ0uR\ntnAhFixYAEEQUFxcDLXa/0bqhgaj3/P+pKXpUFPDIfFQ8b6Fj/cuPLxv4eupe9fRYYVCLutVP7e8\nrAH477fluO2KCfjo23K0mjpwrs4Qdf8Gf18QZEJn1oN3UmduFP8jDw/vW/h478LD+xa+nrp397+w\nCUqFDE8tDi9VZk/Tm6348xtbsOTabIwcFF09ZH8BuXcNsBMRUbcTBAEyWe8tdTBqaCKe+NXMnm5G\nyHrvHSciom4hCIDnTmTqbgzIREQkIQCAjCE50hiQiYhIShDYQ+4BDMhERCQhgB3knsCATEREEoIA\nyBiRI44BmYiIJAQOWfcIBmQiIvLEiBxxDMhERP2Esc0MqzVwLijbtidG5EhjQCYi6gdOnm3B3X/7\nFu+tPRzwWgECF3X1AAZkIqI+pLyqGZ98dxzuWZEPnmyAAGDdzsqA78HEID2DqTOJiPqQx9/eDgDI\nHJ6ISRkp4nGjySw+rm9u81sn2LbtiSE50thDJiLqg55buVvyvLLGID7+7Yub8d5X0qHr/22tQOmx\nOgC2VdbsIkceAzIRUR/2/L9L8c+P9uJYZZPk+Nodp8Vh7TN1BqxcdxR/+2APAKDdbJUEcIoMDlkT\nEfUhk0alYP/xeqQkxMDUbsHuo7U+r9W3mqHTqPH7f20Rj9U2tQIAOizWbm8rSbGHTETUhzi2NXV0\nWHHP899Kzk0bmyZ5vnFPFdrNFsmxx//f9u5tIPnEHjIRUR9y8GQDAKDZaPY4F6dWSJ6frTfi+Jlm\nyTFvr6PIYEAmIuojTtfo/Z6//oJMjBuZjLXbT6HinB7bDp6DUmEbKFXIZbC4JA25oiC9W9tKnjhk\nTUTUR/xv2ymf52QyIFkXg/MnD8Gjt81Asi4G7R1WfLO7CgDwi8vHS64fPjC+W9tKnhiQiYj6CF2c\nCoBtYZe7FF2M5HlDi0nyPGt4Iv7wi3zx+YR0z/eg7sUhayKiPuLzLRUAgNwxA3CqugXNRjPyxqUh\nSRuDuVOH+X2tJlYlSRaijWN4iDT2kImI+pjUhFjcfvVEDEnV4Po5o3HzJWMxbIB0CHr8yCTJ8/hY\npTifDAAKOcNDpPGOExH1EWOGJwIAJmemIntUKv58RwGGpHqfC777hsmS545UmT/KG45rzx/VvQ0l\nrxiQiYh6mXMNRq9lFFvbOhAfq4RcHjjvZVyMEk8tngkAmDNliHj85kvG4hoG5B7BSQIiol5k/4l6\nMU/16w9eKCkCoW81Q2tf2BWMtKQ4vLH0oi5vI4WHPWQiol7kkD3xB2BL7OEgCELIAZmiCwMyEVEv\nMiRVIz4+19AqPm5oMcFiFVDT1NYTzaIuEFRArqurw9y5c3H8+HFUVFRgwYIFuOWWW/DYY4+J16xe\nvRo33HADbrrpJmzYsKG72ktE1K91WJxzxxXVLeLjr3ecBgA0G9oj3ibqGgEDckdHB5YvX47YWNv+\ntCeeeALFxcV45513YLVasXbtWtTW1qKkpASrVq3Ca6+9hueeew5mM/OhEhF1tfpmZw94zbfHcduT\n63DybIuYpeuqWUx52VsFDMhPPfUU5s+fj4EDB0IQBBw4cAD5+bZsLnPmzMHmzZtRWlqKvLw8KJVK\naLVaZGRkoKysrNsbT0TUn2zedwafbDrhcfzp93eKeaizR6VGuFXUVfwG5I8++gipqakoLCwUC1lb\nrc4amfHx8dDr9TAYDNDpdOJxjUaDlpYWj/cjIqLwvfbpQfHxlTOdPeFWk7OEYkK8OqJtoq7jd9vT\nRx99BJlMhk2bNqGsrAwPPvggGhqcK/wMBgMSEhKg1Wqh1+s9jgeSnKyBUqkIeJ0vaWm6wBeRB963\n8PHehYf3LXyOe2dsk04DLr4xF599f9Lj+olj0qBQcL1ub/yd8xuQ33nnHfHxz372Mzz22GN4+umn\nsW3bNkyfPh0bN25EQUEBcnJysGLFCrS3t8NkMqG8vBxZWVkBP7yhwRjwGl/S0nSoqWEvPFS8b+Hj\nvQsP71v4XO9deZW0bnFNTQuyhifiyOkm8djdN+Sgvt4Q0TZGo2j+nfP3RSHkxCAPPvggHnnkEZjN\nZmRmZmLevHmQyWRYuHAhFixYAEEQUFxcDLWawyZERF3l8be3i48XXjoWAPDA/Kn45TMbxOMuM4rU\nCwUdkN9++23xcUlJicf5oqIiFBUVdU2riIhIVOeyt/jeoimYnGlbuKV0G5rusDAi92acaCAiijCr\n4JmH2p8HXtosPs4eLa1T7JqZiwG5d2NAJiKKoM9/OIl7/v6tZD9xsHLHDIBcJi0c8cjP88XHDMi9\nGwMyEVEEfbDhGAxtHdh5uCbk13rrWaclxeG62bbqTBMzUjzOU+/Bak9ERBGy7dA58fF7a49gSGo8\nJo3yH0SrXQpITB8/0Os1VxeOwhUz06GQs4/Vm/GnR0QUIR99c0zy/LlVuwO+5sutFeLjWdmDfV7H\nYNz78SdIEdXQYsLGPVVi5jei/kQXYhatnYfOoarO1kO+9fLxktrH1PdwyJoi6tmVu3CmzghdnApT\nx6b1dHOIIqqh2YRErRpNeltFpiSt7wD9303Hsebb4+LzCRnJ3d4+6lnsIVNEnbF/269pbA1wJVHf\nYrUKaGgxIS0xDo/eOh0AkJvl+0upazAGABXTYfZ5/AlTz+DQG/UzTYZ2WAUBKQkxUKtsOfytVu9T\nN6Z2CzQx0gFM5qfu+zhkTT0iVm37g3SsqglKuRzpg3tfIniiUDS0mAAAyboYyOW2L6TeAvLKr4+I\ntY1dKRX8EtvX8SsX9QiVUo4zdQb8+e0deOytbWg3W0LOXkTUmzgCcpI2Bgr7CJHFS/Jpb8EY8EyT\nSX0Pf8IUMa4rqy0WARXVzpKdi5/7Bv/ecMzby4h6PZPZgtc/OwDAHpAVjoDs+SV0YFKc1/dQyNlD\n7usYkCli9h2vFx9bBQEms0Vy/ostFe4vIeoTPvqmHG3ttt/3CRnJPoesrYKAcy4LHlVK559obnnq\n+ziHTBEjd/mGb7FY8f7XR3uwNUSRs/+E88togkYNQ5sZgLSHvOdoLf7+71LJ626ZNx5b952JTCOp\nxzEgU8RYXBLf1za1eU2E32rqQFwMfy2p77AKAmLsq6odHMPPHRYBLcZ26DRqbNxTJZ7/0bThyBye\ngKvmjMFsP9m5qG/hkDVFjGPIDgCMpg6v17gOaxP1Bf/ecAzHzzQDgFjH2BGQ95bX4Z7nv8Ohkw2S\nL6LD0uJRMHEwh6n7GQZkihiTS0CubzZ5vSacknRE0apRb5Ksjbjz2mwA0ukbAPjv5hOSNRVZI5Ii\n00CKKhwbpIh58/ND4uO95XVer2E9V+pLlr78vfh41JAEMSGIeyEIhVwGY5tt1OjZO2chJSE2co2k\nqMEeMkWEr2ISAxKlf3gsFu5FpsiwCgLe+V8Z9hyt7bbPaO9wfsG8t2iy5NxzdxWKj/cdr8fBkw0A\nwGDcjzEgU0SYO7z3fC+bMRKF2YNx1awMAECHl0QJRN3h5NkWrNtZ6bGyuau0tTvXSeSNS4M2TiU5\nn6yLwRvHYA6vAAAgAElEQVRLL+qWz6beiQGZIqLNPj/mnvTgomnDsOiqiZhiX+xSUa332J9M1B0c\nFZcC2binSlyUFYo6+zqJC3KH4q7rcoJaoDUo2XtSEOofGJApIhwrrJN0MeKx0UMTxD9SSVrb8dJj\ndXj6vV2RbyD1O8FUHGvSm/DW54fwp/+3Hc//uxRNeu+LEb2pa7ItUEwNYQj60dtmBH0t9T0MyBQR\np6pbAADD0+LFY679hVSXueRweiNEoTrXEDggL3tti/h499FafPr9yaDff+vBagCBA/K880YCANRK\nucd+ZepfGJApIhy1XaeNddZ/5fKt/uOLLRX4+Nvynm6GSBAEfL3ztPj8Hx+WotXL3nhDm/SYr8WJ\n7iprDdi87ywAYGCAYeiiuZm44YLRuOfGyX6vo76PAZm63Z6jtaiqNQCQ9oT1RnNPNYkibPX6o/hk\n0wkAtqBmbPOeGCZSjlVKR2F2HanFOpcADXgPvsFUXLJaBTzi0rMePTTB7/UymQxXzszAhIyUgO9N\nfRsDMnU717k612xE53zM4Y0cpO32NvUlVbUGfLGlIujeW3c4W2/E51tOel1N7zrv2mGxYtFT6/Hr\nv23EybMtkWwiANtWp2fe34W/vLPD45wmVroK2tvvpyOhxwcbjuLZld7XOriurp4zZSizbVHQAgZk\nq9WKhx9+GPPnz8fNN9+Mo0ePoqKiAgsWLMAtt9yCxx57TLx29erVuOGGG3DTTTdhw4YN3dlu6kW+\n3OrMVBSnVuCmH2UBAPJchq8B4G+/OR8AYDJz61OwjpxuxLLXtmD1+qM4WtnUI20wtJnx8Ks/4IP1\nx/D9/rMe50+fc5bZdD2/uxP7fw+eqMezK3eF3NP+rvSMuN/XXWK8Wnz8xmcH8cJH+wAAP71ojHg8\nPtb2hfLzHypw4ESD1x0BZpe99NfOHhVS+6h/C5ipa926dZDJZHj//fexdetW/PWvf4UgCCguLkZ+\nfj6WL1+OtWvXIjc3FyUlJVizZg3a2towf/58FBYWQqVSBfoI6uMGJmvELSBKhRyXTh+B7FEpSEmI\nkVyXoFFjYHIcTO09O5zZmzz5zk7xsft8ZyS8/cUhbNjtLIpwukYvOS8IApa+8J34/M3/c2Zrq6o1\nQBCEsHqQz6zcDQDYXnYOc6YMDXh9RXULPvym3GOe+Dc3Tsbz9n3IjgGGAyfq8d1eZ4Wl1IRY3H9T\nLp5buRtrt58WdwQAtt7/wGSN5D3P1tmmZ/LHD5RcSxRIwIB88cUX46KLbJvXq6qqkJiYiM2bNyM/\nPx8AMGfOHGzatAlyuRx5eXlQKpXQarXIyMhAWVkZsrOzu/dfQFFPp7F9KRuUHCf+8R06IN7rtbEq\nBVqMwe0PJWBwqgZn6owAgPYe2L/tGowBePRYW1p9rxPYdugcRg1JEFcZB8t1aN6xtcifs/VGPPrm\nNo/jf/11IZK0MVhwcRbeW3sEJ84244U1ez2uSx+sE1O6Nhna8fpnB8VzD7+6Ba89eKHk+qfs2/ZK\nuzEDGPVNQc0hy+VyLF26FI8//jiuuuoqyX8Q8fHx0Ov1MBgM0Ol04nGNRoOWlsjPEVH0adS3Qwbg\n8TvOC3htjFqBtnZLj86H9iauvWJfBTsiIXu0bUGSawGRz7ecxL3P23rHaqX3PzWr14deE9t1nvq/\nm08EvN6x2tnVv343V+y9OuaFP/OxpSk1MdZnT9fq5/c0f/zAgG0jchX0oq4nn3wSX375JZYtWwaT\nyfkfvsFgQEJCArRaLfR6vcdxoka9Cbp4tUdCfW9i1AoIgjQHMHl34EQ9mg3O0YRggpvFau2yAh7m\nDmfwvfv6yZAB2HG4BlarLUh9sP6YeD43a4D4+I6rJ6JobmbYn/ve2sOS58Y2373wHWU1+NQtaKuV\ncsnvojzAkLlcJguqRrcgCKiuNyJJa5uLvvmSsQFfQ+Qq4G/Zf/7zH1RXV+OXv/wlYmJiIJfLkZ2d\nja1bt2LGjBnYuHEjCgoKkJOTgxUrVqC9vR0mkwnl5eXIysry+97JyRooleFvhE9L0wW+iDxE+r41\nG9oxdIA2qM8dMkCLfeX1EBSKgNfvPVqLh1/ahEvPS8fdP8ntqub6FS2/c+cajHjWPo/qKjVV61Ha\nz9Vv/74RZRUN+M8z1/i9Lhh6+3D0eZMGY+iQRHFf+e1Pr8fkMQMk1971k6m4vLIJ3+6uxEXnZSAu\nRokPNtgCdlKyBtsPnkNyQgzGpwfe+rNxzxnJc7la5fXnsqvsnNch6LhYpeT6hATnPuFErRrvPHY5\nBEHAa5/sw7RxA8VrL5+Vgc+99MibTBaMGZ6Ej9YfxZuf7gcADBkQj5HDkwP+W4IRLb9zvU1vvG8B\nA/Kll16Khx56CLfccgs6OjqwbNkyjB49GsuWLYPZbEZmZibmzZsHmUyGhQsXYsGCBeKiL7Va7fe9\nGxqMYTc8LU2HmhoOiYcq0vetw2JFW7sFSoUsqM9NirfNN+8/UoPYAB3qh1/aBAD435aTuLYwHSVf\nlmHM8CRcOHVYp9vtTbT8zm3YXYm3vygTnz+zZBYeeGkzAOAvb27Br66Z5PO1ZRW2FcZnq5ug6sSX\nYcAZkM1mi8d9cZ0/vXr2aFhMZqQP0CD94iy06tvQqgdyRqdib3kd/vz6Fuw4XAMAePWBuQH3+o4c\nqEWFy8rtxkaj19+VP7z6vedB2HJYu7bXYHDOQ2tilOK5a+0FTxzPL546DMNTNcgYrENifAx+/beN\nAICte6uQGKPAJxudIxQKWXC/74FEy+9cbxPN983fF4WAATkuLg5/+9vfPI6XlJR4HCsqKkJRUVGI\nzaO+bO8xW93jw6cag7p+cIptxeq5EL+s3flX2x/H7/dX44IpQzvd+4tWVkGQBOOHbpkmSbay5UC1\nJCCfqTNg3Y5KXH/BaMmwa1cU1XLMnzpGfAckxqLWbZHVS8UXYPiwJK9/HKdmDcDe8joxGANA2alG\nTAqQICNBqwbOAYXZg7Fp31l0dHJ6w3W7kybW95/EZF0MZk4aLD6/89psvPjxPry/9giOnGoUdxIA\nQIyaKR4odPytoW6173h9SNfHqm1/EI+cDryn1tdK7bP14Y+8RLvH/9928fHd1+cga3gSAOD2qyaI\nx10XxL2/9gi+3nka/918QnLcYu38ojnB/h6OOdilN0+TnP/19TmIUfvuhXur+/vcyt2oDVD0wfHP\n2Ftu+7LnukXJH0fPO94t6E7OdA6vJ4ewTck1Jeb2shrJOXUnRx+of2JApm4jCALW76oEANx/U3Bz\nvI5VusEkjUj3kdFr2WtbQu5h9wZ7y+twwp7dKn2wDlNdEqsUTBqMRPtiItdg68iSdrpGj2fed2aW\n8rc6OFiOj3GMRqQkxOKPLtWKxo5I8vv6EQO9//yaDP63vTm+WEyfMAgA8L9tp7xep1TIMXKgFktv\nnoY/LZoh9n5dF5i5u7wg3e9nu9JpfE/JDUnV+DxH5AsDMnWbqjpnUMwalhjUawSXkhPuSSbctdsz\neuWMTvU4d+qc/9f2Rp98d1x8/MurJ0rOyWUyMcA5ArLFakW1vaLRvvJ6HKpwThtYu6KH7DZkDQAK\nhfOJNs5/UqBkl1KcGpfhdJWPLVLOz7X9/6ghOpdjnv8ei9UKtVqBsSOSMCxNK36Gt+xejr3yvr4k\neJOkVSMuxrMnnD0qRcxGRxQKBmTqFKtVgMHHtpMDJ2zD1QUTB0EdbFk5l7+rL328z/dlgiD2pPLG\npXmc95eQojcSBAEDkmxDpE/8sgBDUj2H6xX2yOgItmdqfY8SdMWQtaOX7bptKNy5+1uvGI8fTRse\nVNsc/z7XYeHyKmmxCKsgQBCc9wQArpxp6/0W5gzxeM+//LIATy+eGVTxCAeZTIYX7rtAcmzs8EQU\n/zQ3pPchcuBvDXXKsyt34e6/fYv6Zs+MSY5jl0wfEfT7uf4trq73PZf4xdYKMXezt57Yf749jtue\nXBdU4oho95eSHVj01HpsOVANtUqONB/l/BT2IOAIaN6+lIwdbhupeOvzQx7nQuX4Wbn2kFX2NigV\nwQVmx7D2xIwUqFRy+/v6D8iCIEAGSL7kuY+mOHrBrgvZCnOG4O+/OV9SAtQhPlYlfuEJ1R1XTcTY\n4Ym4fs5oPLBgaljvQQQEscqayJdWU4c4DHq0sgkz3BbpOLbFuC+i8Uetcn5H9PeH+f9csip565U5\nes9rNpbjavv2ld6ousEoKRoxKFnjM5GFY6jX1G6BJkYpfiEaNyIJZacakaBRQWuf93QsiOoM90Vd\ngG0e+bc35XrtwXtz/0+nwGS2Ii5GCYX951jb2IaBSXFe52iPn2nGYfuCP9fsX47pi89/OIkTZ1tw\nqf1LoGNe3cHfvG+4ZmYPxszswYEvJAqAAZnC9ofXnTVf29o98ygbWm29lEBzia4mjUpBgkaFZqMZ\nF+cP93mda8rIAfZtP6kJsajz0lPvzVoM0l5uqpeVyQ4x9i8zjj3JDhfkDsWUMQOQNy4NaqUcOw/X\n+F39HKyth84BsKWmvPUK5yrviSHU9VUpFeJ+aEee81c+sSXXGDlQi0ddFokBwJ9cVpkPd5nv3Xqo\nGjVNrVi73VbTuNq+qM91SxNRtOOQNYXFYrVK9l16m/cztJkhkwGxQaQddJDLZFhyra0gyd7yeuwo\nO+f3+nuLJmN4mhbLfpaPx26bjmfvnCXZjgLY9uL2Vu5buLQa319uXLfvuNLFqzHvvJFIS4pDojYG\n2aNTYGq3+Jz7D0ZDiwlrNpYD8L9qORTuAx0V5/SS1KDutHEqFP9kCgDgWGWzGIwBoKLaNoTNakvU\nmzAgU1j+8aE0JWGHxQqrVYAg2P73/b6zOHK6CYIQOFewO0dPqbreiBfW7PO7Itixwnr00ARoYlVI\nSYjFRdOkPeu/28vr9UZv/N9ByfMpPoIuYEu04U2C2zCtDLb7e/ffvg2rTR0WK+5/YZP43PEFqrMU\nXqYe7v3Hd1jy3Dfi9Ie7+ACjL+5D1kTRjAGZQlZdb0SpPQPXGPt2psoaPW5/ej0+31KBbYfO4V+f\nHgj7/d3nhL0NQ8fHKjEsLd5rLd0UnbRXpDf23hXXjsxQP7lwDJ69cxamjfUdkH3VFR7mlkBlUoYz\nx3JDS+gVog6caJA8D/ULly/pg72nFDSZLfjz29u9FsUItHqfPWTqTTiHTEHrsFix7F9b0Kh3/hGf\nPn4gjlY2iQn//73hGCakO//gzwpjsYt7T+lcYyvS3FbACoKzp+du2rg0XDkzXSynZzR57jvtDayC\ngO/320oHzp4yBPGxgefiX3/wQuwoq8GkUSk4VtmEuFilxxecS6aPwMp1trzL97+wCW8svSikdtW4\nZNLqyopGjqxjgO0LiGv1qiZDu7iSeuRALe77qS3RjK+yjg6cQ6behD3kPuzE2WZJibzOqmtqw7nG\nVrE04pUz073uAT540tmDun7O6JA/xyMgN3hufxIgeMw5OshlMtxwQaa4xWegPZgfPtUYMAtUNDnm\nsro6mGAM2HrJ+eMHIi5GiezRqcgc6pmQRSaTSZJyhOrdr2zlD/PGpXVpIY+4GCUeu20GVtx9Pi6a\nNgwpCc42trVbxJ75tLFpYqB17SH/+PxR+Oe9czDSZbFXAgMy9SIMyH3U2Xoj/vjWdvzlnZ2S49X1\nRny17RSajaEHptZ2aU9z9NAEr/mIHX4+b5zf8764b00p+bLM4xqr4HuI1mH+xbbe2+TMVFQ3GPHk\nuzsluaCjnePfN2Z4cFnOQuE6VP31jtP4+Ntyr0PCb31+CLc9uU6SitQxBH7j3MwuL+IxYqAWifFq\nqFUKPHtnId5YepH4pe7f9nKNcS7b6Fx7yONHJkETq8SVLtvcmKCDehP+tvZRJ+05jx3/71Dyfwfx\n/tdHcO/z3+GR17agNYTh3O2HpAn0p2bZescP3TLN49ob52bigtzwek86PyuJHQTbmLVfjp62VRDw\nxZYKAN7no6PRibPNeH+trSeaPSr4bUThePerw/hk0wn88pkN+PyHk5JzG/dUAQCeW+WsvayQyxCj\nVmBQcmTyNU/OlKZGdd3X7ppm01GYhMPU1FsxIPdRjr2cgDRv8VmXLUCVtQZsD7CtyNUme1WdrOGJ\nkiICWcOT8PDCPMm1V4SQpN+dt16NR65iwXObjDuZ/YKqWoM4F9sbCIKAP761HcfP2L5MxQSbdjQE\n40d6L/zwwYZjsAoCfjhwFj+43DO53PkzaTK0RzTojRykk+SM1rgM37v+rjiu0YSwzY4omjAg9zEV\n1S0w2vf/Ojy7chcsVis6LFaxQL1DKH/sHXPHD92SJ0nKANhWW184zdYjHjUkIczWO101Kx1XzkwX\ntzWZzNK58GCGrB0B+1BFo5jJCQD2nwitJGSklVVIa0d3R0CeYa+U5E1NQyte/eQAXv2vc6V8db0R\nFdUtsAoCWozmiM/NtpqcP39fAdeR+nLogHhMHz8Qv7xmotfriKIVv0r2IcY2Mx59cxu0cSrEqhXi\nH7FDFY244+kNkpq5Dv4S+X+5tQItRjOuv2A0mvTtaDdbMMhHHmUA+OmFYzAwKQ5zu2Chz/VzMgEA\nr9u3T7UYzeKQJGDPZxygh+xrfvMfH5bi5fvndrqN3aXarXRkZxZg+XJB7lCkD9ZJMl85HHL70ubw\n380ncNXMDFgFAfE92At1T8W66MoJiFUrxO1Xcrmsy/ZGE0USA3If4shU5CuJwsmzniUJW4xmbDt0\nDmOHJyLRZc9ms7Edq+xbY+LjlFDI5bBYBb85e9UqBS6bMbIz/wQPKnvv0FEsQLDPB1usQsAessrH\ngp4RacGX2OsJjuxUc3OHQqmQIyfTs7xkZ8lkMmT42Pd7+FST5PnMSYPx/f6zSB+kw9Pv2xYJBiqR\n2NXuuHoi/mXvsSe67S32Vr2JqDfikHU3+HTzCXy/L/JzlvvchmIvyB2KB+ZPFdc+nThrK1F36xXj\nxa0hK78+gpc+3ofXXBJ5vPrf/bj3+e/E5x+sP4aVXx8BAMSpI/sdbrs9X/Kb9oxVB0404AP7attA\n63vdk0I45j2PVTXDYvVcUdzTth06hy+2VGDfcdvP8bLzRmLBJWO7LPGGO19faFzn2y+bMULc2lRV\nZxBHXX42b3y3tMmXgonOIfZQcqMT9SbsIXexU+f0+Mie4zctKa5btqz4MjE9GUdPO3s3VxSkIy0p\nDhfnj8BX20/hiP3csAFa3H9TLu5xCbpl9l7R/uP1+GF/tc/PmD0lsr0RR2+/4pytd79upzNfccA5\nZLch63Ejk7D1oC3AHzrZiEndvHo5FMY2s6T+c+awhIisYr44fzj2HqvDzZeORZvJghfdalDnjE6F\nxj5E7Pp7EemgKJPJsOxn+ZLFXUR9DXvIXczRowOAI5WNfq7seo7qShmDdXj2zllidiv3ObdhafEe\nf1A7LFZUVLdItrcAwMxJzp7J5MxUyTxuJMye7PwCsOdoLXYdqRWfB9PLffTW6UgfZBuaTdLGYFia\nbQ9tNNVJbja249dueaXdM5N1lwUXj8UTv5qJ7FGpyB8/0GOLUWpCrEe+6PzxAyPSNnejhyYEXdaR\nqDdiQO5irquBOzoiOyxqNNl6k3dely1JyHGVS6KEaeMGIkalgEzmufDl0Te3iY9HDtLipeILcMfV\nk8SA7poSM1IWXjYOgC0wuBeJOFbZHPD1IwfpsOznebjtigm4pnAU7iuyVQeCn1rLkSQIgmR6wCFr\nWORGVly5ruiOUSkwMDnOY4vTois8FwcSUedxyLqLudYFNlsi+0ffsWLafR+vXC5D0dxM1DebcPdN\nU1Ffb9uLPH38QAxdNANvfn4I5VXO4DZpVAp+dc0ksWbu8/fMxuFTjZJcw5Hi+Ld0JqGHQi7H+fae\ntiZWibgYBarqjHj6vZ34+bzxGJQSmQQX7gRB8NlTn5M7NLKNsXMNyP+8b7bXaYGuqKVMRJ7YQ+5i\nrvVbP918AuYAveTqBqPHNpdwWexfALyVsbu8IB03XzoWCrdgPSxN65HecuRArWRIWyaTYdzI5C5P\nk9hZ4QYGTYwS+lYzDlU04un3d3Vxq7zbdaQG9/3zO7G+sSAIWLF6Dz7+9rjkuh+fPwov3DcHCnnP\n/Kfpek9d2/DordMBAAsuzop4m4j6CwbkLtagl5az23rQ9wKpVlMHHnrlB/zxra7Jr+zoIXsLyP5M\nHSMt6ec6xB0NBiR65sN+/Pbz8PxvZof1fnExzi8bDS2mLi3A4cu7Xx1Gk75dXPBXVWsQV1MDwOUF\nIzEoOQ4XThuGuB7c4+ta0MHVyEE6vLH0IlycPyLCLSLqPzhk3UnnGozQxKpw+pzea2/r9c8O+twn\nWWVPYxlKPmlfahpbUXHOlmox1N5VTmYq5kwZgukTBmFgUlyPBgRvxgxLRG2Tc8j6rutyMHRA+It7\n3BeDtRjNSEno3mHYgUlxqG82oarW9jM3maVtuPb8USiaO6Zb2xAMx7SEa81kIoqM6PrL28u0my1Y\n+soPSIxXh1XWz3XRV1t7h8cKZqtVwKp1R9FhtWLBxVl+A+0f39oGgz15hkIRWg9ZG6fCLy6P3oU6\n7qt8vZV8DEWs21B3V3whCqTZaFtwV1VrwKuf7Jdk37rtiglQKaNjXnbMsEQ8f89sj3tERN3Pb0Du\n6OjAww8/jMrKSpjNZixevBhjxozB0qVLIZfLkZWVheXLlwMAVq9ejVWrVkGlUmHx4sWYO3duJNrf\no07X2Ho7gYKxLc2jZ5Bs1LdLHg9Okf44vtp+Cl9tPwUAGJoajx/lDff6/sa2DjEYA6EPWUe7SRkp\n+HqHbf/x2C7Y1+2eG7q9m1fDG9s6cKbWWdTjhwPOaYwEjQozJvTMNiJfmHiDqGf4DciffPIJkpOT\n8fTTT6O5uRk//vGPMX78eBQXFyM/Px/Lly/H2rVrkZubi5KSEqxZswZtbW2YP38+CgsLoVL17f+w\nXWvK+mPusEoKqQO2YPv+2iPi87qmNgx2W+1beqxOfNzW7tmLM3dY8cKavWJaScC2QjpQwozexnWh\n0YJLxnb6/dxHImoaW7ukIIYvp861QACgVMjQ4bby/rfzp3r8bhBR/+R3svHyyy/HPffcAwCwWCxQ\nKBQ4cOAA8vPzAQBz5szB5s2bUVpairy8PCiVSmi1WmRkZKCszLOofF/TbJAG5JmTBiF3zAA8MH+q\n5Li3HphrMAZs9WaPVTmzbAmCgEqXXtWGXVUe77HzcA1Kj9XhaKXtdXKZDPf/NDf0f0iUyxisg1ol\nxzWFGRg5yHv+5VDc9CPpXO3L/9nv48rOqa434l//3Y+dh23JTK6ameFxTWfmwomob/EbkOPi4qDR\naKDX63HPPffgvvvuk9SljY+Ph16vh8FggE7n/EOp0WjQ0tLSfa2OEiX/Oyx5ftWsDPzmxsnIchtW\nDbT1yeGJkp3i4/fXHpFsoaprbvOoCey+N/f2q6N3Hrgz4mKUePn+ubh29ugueb+ByRq8sfQiXDq9\ne1cMP/TqD/h+f7U47TBuZBJGD5X2xLsrTzUR9T4BF3WdOXMGv/71r3HLLbfgyiuvxDPPPCOeMxgM\nSEhIgFarhV6v9zgeSHKyBspOLGZJS+t8bylcW/adER+rVQr89OKxmDzeVgnJPXDqEuKQ5tITqqzx\nrLoEAFZBQFqaDsY2M9ba50wHpWhQbd+7qoxVS/YMt7uVTpyRMwxpQSS56Mn7Fk3i450Lq4K9J8Fe\n1+AlkUl+zlDkThiMrQeqscJeNam//Cz6y7+zO/Dehac33je/Abm2thaLFi3CH/7wBxQUFAAAJkyY\ngG3btmH69OnYuHEjCgoKkJOTgxUrVqC9vR0mkwnl5eXIygqcQKChEwkx0tJ0qKnpmV54s6Edj7+5\nVXz+8v0XAICkPffcOBmf/XASR0834Wx1M7aUVkKllGPGhEFY/OQ6ALbcvA8umIZfPbsBgK23dLqy\nEUv++o34Pn/4eT7e/PwQth86hxc/2I3brpgAY5sZidoYnLUH9twxA3D7VRMgt1gC3pOevG/Rxmh0\nTjkEc0+CvXer1h3Bl1tPeRxvaWoFAEwckYDRQxMwOTO1X/ws+DsXPt678ETzffP3RcFvQH7llVfQ\n3NyMF198ES+88AJkMhl+//vf4/HHH4fZbEZmZibmzZsHmUyGhQsXYsGCBRAEAcXFxVCr1f7eulc7\n4lJR6aaLvO8dnTJmAErL63D0dBNKy+vwb3vJwBkTnMUaBiTGQqWU4+4bcvCPD/di9NAE/Llkh+R9\n1Co56ux/yLccqMaxyibUNrXh/p/mipWL7ro+u8cyO/VmrgMZVqvQZZnIvAXjZT/LFx8r5HLJcyIi\nIEBA/v3vf4/f//73HsdLSko8jhUVFaGoqKjrWhbFahpbxcezp/jOOVxnT2bhCMaALSnF8DQtTtfo\nccfVEwEAUzJtmbIci7McRg3RQSGXY/GPs/Hgy98DgJggw7UqE4NxeFyrYN3+9Hos/vEkyRcmf77e\ncRqpibHIdcty5p505ParJiAhXu0xd0xE5I5/ycPgGpD95VO+2ksKys9/qIBCIYNKKRcDqa+emaMX\nlZYUh19c7r0gvK+9yRSYexrIYFdbNxvb8e5Xh/G8W/UpAPjPdyfEx7+bPxWzsocge1Sqx3VERO4Y\nkMPgCMgv3DfH7ypZb1WEyqua0dDcFjD5wpOLZ0r2Ew9KltbHjVUr8NhtM/CTC3s+3WJvFRejxLzz\nRkqO3fP8tzC0mf2+7sQZ73NTlTV6fOpSvWl8D5SrJKLei6kzw1DT2AqdRhUw57PGy/mDFQ0wtVtQ\nMEk6NPpi8Ry89ulBFOYMxphhidBppHPwIwZqxcc3XDAaV3rZ00qhc08R2WI048MNx/Czed5HJABp\nqk1zhxUqpe177SmX1fOLfzypi1tKRH0dA3KIzB1WVDe0IkETOAuZt6Fok71e8oBE9x6vEr++Psfn\ne2liVXhj6UUhtpYCUXvZdhcoA5vJ7KwOdbSyCRPsPeHjVc6e8/Tx0ZUOk4iiH4esQ/RtqS1jlqNY\nQM1kW7kAABUFSURBVCCO0oGpbjWHVSEWgKDuEaPy/E/A4KfYhCAI2LTXuQf9GXuFr6pag5gA5JrC\njD6XvpSIuh8Dcog27T0LAB7ZuHzJzbKtwm0xSgtQ6Fu7v8IQBeatylKbn4C87dA5ybY3AKisNeCt\nLw6Jz2dlD+66BhJRv8GAHCJHj8rXqmd340bY6steOG2Y5LgAwdvlFGHedozlZvku7+haocvhkde2\nSLKzJWpjPK4hIgqEc8ghMpmtUCrkGJIaXFGAaWPTsPTmaRiepsXxMy04fKoRAHBlQXp3NpOCJIPn\n0LJj/7irTXvPYOuhUuSPHeBxDgCOVTYDAB5cMNWjvCMRUTAYkENktQpQhDD/K5PJMNbeS76vaAqq\n6gxIH6xjUYEoERfr+Z9Ao965qKuyRg+ZTIbXPzsIAHD86BddOQGb953FwZMNktdm2X/WREShYkAO\nUqupAy3GdlisVijCDKYxakW31t2l0OWMTsG8GSNRMGkQ9pbX4cNvymFodS7Ye+T1rZLrdx+1lVJM\njFfj19fn4K4VGyXn+UWLiMLFgGxX39yGqjqD16xKPxw4i1c/OQAASNbFdFnOY+p5CrkcP7HnIx85\nSIfv91fjjL26lr7V90r6CRnJUMjluLxgJD7/oQIAcEGu7zSqRESBMCDb/fbFzQCA5++ZLcmi9fR7\nO3GoolF8HmiPKvVuVbUGALYvYaeqvZfJTEuKFdOeuiZ/WXBx4ApnRES+9OuA3GrqwDv/O4zLZjhz\nGhvazGJANndYJMGY+o93/3cYhjbv259cF23tP14vPva2hYqIKFj9etvT1ztO4/v9Z/Hom9vEYw+9\n8gO2HKgGYNtfSv2Tr2AMAC0uQ9lXeikgQkQUjn4ZkM/WG/HM+7uwx75Ax90rn+yHVRBQYR+yjItR\n4KX7LxDTIf7mhskRaytFD6XC9p9Lk8te5IzBvouNExGFot8NWVutAh5+9YeA193+1Hrx8b1FUxCj\nUuDWK8bjomnDMG4kq/j0VXnj0rCjrEZ8PiwtHvcVTUGsWolDlU345wd7JNc75pC595iIOqvfBWS9\nW2m9kQO1WHxtNlJ0MdiwqxIr1x31eM3IgbZeUKxayWDcx/3qmkn45TMbxOexKgVS7HnIB6d4JoOR\nyWR47q5CseITEVG4+l1ANrrNDY4bmYzB9rrFl84YiQunDcevnt0gnmeFpf5FqZBDp1GhxV485FhV\ns3huctYAXFOYgZxM6da4ZB1TZRJR5/W7r/UV1bYSeUqFDDFqBX6UP1xyXqWU4+GFeQBsdYep/xF8\npBmXyWS4dvZoZA4NrrAIEVEo+l0P2bFN5bc3TUXW8ESvZfLGDEvEirvPhy4ucM1j6ntcE4LcfMnY\nHmwJEfUn/S4gf1tqq2WblhTnt2ZtYrw6Uk2iKHbh1GGBLyIi6gL9asjatURekpYBl7wrujATALDk\n2mymSSWiiOlXPeT6Zlvay+njB/rtHVP/dvl56bhsxkgWiiCiiOpXPeSqOlvmrSGpmh5uCUU7BmMi\nirR+FZAPnrDVrk1ndiUiIooy/WLIWhAE3PH0Bljtc8ijuW2FiIiiTJ/vIQuCgKfe3SkG4yGpGq6g\nJiKiqBNUQN6zZw8WLlwIAKioqMCCBQtwyy234LHHHhOvWb16NW644QbcdNNN2LBhQ7c0Nhxn6404\nfLoJABAXo8Sfbj+vh1tERETkKWBAfu2117Bs2TKYzbZkCU888QSKi4vxzjvvwGq1Yu3ataitrUVJ\nSQlWrVqF1157Dc8995x4fXc7eroJm/ae8Xn+pD0zFwD8457ZXKxDRERRKWBATk9PxwsvvCA+379/\nP/Lz8wEAc+bMwebNm1FaWoq8vDwolUpotVpkZGSgrKys2xqtbzVD32rGrsM1+Ms7O/D6ZwfR1u69\nfm2ryQLAVjSAe0qJiChaBVzUdckll6CyslJ87ppcIz4+Hnq9HgaDATqdc+WyRqNBS0sLOksQBI/9\nws3Gdtz7/Hce17771WHccEEmkrTSRP9Ge3WnuJh+sX6NiIh6qZCjlFzu7FQbDAYkJCRAq9VCr9d7\nHA8kOVkDpdKzjqzFYsW1v/svhqTG45WHfiQJyo88udbre23aexab9p7Fx89cA4W9J/z2/x3Ah9+U\nAwBGj0xGWhq3OwHgfegE3rvw8L6Fj/cuPL3xvoUckCdOnIht27Zh+vTp2LhxIwoKCpCTk4MVK1ag\nvb0dJpMJ5eXlyMrKCvheDQ1Gr8c/WG+rSXymzoD9R85hULItkUerqQOVNQa/73ntA5/g0VunY0hq\nPD74+ojzRIcFNTWd77X3dmlpOt6HMPHehYf3LXy8d+GJ5vvm74tCyAH5wQcfxCOPPAKz2YzMzEzM\nmzcPMpkMCxcuxIIFCyAIAoqLi6FWh7+16PMtFeLjh175ARfnDUeToR1n6pzBeGByHM41tHp9/T8/\n2ouWVumisvhYDlkTEVH0kgmCr+qv3c/XN5jbnlzn93XPLJmF8WPScPX9/wEAPPmrAsSqlXj+w1KU\nuxSUB4C8sWm4ZPoIjB2R1DWN7uWi+ZtjtOO9Cw/vW/h478ITzffNXw85KhODpCbE+j+faDt/7exR\nGDciCQMS45AQr8ayn+VLrrt+zmjcdX0OgzEREUW9qBzHNZq8b2ECgHuLpoiPrykchWsKR0nOv3z/\nBdhedg4zJw1mRSciIuo1ojIgd1isGDlIi7yxaVjz7XEAwBO/KkB8rAraOJXf16pVCszKHhKJZhIR\nEXWZqAvIgiCgo8OKGJUCVxeOwlWzMgCAvV0iIurToi4gV1TrIQA4cdY2Ic9ATERE/UFULeqyCgJe\n/s8+AIC5w9rDrSEiIoqcqOohP/jSZtQ1mwAAo4b0viwrRERE4YqaHvLhU41iME4fpMNvb5rawy0i\nIiKKnKjpIW87dA4AkDU8Eb+9KRcqLzmuiYiI+qqo6CGfONuMr3ecBgDcODeTwZiIiPqdqAjIJV8e\nFh8PStH0YEuIiIh6Ro8OWd/25DoUZg9GVa0BapUcz95ZGDDxBxERUV/U43PIm/adBQBcUZDOYExE\nRP1WVAxZA8BlM0b0dBOIiIh6TI/2kJ+9cxYOnmzA1KwB0MSyd0xERP1XjwbklIRYFOawEAQREVHU\nDFkTERH1ZwzIREREUYABmYiIKAowIBMREUUBBmQiIqIowIBMREQUBRiQiYiIogADMhERURRgQCYi\nIooCDMhERERRoEtTZwqCgEcffRRlZWVQq9X485//jBEjWDSCiIgokC7tIa9duxbt7e1YuXIl7r//\nfjzxxBNd+fZERER9VpcG5B07dmD27NkAgClTpmDfvn1d+fZERER9VpcGZL1eD51OJz5XKpWwWq1d\n+RFERER9UpcGZK1WC4PBID63Wq2Qy7lujIiIKJAuXdQ1bdo0rF+/HvPmzcPu3bsxduxYv9enpen8\nng+ks6/vr3jfwsd7Fx7et/Dx3oWnN943mSAIQle9mesqawB44oknMGrUqK56eyIioj6rSwMyERER\nhYcTvERERFGAAZmIiCgKMCATERFFAQbkPopLA4iIepeoDchGo1Gyp5mC19jYiNra2p5uBhFRt+mL\nMSIqA/I777yD4uJicfsUBW/NmjW47LLLsHLlyp5uSq/z7rvv4r333sPBgwd7uim9ypYtW/Dhhx8C\n4MhMqEpKSvDGG29g//79Pd2UXqWvxoioCciCIKC+vh6XX3456urq8Oyzz2LatGmS8+Tbrl27sGjR\nIuzevRvZ2dk4//zzAfC+BUOv12PJkiU4ePAgkpKS8Pe//x3ffPMNADD1axC+/PJLfPXVV6itrYVM\nJuPvXBCMRiN+85vf4ODBg4iJicEbb7yBY8eO9XSzol5fjxFdmqkrXBaLBQqFAikpKcjMzER6ejpe\nfPFFNDc3IzExEQ888ABkMllPNzMqOdKTVlVV4fbbb8fMmTPx1ltv4ciRI5g6dSrvmx+O3zuLxQKd\nTocHHngAiYmJ+P/t3WtMU/cbwPFv13KwzIgWsBBLkYWmKzjXBHVR2FyM8VJFbMxCsgvbyIKJiZuJ\nJu6FJiSbsmzeJhEyExdxEkti5xZk88JcdGNGmXNBSYbEaBhEBBUGVPDSdi82kf9/KuzMcmp5Pm+B\n9He+OT1Pz6E9vXv3Lp9++imzZ8+WW78O4ccff+TChQvY7Xb27t3LqlWrZJ8bhjt37jBmzBjWr1+P\noiicP3+esWPHar2ssGcymbDZbBE7I/RFRUVFWj14f38/xcXFnD17lo6ODux2O729vVRUVJCVlcXr\nr79OeXk5bW1tTJ8+nUAgEBHRH4d77c6cOUN3dzcul4vk5GTu3r2L1+tl+vTpJCcnS7MHGLzfdXd3\nEx8fT01NDU6nkwkTJtDb28sPP/yAoig4HA6CwaA0/JvH46GhoYEpU6YAEBMTQ2JiIi+++CI1NTUk\nJSVhNpul2QN4PB7Onz/PlClTuHr1KlarlcmTJ7Nz504qKyvp7u6mqamJzMxMed4OMnif8/v9+Hy+\niJ0Rmr387+/vZ/v27RiNRhYsWMCuXbuora0lJSWF/Px8cnNzMZlMFBUVDXzPspyt/GVwO5fLRVlZ\nGcePH8fn82EwGEhJSeHQoUMA0uz/DG43f/58SktLaW1tJSkpifLycjZs2IDH42Hp0qU0Njbi9/uf\n6Cf441ZXV8dnn31GX18fAPHx8cydO5dJkybhdDr5+uuvAaTZA9TV1bFz5076+vpISUnhhRdeACA7\nO5va2lreeOMNPB4P/f398rwdZPA+p9frsdlsvPrqq7jd7oibESO++o6ODgCioqI4d+4cbrcbh8NB\nQUEB33//PePGjWPJkiX09PQA0NLSwpw5c1AUZaSXGnYe1u6dd97h2LFjtLa2AjBz5kxiY2Npb2/X\ncrlh5UHt0tPTefvttzl69CiLFy+msLAQs9nM+++/T0JCAjabDb1er/HKtXWvG0BTUxNjx44lNTWV\nrVu3An9d9gcwGo1kZWXR2dlJVVWVJmsNN0O1u/f+BIvFQkxMDF1dXcybN4/o6GhN1hsuHtZt8+bN\nAGRkZOB2u+nq6gIia0aM2CXrtrY2iouLqa6uxufzYTKZ0Ol0XLhwgWnTpvHss89y7NgxFEXB7/dT\nWlrKvn37qK+vJycnB4vFMhLLDEtDtbPb7Rw/fhydTofD4eDKlSucOnWKtLQ0Jk6cqPXyNTWc/a6m\npgZFUcjIyKCtrY2Kigp+/vlnFixYQFJSktaboInB3W7evMn48eOJi4vDZrPxyiuvsHHjRrKzs4mL\ni8Pv9/PUU0/x9NNPYzQaSU5OHtX73b9pd+bMGbxeL7t376auro7c3FxSUlK03gRNDNWtuLiY7Oxs\nEhISOHXqFLt376aioiKiZsSIDeQ9e/ZgNBpZvnw5Z8+epba2FqvVSnt7O9HR0QMHPo/HQ2FhIS+/\n/DJms5mVK1dGROj/YjjtdDodX3zxBcuWLSMxMZHY2FicTqfWS9fccNvt27ePvLw8JkyYgMFgYO3a\ntaN2GMP/dvvll184efIks2bNwmw2oygKPT09VFdX43K5Bi4TGgwGUlNTR/UwhuG1O3jwIC6XC7PZ\njNPpJD4+nvfeew+r1ar18jUznG5VVVUsWrSIpKQkZs+eHXEzIqQD2ev1Ul5eTmNjIy0tLeTn5w+8\ner58+TLt7e2kpaVx4MABFi5cSH19PYqikJmZiaIoo3rnVNPOaDSSmZmJXq9n0qRJWm+CZtS0i46O\nZtq0aYwbNw673a71JmjiYd3MZjO//fYbzc3NAy/yZsyYQXFxMVarlWeeeUbjlWtPbbu0tDQURWHy\n5MnaboBG/m23jz76aKCbwWCIuBkRsoG8adMmzp07R0FBAYcPH6a6uhpFUcjKysJoNBIMBmlubiYn\nJ4eLFy+yf/9+Tp8+TWFh4ah/hS3t1Psv7RISErRevmaG6qbX62loaOC5555jzJgxADgcDiwWCyaT\nSePVa0vaqSPd/ilkn0Pu6ekhLy+PjIwMXnvtNSZOnMjBgwdZvHgxDocDk8mEz+fDbDazZs0aOjs7\nR/UBcTBpp560U2eobnFxcdy6dYuYmJiBjzTNnDlT62WHBWmnjnT7p5C8yzoQCDBv3jymTp0KwDff\nfMNLL73EihUr2LBhA5cuXeLkyZN0d3fT19eHwWCQg+LfpJ160k6d4XT76aef6OrqeuI/5/m4STt1\npNuD6YIhvt9Yb28vb731FmVlZSQkJFBWVsYff/zBtWvXWLt2rRwQH0HaqSft1JFu6kk7daTbfSG/\ndebVq1eZNWsWPT09fPjhh9hsNlavXk1UVFSoH/qJJ+3Uk3bqSDf1pJ060u2+kA/ke3enaWhoIDc3\nlyVLloT6ISOGtFNP2qkj3dSTdupIt/tCfsna6/XS0dFBQUFBRNxJZSRJO/WknTrSTT1pp450uy/k\nA1luMq+etFNP2qkj3dSTdupIt/tCPpCFEEIIMbQn+6sxhBBCiAghA1kIIYQIAzKQhRBCiDAgA1kI\nIYQIAzKQhRBCiDAQ8huDCCFGRmtrK/Pnz8dmsxEMBrl16xZ2u53169cTFxf30L/Lz89nz549I7hS\nIcSDyBmyEBHEbDZz4MABvvrqK7799lusVivvvvvuI//m9OnTI7Q6IcSjyBmyEBFs5cqVZGdn09jY\nyN69e2lqauL69eukpqZSUlLCJ598AkBeXh6VlZWcOHGCkpIS/H4/FouFDz74gNjYWI23QojRQc6Q\nhYhgUVFRWK1WvvvuOxRFwePxcOTIEfr6+jhx4gTr1q0DoLKykhs3brBlyxY+//xzvvzyS7KysgYG\nthAi9OQMWYgIp9PpSE9Px2KxUFFRwaVLl2hubsbn8w38HKC+vp4rV66Qn59PMBgkEAgwfvx4LZcu\nxKgiA1mICHbnzp2BAbxt2zbefPNNli1bRmdn5z9+1+/3k5mZSWlpKQC3b98eGNpCiNCTS9ZCRJDB\nt6YPBoOUlJTgdDr5/fffcblcuN1uTCYTdXV1+P1+APR6PYFAgOeff55ff/2Vy5cvA7Bjxw4+/vhj\nLTZDiFFJzpCFiCAdHR243e6BS87p6els3ryZtrY2Vq9ezaFDh1AUBafTSUtLCwBz5swhNzcXr9fL\nxo0bWbVqFYFAgMTERPkfshAjSL7tSQghhAgDcslaCCGECAMykIUQQogwIANZCCGECAMykIUQQogw\nIANZCCGECAMykIUQQogwIANZCCGECAMykIUQQogw8CepwhihftgpswAAAABJRU5ErkJggg==\n", + "image/png": "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27bx/vvvA3T5ZGj+g/TkyZPk5OQApoSxe/dufHx8AIiOjiYmJobExESb13Rl1nGdPn0agLKyMnJycixj1kVFRQQGBuLp6dkt/v3Z+12Z23306FGWL19OeHg4b775JkC3SfD24srPz2fXrl1OzRfd46fnJJWVlTz00EO89tpr/Oc//+Gll16itraWa665hqeffprvvvuOefPmMXr0aF599VX279+Pm5tbl08ezcX15z//mYKCAlasWMErr7zCrFmzePvtt/n555+Brp0UFQoFtbW1PPvss2zbtg2dTkffvn0ZPHiwJVkA/P3vf+fAgQMcOXKkWyQP67i2b9+OTqdj6NChvPDCC2i1WsCUVMxfZN0tpm3btlFbW2tpd11dHZWVlfzzn/9kzZo1/PGPf+TEiRNObnHbNPdvcOTIkSxatMhp+aLr/4twovz8fFQqFZ999hmJiYkEBwezePFibrzxRjIyMggLC2Pq1Klce+213HbbbXz99ddA1+/1No4rKCiIRYsWERUVRXh4OI8++igzZsxgwoQJ3Hnnnaxbtw7o+nHt2LGDQ4cOsW/fPtLT0wFYsGAB27dvt9yc9Pf359prr2Xv3r3ObGq7WMeVkZEBwIgRIyzDaYcOHSIuLg6Ampoap7WzPaxjOnToEGCaTVNeXo6HhwdffvklQUFB5OXlMWTIkG4z08Y6rsOHDwMwd+5c9u/fz4ABA5ySLyTJN7Jr1y7OnDkDmMbS9u3bB4Bareb222+npqaGffv2ERcXR3JysuV1paWlXH311c5ocpu0FNcdd9xBZWUl33//PW5ubmzatMnyuurqambNmuWMJrdq165d5OfnW56fOXOGBQsW4O/vz4EDBygtLWXw4MHMnDmTJUuWWK4rKipi1KhRzmhym7QU1969eykrK7OcO3DgAIGBgVxxxRV8+umn3HXXXV1yZlRrMZ07dw6lUklZWRmPP/44Go2Gr7/+mqysLH777bcuO9Ompbj27dtHRUUFV155JePHj+e7776zXNeZ+UJuvNY7deoU8+fPp0+fPigUCubMmcO0adNQq9Vs3ryZ2bNn06NHD+655x4++OAD3nzzTe6//36WLFnCyZMnCQwM7JKJo61x3XfffXz00UesWrWKd955hyVLlnDixAl69erFXXfd5ewwbFjH5ObmxuzZs7n++usJCwvjyiuv5Oeff2bTpk0MHTqUyZMn88wzz3D//ffz7LPPcvjwYUJCQggNDe1yN17bGtewYcOYNGkSAPv27SMrK4t7770XHx8fXnjhBQYNGuTkSBq0Nabhw4dz9dVX87vf/Y4nnniCsLAwAJYvX05QUFC3/F198803lrief/555s6dS2JiIidOnOjUfHHJT6GsqanB09OTdevWUVFRwb333ssPP/zAtm3bCAoKYvjw4axbt4533nkHMP1y33zzTRITE/H09KSwsBCNRtPlevEXGtezzz6L0WgkNzeX8vJyYmNjnRxJA3sx/fjjj2zdupXQ0FAeeughy7UvvfQS/v7+3HTTTYSFhXH+/HmKioo4e/Ys0dHRToyiqQuJ6+abbyY0NJT333+ft99+m+XLlzN58mQnRmGrvTH5+vpyxx13oFarAdPQjZubW5dK7ND+uPz8/Lj55pvp378/JSUlFBcXd3q+uGSHa+rq6njttddITEwkJSWFlJQU8vLyAJg0aRIzZsxg3759eHl5oVarefXVVwHw9fVFq9Xi7+9PYGAgQ4cO7VIJ/mLj8vPzQ6VSERUV1WUSfGsxzZo1ix07dnD8+HHLa+Lj48nOziYtLQ2j0UhAQACXXXZZl0rwFxPX7t27MRqN3HrrraSmpnaZBH+hMeXk5JCammq5CalUKrtUgr/QuE6fPs2ePXswGo0EBQU5JV9ckkm+pKSEJ554gqqqKqZMmcKGDRuIiIggPz+f3NxcvL29GT58OJGRkRw4cIBHHnmE7777jhdeeIF7772XYcOG4eHh0eVmm7hiXK3F5OXlRUREBFFRUWzcuNHyujFjxhAeHo5SqexS8Zg5Ki4/Pz8nRmFLflddM65Lcky+pKSEkpISVq9eDUBmZib79+8nIiKCr776iscff5xevXrRp08fTp48Sf/+/fnggw/Iysri+uuv5/LLL3dyBPa5Ylxtialnz56EhISQmZmJTqfD3d0dpVLJI488goeHh5MjsM8V43LFmKD7x3VJ9uQDAgKIi4ujsLAQgNDQUFQqFZdffjnHjh0jJSUFpVKJp6enZUpa3759iY6O7pKJ0MwV42pvTF5eXpaZGM7+z9USV4zLFWMCF4jLeAkyGAzG0tJSy/N7773XuHbtWmNtba3xq6++Mk6fPt344osvGqdPn2785ptvnNjS9nHFuC4kJoPB4KzmtpkrxuWKMRmN3T+uS352TU5ODnfffTcbN27E39+f7OxssrOzqaio4PLLL6d///7ObuIFccW4XDEmcM24XDEm6J5xXZJj8tZycnKYPn06Go2GJ598ksDAQP7617+iUqmc3bSL4opxuWJM4JpxuWJM0D3juuST/JEjR/jkk08sJU5vvfVWZzfJIVwxLleMCVwzLleMCbpnXJf8cM3nn3/O2bNneeCBB7p9mVZrrhiXK8YErhmXK8YE3TOuSz7JG7vYcmlHccW4XDEmcM24XDEm6J5xXfJJXgghXNklOU9eCCEuFZLkhRDChUmSF0IIF3bJT6EUl67c3FyuvfZahg0bBpj22/Tz82PevHlcd911Lb521apVREREMGPGjM5oqhAXTJK8uKR5e3uTlJRkeZ6Xl8cf/vAHlEplizti7dy5kyFDhnRGE4W4KJLkhbASGhrKE088wbvvvsuwYcN4/vnnqaysRKPREBERwRtvvMH69etJT09n+fLlKJVKYmNjWbFiBbt370av1zNy5EgSExMte7AK4UwyJi9EIxERERw7doy1a9dy4403snbtWr799ltyc3PZunUrd955J6NHj+aZZ57h2muv5e2330apVPLFF1+wYcMG1Go1K1ascHYYQgDSkxeiCYVCgbe3NwsXLmT79u288847ZGVlUVhYSFVVVZPrt27dyvnz50lNTQWgtraW4ODgzm62EHZJkheikYMHDzJs2DCeeuop9Ho9s2fPZsqUKeTn59vd4cdgMLB48WLLdomVlZXodLrObrYQdslwjRBWMjMzWb16Nffddx/btm3jscces8y02b9/P3q9HjDtQVpXVwfA5MmT+eSTT6ipqcFgMPDss8/y+uuvOy0GIaxJT15c0rRaLTfccAMAbm5ueHl58dRTTzFlyhQWLFjAY489hq+vL/7+/kycOJHTp08DMG3aNF5//XVqa2t59NFHeeWVV7jpppvQ6/WMGDGCRYsWOTMsISykdo0QQrgwGa4RQggXJkleCCFcmCR5IYRwYZLkhRDChUmSF0IIFyZJXgghXJgkeSGEcGGS5IUQwoX9fw7DQHlNkci2AAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "
" ] }, "metadata": {}, @@ -1169,9 +1417,7 @@ { "cell_type": "code", "execution_count": 29, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1212,9 +1458,7 @@ { "cell_type": "code", "execution_count": 30, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1263,9 +1507,7 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1317,9 +1559,7 @@ { "cell_type": "code", "execution_count": 32, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1361,9 +1601,7 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1424,9 +1662,7 @@ { "cell_type": "code", "execution_count": 34, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# !curl -o FremontBridge.csv https://data.seattle.gov/api/views/65db-xm6k/rows.csv?accessType=DOWNLOAD" @@ -1443,9 +1679,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1532,9 +1766,7 @@ { "cell_type": "code", "execution_count": 36, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "data.columns = ['West', 'East']\n", @@ -1551,9 +1783,7 @@ { "cell_type": "code", "execution_count": 37, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1655,9 +1885,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -1667,9 +1895,7 @@ { "cell_type": "code", "execution_count": 39, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1699,9 +1925,7 @@ { "cell_type": "code", "execution_count": 40, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1733,9 +1957,7 @@ { "cell_type": "code", "execution_count": 41, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1766,9 +1988,7 @@ { "cell_type": "code", "execution_count": 42, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1800,9 +2020,7 @@ { "cell_type": "code", "execution_count": 43, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1835,9 +2053,7 @@ { "cell_type": "code", "execution_count": 44, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1869,9 +2085,7 @@ { "cell_type": "code", "execution_count": 45, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "weekend = np.where(data.index.weekday < 5, 'Weekday', 'Weekend')\n", @@ -1888,9 +2102,7 @@ { "cell_type": "code", "execution_count": 46, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1947,9 +2159,22 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.8.5" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/data/FremontBridge.csv.gz b/notebooks/data/FremontBridge.csv.gz new file mode 100644 index 000000000..94f087df6 Binary files /dev/null and b/notebooks/data/FremontBridge.csv.gz differ diff --git a/notebooks/data/openrecipes-small.json b/notebooks/data/openrecipes-small.json new file mode 100644 index 000000000..32a5a2c7d --- /dev/null +++ b/notebooks/data/openrecipes-small.json @@ -0,0 +1,2 @@ +{"name": "Easter Leftover Sandwich", "ingredients": "12 whole Hard Boiled Eggs\n1/2 cup Mayonnaise\n3 Tablespoons Grainy Dijon Mustard\n Salt And Pepper, to taste\n Several Dashes Worcestershire Sauce\n Leftover Baked Ham, Sliced\n Kaiser Rolls Or Other Bread\n Extra Mayonnaise And Dijon, For Spreading\n Swiss Cheese Or Other Cheese Slices\n Thinly Sliced Red Onion\n Avocado Slices\n Sliced Tomatoes\n Lettuce, Spinach, Or Arugula", "url": "http://thepioneerwoman.com/cooking/2013/04/easter-leftover-sandwich/", "image": "http://static.thepioneerwoman.com/cooking/files/2013/03/leftoversandwich.jpg", "cookTime": "PT", "recipeYield": "8", "datePublished": "2013-04-01", "prepTime": "PT15M", "description": "Got leftover Easter eggs? Got leftover Easter ham? Got a hearty appetite? Good! You've come to the right place! I..."} +{"name": "Pasta with Pesto Cream Sauce", "ingredients": "3/4 cups Fresh Basil Leaves\n1/2 cup Grated Parmesan Cheese\n3 Tablespoons Pine Nuts\n2 cloves Garlic, Peeled\n Salt And Pepper, to taste\n1/3 cup Extra Virgin Olive Oil\n1/2 cup Heavy Cream\n2 Tablespoons Butter\n1/4 cup Grated Parmesan (additional)\n12 ounces, weight Pasta (cavitappi, Fusili, Etc.)\n2 whole Tomatoes, Diced", "url": "http://thepioneerwoman.com/cooking/2011/06/pasta-with-pesto-cream-sauce/", "image": "http://static.thepioneerwoman.com/cooking/files/2011/06/pesto.jpg", "cookTime": "PT10M", "recipeYield": "8", "datePublished": "2011-06-06", "prepTime": "PT6M", "description": "I finally have basil in my garden. Basil I can use. This is a huge development. I had no basil during the winter. None. G..."} \ No newline at end of file diff --git a/notebooks/data/openrecipes.json.gz b/notebooks/data/openrecipes.json.gz new file mode 100644 index 000000000..13e812ff3 Binary files /dev/null and b/notebooks/data/openrecipes.json.gz differ