Skip to content

Instantly share code, notes, and snippets.

@gglanzani
Created March 12, 2016 22:20
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gglanzani/2958fb4237083aecae8c to your computer and use it in GitHub Desktop.
Save gglanzani/2958fb4237083aecae8c to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"## The workhorse of PyData\n",
"\n",
"The library most widely known in the PyData ecosystem is probably pandas. Developed initially by Wes McKinney (now at Cloudera), it has grown, building on top of `numpy` and many other Python libraries, to be *the* workhorse of almost any analysis you may wish to perform.\n",
"\n",
"The API is rather large therefore, instead of pretending to show it all off, we'll present the main features and, when necessary, point to other sources."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Pandas: from bdate_range to wide_to_long\n",
"\n",
"## Giovanni Lanzani, Shoe Designer @ GoDataDriven\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Slide are part of a (longer) public course, Doing Data Science with Python.\n",
"\n",
"If you like this tutorial, you'll love the course.\n",
"\n",
"If you don't like this tutorial, you'll love the course."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## About me\n",
"\n",
"* Italian born, move to the Netherlands 10y ago, before it was cool;"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* Somehow got a master and philosophical degree in Th. Phyisics;"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* Also managed to get 4 kids in the meantime (myth about PhD's having a lot of free time is true);"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* After graduation, one year as Powerpoint monkey at KPMG;"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* Then GoDataDriven made me an offer I couldn't refuse${}^{+}$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* Last year made the next career step and became shoe designer."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"* You do get custom designed shoes if you come work for us (hint: we're hiring!)\n",
"\n",
"$+$ No horses involved!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## About the tutorial\n",
"Pandas is probably the most widely known library in the PyData ecosystem, maybe on par with Numpy. Developed initially by Wes McKinney (now at Cloudera), it has grown, building on top of numpy and many other Python libraries, to be the first choice for almost any analysis you may wish to perform.\n",
"\n",
"The API is rather large therefore, instead of pretending to show it all off, we'll present the main features and, when necessary, point to other sources.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Pandas basic"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"import numpy as np # this is not needed to use pandas per se, but I will make use of it\n",
"# also not needed, but P-L-O-T-S!\n",
"%matplotlib inline\n",
"import matplotlib\n",
"matplotlib.style.use('ggplot')\n",
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We start off with `Series`. Series are what makes up DataFrame and are, in a handwavy sense, nothing more than numpy array with an index."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 5\n",
"1 4\n",
"2 -1\n",
"3 -2\n",
"dtype: int64"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie = pd.Series([5, 4, -1, -2])\n",
"serie"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(array([ 5, 4, -1, -2], dtype=int64), Int64Index([0, 1, 2, 3], dtype='int64'))"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie.values, serie.index"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Series have an index, whether it's automatically assigned by pandas, or whether it's specified by us."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"a 5\n",
"b 4\n",
"c -1\n",
"d -2\n",
"dtype: int64"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2 = pd.Series([5, 4, -1, -2], index=['a', 'b', 'c', 'd'])\n",
"serie2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Accessing by index?\n",
"\n",
"<div class=\"naked-img\">\n",
" <img src=\"https://standupforamerica.files.wordpress.com/2009/08/obama-yes-we-can-matte.jpg\" width=\"400\">\n",
"</div>\n",
"<script>\n",
" $(\"naked-img\").css(\"margin-left\", \"15%\");\n",
"</script>"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"b 4\n",
"dtype: int64"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2[['b']]"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2['b']"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"b 4\n",
"c -1\n",
"dtype: int64"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2[['b', 'c']]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We can work with Series like we would with Numpy arrays"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1.5"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.mean(serie2)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1.5"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2.mean()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"a 25\n",
"b 16\n",
"c 1\n",
"d 4\n",
"dtype: int64"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2 ** 2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We can select using series of booleans!"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"a True\n",
"b True\n",
"c False\n",
"d False\n",
"dtype: bool"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2 > 0"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"a 5\n",
"b 4\n",
"dtype: int64"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie2[serie2 > 0]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'a' in serie2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Data from dicts can also be loaded"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"literacy_pct = {\"NH\": 0.5, \"ZH\": 0.4, \"FL\": 0.1, \"GR\": 0.6}\n",
"literacy_srs = pd.Series(literacy_pct)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"FL 0.1\n",
"GR 0.6\n",
"NH 0.5\n",
"ZH 0.4\n",
"dtype: float64"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"literacy_srs"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"An index can also be passed. Missing values from the index will be `nan`, extra values will be ignored"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"NH 0.5\n",
"ZH 0.4\n",
"FL 0.1\n",
"UT NaN\n",
"dtype: float64"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"literacy_index = [\"NH\", \"ZH\", \"FL\", \"UT\"]\n",
"literacy_srs2 = pd.Series(literacy_pct, index=literacy_index)\n",
"literacy_srs2"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"NH False\n",
"ZH False\n",
"FL False\n",
"UT True\n",
"dtype: bool"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"literacy_srs2.isnull()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We can give names to Series and their indices"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Province\n",
"NH 0.5\n",
"ZH 0.4\n",
"FL 0.1\n",
"UT NaN\n",
"Name: Literacy, dtype: float64"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"literacy_srs2.name = 'Literacy'\n",
"literacy_srs2.index.name = 'Province'\n",
"literacy_srs2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The index can be changed on place! (Beware: state modifications are always bad!)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"OH 0.5\n",
"MY 0.4\n",
"WFT 0.1\n",
"HAPPENED? NaN\n",
"Name: Literacy, dtype: float64"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"literacy_srs3 = literacy_srs2.copy()\n",
"literacy_srs3.index = [\"OH\", \"MY\", \"WFT\", \"HAPPENED?\"]\n",
"literacy_srs3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"As with dictionary keys, index values must be hashable!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## DataFrame: bi-dimensional Series with two (or more) indices\n",
"\n",
"A DataFrame represents a tabular, spreadsheet-like data structure containing an ordered collection of columns, each of which can be a different value type (numeric, string, boolean, etc.). \n",
"\n",
"The DataFrame has both a row and column index; it can be thought of as a dict of Series (all sharing the same index).\n",
"\n",
"DataFrame's can be created in different ways. One of them is from dict's."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.1</td>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.3</td>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Year\n",
"0 0.2 FL 2013\n",
"1 0.1 FL 2014\n",
"2 0.5 NH 2013\n",
"3 0.3 NH 2014\n",
"4 0.5 ZH 2014"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = {\"Province\": [\"FL\", \"FL\", \"NH\", \"NH\", \"ZH\"],\n",
" \"Year\": [2013, 2014, 2013, 2014, 2014],\n",
" \"Literacy\": [0.2, 0.1, 0.5, 0.3, 0.5]}\n",
"df = pd.DataFrame(data)\n",
"df"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"To change the order of the columns:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy\n",
"0 FL 2013 0.2\n",
"1 FL 2014 0.1\n",
"2 NH 2013 0.5\n",
"3 NH 2014 0.3\n",
"4 ZH 2014 0.5"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.DataFrame(data, columns=[\"Province\", \"Year\" ,\"Literacy\"])\n",
"df"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"An `index` can be passed (as with Series), and passing column names not existing, will result in missing data."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Assigning values to new columns is easy"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense\n",
"0 FL 2013 0.2 10065.000000\n",
"1 FL 2014 0.1 20140.000000\n",
"2 NH 2013 0.5 4026.000000\n",
"3 NH 2014 0.3 6713.333333\n",
"4 ZH 2014 0.5 4028.000000"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df['nonsense'] = df.Year / df.Literacy\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df['Serie_aligned'] = pd.Series(range(3), index=[1, 3, 4])\n",
"df"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Passing a dicts where the values are dicts is also possible"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"{'Literacy': {0: 0.20000000000000001,\n",
" 1: 0.10000000000000001,\n",
" 2: 0.5,\n",
" 3: 0.29999999999999999,\n",
" 4: 0.5},\n",
" 'Province': {0: 'FL', 1: 'FL', 2: 'NH', 3: 'NH', 4: 'ZH'},\n",
" 'Serie_aligned': {0: nan, 1: 0.0, 2: nan, 3: 1.0, 4: 2.0},\n",
" 'Year': {0: 2013, 1: 2014, 2: 2013, 3: 2014, 4: 2014},\n",
" 'nonsense': {0: 10065.0,\n",
" 1: 20140.0,\n",
" 2: 4026.0,\n",
" 3: 6713.3333333333339,\n",
" 4: 4028.0}}"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.to_dict()"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Year</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>10065.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.1</td>\n",
" <td>FL</td>\n",
" <td>0</td>\n",
" <td>2014</td>\n",
" <td>20140.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>4026.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.3</td>\n",
" <td>NH</td>\n",
" <td>1</td>\n",
" <td>2014</td>\n",
" <td>6713.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2</td>\n",
" <td>2014</td>\n",
" <td>4028.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Serie_aligned Year nonsense\n",
"0 0.2 FL NaN 2013 10065.000000\n",
"1 0.1 FL 0 2014 20140.000000\n",
"2 0.5 NH NaN 2013 4026.000000\n",
"3 0.3 NH 1 2014 6713.333333\n",
"4 0.5 ZH 2 2014 4028.000000"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.DataFrame(df.to_dict())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Reindexing\n",
"Reindexing can often be important, especially with time series. Let's assume we have the following DataFrame (or Serie)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 0\n",
"2 1\n",
"4 2\n",
"6 3\n",
"8 4\n",
"10 5\n",
"12 6\n",
"14 7\n",
"16 8\n",
"18 9\n",
"dtype: int32"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie3 = pd.Series(range(10), range(20)[::2])\n",
"serie3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The index might represent days of the month. Suppose we want to have an entry for every day of, say, November:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 0\n",
"1 NaN\n",
"2 1\n",
"3 NaN\n",
"4 2\n",
"5 NaN\n",
"6 3\n",
"7 NaN\n",
"8 4\n",
"9 NaN\n",
"10 5\n",
"11 NaN\n",
"12 6\n",
"13 NaN\n",
"14 7\n",
"15 NaN\n",
"16 8\n",
"17 NaN\n",
"18 9\n",
"19 NaN\n",
"20 NaN\n",
"21 NaN\n",
"22 NaN\n",
"23 NaN\n",
"24 NaN\n",
"25 NaN\n",
"26 NaN\n",
"27 NaN\n",
"28 NaN\n",
"29 NaN\n",
"30 NaN\n",
"dtype: float64"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie3.reindex(range(31))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The NaN's can be taken care of with the `method` argument: it can either be `ffill` (forward fill) or `bfill`"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 0\n",
"1 0\n",
"2 1\n",
"3 1\n",
"4 2\n",
"5 2\n",
"6 3\n",
"7 3\n",
"8 4\n",
"9 4\n",
"10 5\n",
"11 5\n",
"12 6\n",
"13 6\n",
"14 7\n",
"15 7\n",
"16 8\n",
"17 8\n",
"18 9\n",
"19 9\n",
"20 9\n",
"21 9\n",
"22 9\n",
"23 9\n",
"24 9\n",
"25 9\n",
"26 9\n",
"27 9\n",
"28 9\n",
"29 9\n",
"30 9\n",
"dtype: int32"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie3.reindex(range(31), method='ffill')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"With dataframes a `reindex` can also operate on `columns=`\n",
"\n",
"```python\n",
"df.reindex(columns=['old_column1', 'old_column2', 'new_column'])\n",
"```\n",
"\n",
"Interpolation happens row-wise."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Dropping data\n",
"\n",
"Dropping from an axis is easy in pandas"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy Serie_aligned\n",
"0 FL 2013 0.2 NaN\n",
"1 FL 2014 0.1 0\n",
"2 NH 2013 0.5 NaN\n",
"3 NH 2014 0.3 1\n",
"4 ZH 2014 0.5 2"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.drop('nonsense', axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.drop(4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Indexing and filtering"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Selecting data can be done using names or conditions"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 FL\n",
"1 FL\n",
"2 NH\n",
"3 NH\n",
"4 ZH\n",
"Name: Province, dtype: object"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df['Province']"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>10065.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>20140.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>4026.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>6713.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>4028.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province nonsense\n",
"0 FL 10065.000000\n",
"1 FL 20140.000000\n",
"2 NH 4026.000000\n",
"3 NH 6713.333333\n",
"4 ZH 4028.000000"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df[['Province', 'nonsense']]"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"3 NH 2014 0.3 6713.333333 1"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df[df.nonsense > 5000]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Fancier indexing is also available"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nonsense</th>\n",
" <th>Literacy</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>10065.000000</td>\n",
" <td>0.2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>6713.333333</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" nonsense Literacy\n",
"0 10065.000000 0.2\n",
"3 6713.333333 0.3"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.ix[[0, 3], ['nonsense', 'Literacy']]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Functions!\n",
"Numpy functions working on array (element-wise) work fine with dataframes"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.447214</td>\n",
" <td>100.324474</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.316228</td>\n",
" <td>141.915468</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.707107</td>\n",
" <td>63.450768</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.547723</td>\n",
" <td>81.934934</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.707107</td>\n",
" <td>63.466527</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy nonsense\n",
"0 0.447214 100.324474\n",
"1 0.316228 141.915468\n",
"2 0.707107 63.450768\n",
"3 0.547723 81.934934\n",
"4 0.707107 63.466527"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.sqrt(df[[\"Literacy\", \"nonsense\"]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sometimes we want other, custom functions, on our datasets"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def is_numeric(g):\n",
" try:\n",
" g + 5\n",
" except:\n",
" return False\n",
" return True"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def custom_max(group):\n",
" seq = [g for g in group if is_numeric(g)]\n",
" if seq:\n",
" return max(seq)\n",
" else:\n",
" return None\n",
"f = lambda group: custom_max(group)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0 10065.000000\n",
"1 20140.000000\n",
"2 4026.000000\n",
"3 6713.333333\n",
"4 4028.000000\n",
"dtype: float64"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.apply(f, axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Province NaN\n",
"Year 2014.0\n",
"Literacy 0.5\n",
"nonsense 20140.0\n",
"Serie_aligned NaN\n",
"dtype: float64"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.apply(f)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Sorting\n",
"Sorting a dataset is as easy as cake"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sort_index()"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Year</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>10065.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.1</td>\n",
" <td>FL</td>\n",
" <td>0</td>\n",
" <td>2014</td>\n",
" <td>20140.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>4026.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.3</td>\n",
" <td>NH</td>\n",
" <td>1</td>\n",
" <td>2014</td>\n",
" <td>6713.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2</td>\n",
" <td>2014</td>\n",
" <td>4028.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Serie_aligned Year nonsense\n",
"0 0.2 FL NaN 2013 10065.000000\n",
"1 0.1 FL 0 2014 20140.000000\n",
"2 0.5 NH NaN 2013 4026.000000\n",
"3 0.3 NH 1 2014 6713.333333\n",
"4 0.5 ZH 2 2014 4028.000000"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sort_index(axis=1) ## look at those capital letters!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Sorting can also happen on a column level"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Year</th>\n",
" <th>nonsense</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.1</td>\n",
" <td>FL</td>\n",
" <td>0</td>\n",
" <td>2014</td>\n",
" <td>20140.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>10065.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.3</td>\n",
" <td>NH</td>\n",
" <td>1</td>\n",
" <td>2014</td>\n",
" <td>6713.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>NaN</td>\n",
" <td>2013</td>\n",
" <td>4026.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2</td>\n",
" <td>2014</td>\n",
" <td>4028.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Serie_aligned Year nonsense\n",
"1 0.1 FL 0 2014 20140.000000\n",
"0 0.2 FL NaN 2013 10065.000000\n",
"3 0.3 NH 1 2014 6713.333333\n",
"2 0.5 NH NaN 2013 4026.000000\n",
"4 0.5 ZH 2 2014 4028.000000"
]
},
"execution_count": 134,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sort_values(by='Literacy').sort_index(axis=1) # and secondary sorting in one pass"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Descriptive statistics\n",
"A pandas tutorial without descriptive statistics is worth nothing!"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"44972.333333333336"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.nonsense.sum()"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Province FLFLNHNHZH\n",
"Year 10068\n",
"Literacy 1.6\n",
"nonsense 44972.3\n",
"Serie_aligned 3\n",
"dtype: object"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sum() # province is always the cutest!"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 12078.200000\n",
"1 22154.100000\n",
"2 6039.500000\n",
"3 8728.633333\n",
"4 6044.500000\n",
"dtype: float64"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sum(axis=1) # psst: non numeric values are ignored!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"A quick way to compute descriptive statistics on a dataframe is describe"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>count</th>\n",
" <td>5.000000</td>\n",
" <td>5.000000</td>\n",
" <td>5.000000</td>\n",
" <td>3.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>2013.600000</td>\n",
" <td>0.320000</td>\n",
" <td>8994.466667</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>0.547723</td>\n",
" <td>0.178885</td>\n",
" <td>6706.787166</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>2013.000000</td>\n",
" <td>0.100000</td>\n",
" <td>4026.000000</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>2013.000000</td>\n",
" <td>0.200000</td>\n",
" <td>4028.000000</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>2014.000000</td>\n",
" <td>0.300000</td>\n",
" <td>6713.333333</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>2014.000000</td>\n",
" <td>0.500000</td>\n",
" <td>10065.000000</td>\n",
" <td>1.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>2014.000000</td>\n",
" <td>0.500000</td>\n",
" <td>20140.000000</td>\n",
" <td>2.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Year Literacy nonsense Serie_aligned\n",
"count 5.000000 5.000000 5.000000 3.0\n",
"mean 2013.600000 0.320000 8994.466667 1.0\n",
"std 0.547723 0.178885 6706.787166 1.0\n",
"min 2013.000000 0.100000 4026.000000 0.0\n",
"25% 2013.000000 0.200000 4028.000000 0.5\n",
"50% 2014.000000 0.300000 6713.333333 1.0\n",
"75% 2014.000000 0.500000 10065.000000 1.5\n",
"max 2014.000000 0.500000 20140.000000 2.0"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.describe()"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>count</th>\n",
" <td>5</td>\n",
" <td>5.000000</td>\n",
" <td>5.000000</td>\n",
" <td>5.000000</td>\n",
" <td>3.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>unique</th>\n",
" <td>3</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>top</th>\n",
" <td>FL</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>freq</th>\n",
" <td>2</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>NaN</td>\n",
" <td>2013.600000</td>\n",
" <td>0.320000</td>\n",
" <td>8994.466667</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>NaN</td>\n",
" <td>0.547723</td>\n",
" <td>0.178885</td>\n",
" <td>6706.787166</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>NaN</td>\n",
" <td>2013.000000</td>\n",
" <td>0.100000</td>\n",
" <td>4026.000000</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>NaN</td>\n",
" <td>2013.000000</td>\n",
" <td>0.200000</td>\n",
" <td>4028.000000</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>NaN</td>\n",
" <td>2014.000000</td>\n",
" <td>0.300000</td>\n",
" <td>6713.333333</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>NaN</td>\n",
" <td>2014.000000</td>\n",
" <td>0.500000</td>\n",
" <td>10065.000000</td>\n",
" <td>1.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>NaN</td>\n",
" <td>2014.000000</td>\n",
" <td>0.500000</td>\n",
" <td>20140.000000</td>\n",
" <td>2.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"count 5 5.000000 5.000000 5.000000 3.0\n",
"unique 3 NaN NaN NaN NaN\n",
"top FL NaN NaN NaN NaN\n",
"freq 2 NaN NaN NaN NaN\n",
"mean NaN 2013.600000 0.320000 8994.466667 1.0\n",
"std NaN 0.547723 0.178885 6706.787166 1.0\n",
"min NaN 2013.000000 0.100000 4026.000000 0.0\n",
"25% NaN 2013.000000 0.200000 4028.000000 0.5\n",
"50% NaN 2014.000000 0.300000 6713.333333 1.0\n",
"75% NaN 2014.000000 0.500000 10065.000000 1.5\n",
"max NaN 2014.000000 0.500000 20140.000000 2.0"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.describe(include='all')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Value counts, uniqueness, membership\n",
"Often merely counting the values in a Series is invaluable"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"FL 2\n",
"NH 2\n",
"ZH 1\n",
"Name: Province, dtype: int64"
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.Province.value_counts()"
]
},
{
"cell_type": "code",
"execution_count": 136,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array(['FL', 'NH', 'ZH'], dtype=object)"
]
},
"execution_count": 136,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.Province.value_counts().index.values"
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array(['FL', 'NH', 'ZH'], dtype=object)"
]
},
"execution_count": 137,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.Province.unique()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Vectorized membership is also pretty important and handy!"
]
},
{
"cell_type": "code",
"execution_count": 138,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065 NaN\n",
"1 FL 2014 0.1 20140 0\n",
"4 ZH 2014 0.5 4028 2"
]
},
"execution_count": 138,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df[df.Province.isin(['ZH', 'FL'])]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Handling missing data\n",
"\n",
"If every dataset you ever got your hands on never had missing data, you're probably on the wrong room. \n",
"\n",
"Assuming from now on that you're in the rigth room, let's talk about pandas handling of missing data.\n",
"\n",
"When a value is not present (or `None`), pandas replaces it with `np.nan`"
]
},
{
"cell_type": "code",
"execution_count": 139,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"nan"
]
},
"execution_count": 139,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.nan"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The value is used as a mere place holder, easily detectable"
]
},
{
"cell_type": "code",
"execution_count": 141,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(True, nan), (False, 0.0), (True, nan), (False, 1.0), (False, 2.0)]"
]
},
"execution_count": 141,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(zip(df.Serie_aligned.isnull(), df.Serie_aligned))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"There is a serie of methods that ease working with missing data. Besides `isnull` and `notnull` there is `dropna` and `fillna`"
]
},
{
"cell_type": "code",
"execution_count": 143,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1 0\n",
"3 1\n",
"4 2\n",
"Name: Serie_aligned, dtype: float64"
]
},
"execution_count": 143,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.Serie_aligned.dropna()"
]
},
{
"cell_type": "code",
"execution_count": 144,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"1 FL 2014 0.1 20140.000000 0\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 144,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.dropna() # here every row with missing data in **some** columns is taken out"
]
},
{
"cell_type": "code",
"execution_count": 145,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 0\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 0\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 145,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.fillna(0)"
]
},
{
"cell_type": "code",
"execution_count": 146,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>2.718282</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>2.718282</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 2.718282\n",
"1 FL 2014 0.1 20140.000000 0.000000\n",
"2 NH 2013 0.5 4026.000000 2.718282\n",
"3 NH 2014 0.3 6713.333333 1.000000\n",
"4 ZH 2014 0.5 4028.000000 2.000000"
]
},
"execution_count": 146,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.fillna(np.e)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"`dropna` can be a bit brutal sometimes. This is why it has an option to remove only rows where every column value is missing or where at least `thresh` values are present"
]
},
{
"cell_type": "code",
"execution_count": 147,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 147,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.dropna(how='all') # nothing gets dropped here!"
]
},
{
"cell_type": "code",
"execution_count": 148,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"1 FL 2014 0.1 20140.000000 0\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 148,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.dropna(thresh=5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercise\n",
"\n",
"* Write some helpers function so that you can easily drop lines with more than `n` missing values;\n",
"* A nice feature of `fillna` is that it can fill different values on a per column basis if you pass it a dict. Create a dataframe and test the feature;\n",
"* As above, but use the `ffill` and `bfill` arguments of `fillna`."
]
},
{
"cell_type": "code",
"execution_count": 150,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"# my solution\n",
"def count_na(values):\n",
" \"\"\"\n",
" Values is a numpy array\n",
" \"\"\"\n",
" return np.sum(values.isnull())\n",
"\n",
"def drop_na(df, n):\n",
" return df.ix[df.apply(count_na, axis=1) <= n]"
]
},
{
"cell_type": "code",
"execution_count": 151,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"1 FL 2014 0.1 20140.000000 0\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 151,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"drop_na(df, 0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Hierarchical indexing\n",
"Hierarchical indexing is a, quite important, feature of pandas. It basically allows to work with multidimensional data in a (two) dimensional form. Let's take a look"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"a 1 0.631726\n",
" 2 -1.905334\n",
" 3 0.134675\n",
"b 1 -0.081249\n",
" 2 -0.869233\n",
" 3 0.064204\n",
"c 1 0.547171\n",
" 2 -0.962894\n",
"d 2 -1.569194\n",
" 3 -0.672891\n",
"dtype: float64"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = pd.Series(np.random.randn(10),\n",
" index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'],\n",
" [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])\n",
"data"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"This serie has a multiindex as index. The gaps that we see between one letter and the other are interpreted as: \"use the value above\"."
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],\n",
" labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])"
]
},
"execution_count": 127,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.index"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1 -0.081249\n",
"2 -0.869233\n",
"3 0.064204\n",
"dtype: float64"
]
},
"execution_count": 128,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data['b'] # a partial index is possible"
]
},
{
"cell_type": "code",
"execution_count": 152,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Int64Index([1, 2, 3], dtype='int64')"
]
},
"execution_count": 152,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data['b'].index"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Data can also be selected using the inner labels"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"a -1.905334\n",
"b -0.869233\n",
"c -0.962894\n",
"d -1.569194\n",
"dtype: float64"
]
},
"execution_count": 130,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data[:, 2] # the ':' is necessary"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Not shown here but possible: use hierarchical indexing for columns!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercises\n",
"\n",
"* Create a dataframe with hierarchical indexing on both rows and columns;\n",
"* Give names to all the indexes!\n",
"* Use `swaplevel()` to swap two levels;\n",
"* Use `sortlevel()` after swapping to sort the results!\n",
"* Compute statistics by level (hint: `df.sum(level='a')`);\n",
"* Create a new dataframe without assigning the index. Use then `df.set_index([column_name_1, column_name_2])`;\n",
"* Remove the index (`df.reset_index()`)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"### Scraping and pandas"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import BeautifulSoup as bs\n",
"import requests as r"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"def get_top_questions(sort=\"votes\"):\n",
" page = r.get('http://stackoverflow.com/questions?sort=' + sort)\n",
" soup = bs.BeautifulSoup(page.text)\n",
" for top in soup.findAll('a', attrs={'class':'question-hyperlink'}):\n",
" yield get_info_for_question(\"http://stackoverflow.com\" + top.get('href'))\n",
"\n",
"def get_info_for_question(url):\n",
" page = r.get(url)\n",
" soup = bs.BeautifulSoup(page.text)\n",
" return {\n",
" \n",
" \n",
" 'title': soup.find('a', attrs={\"class\": \"question-hyperlink\"}).string,\n",
" 'votes': soup.find('span', attrs={\"class\": \"vote-count-post high-scored-post\"}).string,\n",
" 'tags': set(map(lambda s: s.string, soup.findAll('a', attrs={\"class\": \"post-tag\"}))),\n",
" 'body': soup.find('div', attrs={'class': 'post-text'}).text\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"top_questions = [q for q in get_top_questions()]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"pd.DataFrame(top_questions)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"#### Exercise\n",
"Get all the names of the people on this webpage: http://www.godatadriven.com/team.html"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Data wrangling\n",
"Getting the data in the shape that we want is the single most consuming task in the life of the data scientist. Sometimes it can be the most frustrating. \n",
"\n",
"So… do yourself a favor and pay attention to this chapter."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Merge operations\n",
"By merging we means combining different data sets by linking rows with one or more keys. The basic syntax is pretty simple."
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned\n",
"0 FL 2013 0.2 10065.000000 NaN\n",
"1 FL 2014 0.1 20140.000000 0\n",
"2 NH 2013 0.5 4026.000000 NaN\n",
"3 NH 2014 0.3 6713.333333 1\n",
"4 ZH 2014 0.5 4028.000000 2"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Population</th>\n",
" <th>Province</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>200000</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>300000</td>\n",
" <td>ZH</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Population Province\n",
"0 100000 FL\n",
"1 200000 NH\n",
"2 300000 ZH"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame({\"Province\": [\"FL\", \"NH\", \"ZH\"], \"Population\": [\"100000\", \"200000\", \"300000\"]})\n",
"df2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Let's say we want a dataset with year, literacy, province and population. We can create it from `df` and `df2`."
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Population</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" <td>300000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned Population\n",
"0 FL 2013 0.2 10065.000000 NaN 100000\n",
"1 FL 2014 0.1 20140.000000 0 100000\n",
"2 NH 2013 0.5 4026.000000 NaN 200000\n",
"3 NH 2014 0.3 6713.333333 1 200000\n",
"4 ZH 2014 0.5 4028.000000 2 300000"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.merge(df2) # merge is smart! If there are overlapping names, it uses those for the merge"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"If the column names are different, you need to specify them explicitely"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Population</th>\n",
" <th>province</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" <td>100000</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" <td>100000</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" <td>200000</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" <td>200000</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned Population province\n",
"0 FL 2013 0.2 10065.000000 NaN 100000 FL\n",
"1 FL 2014 0.1 20140.000000 0 100000 FL\n",
"2 NH 2013 0.5 4026.000000 NaN 200000 NH\n",
"3 NH 2014 0.3 6713.333333 1 200000 NH"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df3 = pd.DataFrame({\"province\": [\"FL\", \"NH\"], \"Population\": [\"100000\", \"200000\"]})\n",
"df.merge(df3, right_on='province', left_on='Province')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What happened? Zuid Holland is weg!\n",
"\n",
"By default `merge` does inner joins. If you want a different type of join, you can specify it."
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Population</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>UT</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>50000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned Population\n",
"0 FL 2013 0.2 10065.000000 NaN 100000\n",
"1 FL 2014 0.1 20140.000000 0 100000\n",
"2 NH 2013 0.5 4026.000000 NaN 200000\n",
"3 NH 2014 0.3 6713.333333 1 200000\n",
"4 ZH 2014 0.5 4028.000000 2 NaN\n",
"5 UT NaN NaN NaN NaN 50000"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df4 = pd.DataFrame({\"Province\": [\"FL\", \"NH\", \"UT\"], \"Population\": [\"100000\", \"200000\", \"50000\"]})\n",
"df.merge(df4, how='outer')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Check this out:"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" <th>Literacy</th>\n",
" <th>nonsense</th>\n",
" <th>Serie_aligned</th>\n",
" <th>Population</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" <td>0.2</td>\n",
" <td>10065.000000</td>\n",
" <td>NaN</td>\n",
" <td>50000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" <td>100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" <td>0.1</td>\n",
" <td>20140.000000</td>\n",
" <td>0</td>\n",
" <td>50000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" <td>0.5</td>\n",
" <td>4026.000000</td>\n",
" <td>NaN</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" <td>0.3</td>\n",
" <td>6713.333333</td>\n",
" <td>1</td>\n",
" <td>200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" <td>0.5</td>\n",
" <td>4028.000000</td>\n",
" <td>2</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Province Year Literacy nonsense Serie_aligned Population\n",
"0 FL 2013 0.2 10065.000000 NaN 100000\n",
"1 FL 2013 0.2 10065.000000 NaN 50000\n",
"2 FL 2014 0.1 20140.000000 0 100000\n",
"3 FL 2014 0.1 20140.000000 0 50000\n",
"4 NH 2013 0.5 4026.000000 NaN 200000\n",
"5 NH 2014 0.3 6713.333333 1 200000\n",
"6 ZH 2014 0.5 4028.000000 2 NaN"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df5 = pd.DataFrame({\"Province\": [\"FL\", \"NH\", \"FL\"], \"Population\": [\"100000\", \"200000\", \"50000\"]})\n",
"df.merge(df5, how='outer')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This was a many-to-many merge. Even though if you think about it, the behavior is what you expect, you might still not think about it and be surprised!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercises\n",
"\n",
"* Create two dataframes that can be merged on multiples keys;\n",
"* Merge them;\n",
"* Create two dataframe that can be merged on a key;\n",
"* Make that key the index;\n",
"* Merge them! (you might want to use: `left_index=True` or `right_index=True`).\n",
"* Pick the two dataframe created on the first point. Convert the two columns of a dataframe to a MultiIndex;\n",
"* Merge them!\n",
"\n",
"pandas also provide the `join` keyword when merging via the index. Experiment with it a bit."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Combining data with overlap\n",
"Sometimes some data is missing, and it can be \"patched\" with another dataset. Let's take a look."
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"serie_a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],\n",
" index=['f', 'e', 'd', 'c', 'b', 'a'])\n",
"serie_b = pd.Series(np.arange(len(serie_a), dtype=np.float64),\n",
" index=['f', 'e', 'd', 'c', 'b', 'a'])"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"f NaN\n",
"e 2.5\n",
"d NaN\n",
"c 3.5\n",
"b 4.5\n",
"a NaN\n",
"dtype: float64"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie_a"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"f 0\n",
"e 1\n",
"d 2\n",
"c 3\n",
"b 4\n",
"a 5\n",
"dtype: float64"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie_b"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Let's say we want to update `a` with the values from `b`. The num-pythonic way to do that is"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"f 0.0\n",
"e 2.5\n",
"d 2.0\n",
"c 3.5\n",
"b 4.5\n",
"a 5.0\n",
"dtype: float64"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.Series(np.where(pd.isnull(serie_a), serie_b, serie_a), index=serie_a.index)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"That's a bit verbose for something so simple. What about this:"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"f 0.0\n",
"e 2.5\n",
"d 2.0\n",
"c 3.5\n",
"b 4.5\n",
"a 5.0\n",
"dtype: float64"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"serie_a.combine_first(serie_b)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercise\n",
"\n",
"* Create two dataframes, with overlapping indices, one without NaN's, one with some NaN's and combine them."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Stacking and unstacking\n",
"Sometimes the data is not in a format that suits further analysis (see the Tidy Data paper by Hadley Wickham). To help there, pandas has some neat features; among them: `stack` and `unstack`. Let's explore them with an example: the effect of two treatments on patients."
]
},
{
"cell_type": "code",
"execution_count": 153,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>trtA</th>\n",
" <th>trtB</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>John Smith</th>\n",
" <td>NaN</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <td>16</td>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" trtA trtB\n",
"John Smith NaN 3\n",
"Jane Doe 16 11\n",
"Mary Johnson 1 3"
]
},
"execution_count": 153,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"patients = pd.DataFrame([[None, 3], [16, 11], [1, 3]], \n",
" columns=[\"trtA\", \"trtB\"], \n",
" index=[\"John Smith\", \"Jane Doe\", \"Mary Johnson\"])\n",
"patients"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"This structure makes it difficult to reason about the data and to add new variables. Let's say we want to add the weather as a variable. What would you do? Add 2 * (#different weather combinations) columns?"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"A better structure is the following"
]
},
{
"cell_type": "code",
"execution_count": 155,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>trt</th>\n",
" </tr>\n",
" <tr>\n",
" <th>index</th>\n",
" <th>treatment</th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <th>A</th>\n",
" <td>16</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <th>A</th>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>John Smith</th>\n",
" <th>B</th>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <th>B</th>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <th>B</th>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" trt\n",
"index treatment \n",
"Jane Doe A 16\n",
"Mary Johnson A 1\n",
"John Smith B 3\n",
"Jane Doe B 11\n",
"Mary Johnson B 3"
]
},
"execution_count": 155,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"long_patients = pd.wide_to_long(patients.reset_index(), ['trt'], i='index', j='treatment').dropna()\n",
"long_patients"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We immediately see that adding the weather is easy"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>trt</th>\n",
" <th>weather</th>\n",
" </tr>\n",
" <tr>\n",
" <th>index</th>\n",
" <th>treatment</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <th>A</th>\n",
" <td>16</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <th>A</th>\n",
" <td>1</td>\n",
" <td>10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>John Smith</th>\n",
" <th>B</th>\n",
" <td>3</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <th>B</th>\n",
" <td>11</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <th>B</th>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" trt weather\n",
"index treatment \n",
"Jane Doe A 16 3\n",
"Mary Johnson A 1 10\n",
"John Smith B 3 9\n",
"Jane Doe B 11 1\n",
"Mary Johnson B 3 2"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"long_patients['weather'] = [3, 10, 9, 1, 2]\n",
"long_patients"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"We can go back to where we were (but we must give up the weather) with `pivot`"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th>treatment</th>\n",
" <th>A</th>\n",
" <th>B</th>\n",
" </tr>\n",
" <tr>\n",
" <th>index</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Jane Doe</th>\n",
" <td>16</td>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>John Smith</th>\n",
" <td>NaN</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mary Johnson</th>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"treatment A B\n",
"index \n",
"Jane Doe 16 11\n",
"John Smith NaN 3\n",
"Mary Johnson 1 3"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"long_patients.reset_index().pivot(\"index\", \"treatment\", \"trt\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Removing duplicates\n",
"Removing duplicates is another extremly common operations in data analysis (`SELECT DISTINCT ... FROM ...`)"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>2011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>2012</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>2011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>2012</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Year\n",
"0 0.2 FL 2011\n",
"1 0.2 FL 2012\n",
"2 0.5 NH 2011\n",
"3 0.5 NH 2012\n",
"4 0.5 ZH 2014"
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6 = pd.DataFrame({'Literacy': {0: 0.2,\n",
" 1: 0.2,\n",
" 2: 0.5,\n",
" 3: 0.5,\n",
" 4: 0.5},\n",
" 'Province': {0: 'FL', 1: 'FL', 2: 'NH', 3: 'NH', 4: 'ZH'},\n",
" 'Year': {0: 2011, 1: 2012, 2: 2011, 3: 2012, 4: 2014}})\n",
"df6"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>2011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" <td>2012</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>2011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" <td>2012</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Year\n",
"0 0.2 FL 2011\n",
"1 0.2 FL 2012\n",
"2 0.5 NH 2011\n",
"3 0.5 NH 2012\n",
"4 0.5 ZH 2014"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6.drop_duplicates()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Like when working with SQL, duplicates might not be there when working with the full dataset, but might be there when working with a subset of columns"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province\n",
"0 0.2 FL\n",
"1 0.2 FL\n",
"2 0.5 NH\n",
"3 0.5 NH\n",
"4 0.5 ZH"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6[[\"Literacy\", \"Province\"]]"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.2</td>\n",
" <td>FL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.5</td>\n",
" <td>NH</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.5</td>\n",
" <td>ZH</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province\n",
"0 0.2 FL\n",
"2 0.5 NH\n",
"4 0.5 ZH"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6[[\"Literacy\", \"Province\"]].drop_duplicates()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Applying a function to a dataframe\n",
"These dataframes are all nice and dandy but sometimes we need to do something with those value. `apply` is a function that applies a function along the axis of a DataFrame. Objects passed to functions are Series objects."
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Literacy 5\n",
"Province 5\n",
"Year 5\n",
"dtype: int64"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6.apply(len)"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 3\n",
"1 3\n",
"2 3\n",
"3 3\n",
"4 3\n",
"dtype: int64"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df6.apply(len, axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Besides functions that works on Series, we can also pass functions that work on element of the serie"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Literacy</th>\n",
" <th>Province</th>\n",
" <th>Year</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2.2</td>\n",
" <td>FL</td>\n",
" <td>2013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2.2</td>\n",
" <td>FL</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2.5</td>\n",
" <td>NH</td>\n",
" <td>2013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2.5</td>\n",
" <td>NH</td>\n",
" <td>2014</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2.5</td>\n",
" <td>ZH</td>\n",
" <td>2016</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Literacy Province Year\n",
"0 2.2 FL 2013\n",
"1 2.2 FL 2014\n",
"2 2.5 NH 2013\n",
"3 2.5 NH 2014\n",
"4 2.5 ZH 2016"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def if_float_add_two(el):\n",
" try:\n",
" return el + 2\n",
" except:\n",
" return el\n",
" \n",
"df6.apply(if_float_add_two)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercises\n",
"\n",
"* Write a functions that replaces the province code with the province name;\n",
"* Create a new column in `df6` with the resulting mapping;\n",
"* Try to use the function `applymap`, that operates on an element base."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Replacing values\n",
"Sometimes we wish to replace values from a dataframe (or columns in the dataframe). "
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.966232</td>\n",
" <td>0.167191</td>\n",
" <td>0.401429</td>\n",
" <td>0.400972</td>\n",
" <td>0.826399</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.450127</td>\n",
" <td>0.493164</td>\n",
" <td>0.092299</td>\n",
" <td>0.923796</td>\n",
" <td>0.925490</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>999.000000</td>\n",
" <td>0.198726</td>\n",
" <td>999.000000</td>\n",
" <td>0.111756</td>\n",
" <td>999.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.681136</td>\n",
" <td>999.000000</td>\n",
" <td>0.020663</td>\n",
" <td>999.000000</td>\n",
" <td>999.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.484590</td>\n",
" <td>0.723809</td>\n",
" <td>999.000000</td>\n",
" <td>0.150108</td>\n",
" <td>0.853176</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>999.000000</td>\n",
" <td>999.000000</td>\n",
" <td>0.555454</td>\n",
" <td>0.487269</td>\n",
" <td>0.300985</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>0.503167</td>\n",
" <td>0.180310</td>\n",
" <td>0.042811</td>\n",
" <td>0.758912</td>\n",
" <td>0.866983</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>0.737835</td>\n",
" <td>999.000000</td>\n",
" <td>0.927041</td>\n",
" <td>0.113381</td>\n",
" <td>0.348598</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>999.000000</td>\n",
" <td>0.146850</td>\n",
" <td>999.000000</td>\n",
" <td>0.603495</td>\n",
" <td>0.687472</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>999.000000</td>\n",
" <td>0.520759</td>\n",
" <td>0.306461</td>\n",
" <td>999.000000</td>\n",
" <td>0.774614</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2 3 4\n",
"0 0.966232 0.167191 0.401429 0.400972 0.826399\n",
"1 0.450127 0.493164 0.092299 0.923796 0.925490\n",
"2 999.000000 0.198726 999.000000 0.111756 999.000000\n",
"3 0.681136 999.000000 0.020663 999.000000 999.000000\n",
"4 0.484590 0.723809 999.000000 0.150108 0.853176\n",
"5 999.000000 999.000000 0.555454 0.487269 0.300985\n",
"6 0.503167 0.180310 0.042811 0.758912 0.866983\n",
"7 0.737835 999.000000 0.927041 0.113381 0.348598\n",
"8 999.000000 0.146850 999.000000 0.603495 0.687472\n",
"9 999.000000 0.520759 0.306461 999.000000 0.774614"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_df = pd.DataFrame(np.random.rand(10, 5)).applymap(lambda ar: np.where(np.random.rand() < 0.2, 999, ar))\n",
"test_df"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"In the above example we immediately see that the `999`'s do not really belong to the dataset. Replace to the rescue!"
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.966232</td>\n",
" <td>0.167191</td>\n",
" <td>0.401429</td>\n",
" <td>0.400972</td>\n",
" <td>0.826399</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.450127</td>\n",
" <td>0.493164</td>\n",
" <td>0.092299</td>\n",
" <td>0.923796</td>\n",
" <td>0.925490</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.852033</td>\n",
" <td>0.198726</td>\n",
" <td>0.478442</td>\n",
" <td>0.111756</td>\n",
" <td>0.839788</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.681136</td>\n",
" <td>0.506961</td>\n",
" <td>0.020663</td>\n",
" <td>0.545382</td>\n",
" <td>0.839788</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.484590</td>\n",
" <td>0.723809</td>\n",
" <td>0.478442</td>\n",
" <td>0.150108</td>\n",
" <td>0.853176</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>0.852033</td>\n",
" <td>0.506961</td>\n",
" <td>0.555454</td>\n",
" <td>0.487269</td>\n",
" <td>0.300985</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>0.503167</td>\n",
" <td>0.180310</td>\n",
" <td>0.042811</td>\n",
" <td>0.758912</td>\n",
" <td>0.866983</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>0.737835</td>\n",
" <td>0.506961</td>\n",
" <td>0.927041</td>\n",
" <td>0.113381</td>\n",
" <td>0.348598</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>0.852033</td>\n",
" <td>0.146850</td>\n",
" <td>0.478442</td>\n",
" <td>0.603495</td>\n",
" <td>0.687472</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>0.852033</td>\n",
" <td>0.520759</td>\n",
" <td>0.306461</td>\n",
" <td>0.545382</td>\n",
" <td>0.774614</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2 3 4\n",
"0 0.966232 0.167191 0.401429 0.400972 0.826399\n",
"1 0.450127 0.493164 0.092299 0.923796 0.925490\n",
"2 0.852033 0.198726 0.478442 0.111756 0.839788\n",
"3 0.681136 0.506961 0.020663 0.545382 0.839788\n",
"4 0.484590 0.723809 0.478442 0.150108 0.853176\n",
"5 0.852033 0.506961 0.555454 0.487269 0.300985\n",
"6 0.503167 0.180310 0.042811 0.758912 0.866983\n",
"7 0.737835 0.506961 0.927041 0.113381 0.348598\n",
"8 0.852033 0.146850 0.478442 0.603495 0.687472\n",
"9 0.852033 0.520759 0.306461 0.545382 0.774614"
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_df.replace(999, {col: test_df[col].median() for col in test_df.columns})"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercises\n",
"\n",
"* The above method is suboptimal for what we want to do. Write a function that computes the mean ignoring values larges than `x`;\n",
"* Use the function to perform a better replacement of `test_df`."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"An alternative approach for outlier removal is when these outliers were actually supposed to be on the edge of the measurable interval. F.e.:"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>-0.843185</td>\n",
" <td>-0.585136</td>\n",
" <td>-0.461297</td>\n",
" <td>-10.000000</td>\n",
" <td>-0.367999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>-0.848863</td>\n",
" <td>-0.014929</td>\n",
" <td>0.079529</td>\n",
" <td>0.464519</td>\n",
" <td>-0.787048</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.499702</td>\n",
" <td>10.000000</td>\n",
" <td>10.000000</td>\n",
" <td>0.235484</td>\n",
" <td>0.338507</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>-0.219157</td>\n",
" <td>-0.162251</td>\n",
" <td>0.897867</td>\n",
" <td>10.000000</td>\n",
" <td>-10.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>-0.451423</td>\n",
" <td>0.518030</td>\n",
" <td>0.712854</td>\n",
" <td>0.073103</td>\n",
" <td>10.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>-10.000000</td>\n",
" <td>-0.207863</td>\n",
" <td>0.948673</td>\n",
" <td>-0.256013</td>\n",
" <td>-10.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>-0.507464</td>\n",
" <td>0.376993</td>\n",
" <td>0.157470</td>\n",
" <td>0.791349</td>\n",
" <td>10.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>10.000000</td>\n",
" <td>-0.509091</td>\n",
" <td>0.129875</td>\n",
" <td>-0.214538</td>\n",
" <td>0.746456</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>10.000000</td>\n",
" <td>-10.000000</td>\n",
" <td>0.282582</td>\n",
" <td>0.124795</td>\n",
" <td>-10.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>-10.000000</td>\n",
" <td>-0.554200</td>\n",
" <td>10.000000</td>\n",
" <td>-0.541893</td>\n",
" <td>0.336246</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2 3 4\n",
"0 -0.843185 -0.585136 -0.461297 -10.000000 -0.367999\n",
"1 -0.848863 -0.014929 0.079529 0.464519 -0.787048\n",
"2 0.499702 10.000000 10.000000 0.235484 0.338507\n",
"3 -0.219157 -0.162251 0.897867 10.000000 -10.000000\n",
"4 -0.451423 0.518030 0.712854 0.073103 10.000000\n",
"5 -10.000000 -0.207863 0.948673 -0.256013 -10.000000\n",
"6 -0.507464 0.376993 0.157470 0.791349 10.000000\n",
"7 10.000000 -0.509091 0.129875 -0.214538 0.746456\n",
"8 10.000000 -10.000000 0.282582 0.124795 -10.000000\n",
"9 -10.000000 -0.554200 10.000000 -0.541893 0.336246"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"my_ar = np.random.rand(10, 5) * 2 - 1\n",
"test_df1 = pd.DataFrame(my_ar).applymap(lambda ar: np.where(np.random.random() < .3, np.sign(ar) * 10, ar))\n",
"test_df1"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The outliers should be clearly limited between -1 and 1. Assuming that the sign of the outliers is a good indication of their direction, we can solve it with"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>-0.843185</td>\n",
" <td>-0.585136</td>\n",
" <td>-0.461297</td>\n",
" <td>-1.000000</td>\n",
" <td>-0.367999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>-0.848863</td>\n",
" <td>-0.014929</td>\n",
" <td>0.079529</td>\n",
" <td>0.464519</td>\n",
" <td>-0.787048</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.499702</td>\n",
" <td>1.000000</td>\n",
" <td>1.000000</td>\n",
" <td>0.235484</td>\n",
" <td>0.338507</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>-0.219157</td>\n",
" <td>-0.162251</td>\n",
" <td>0.897867</td>\n",
" <td>1.000000</td>\n",
" <td>-1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>-0.451423</td>\n",
" <td>0.518030</td>\n",
" <td>0.712854</td>\n",
" <td>0.073103</td>\n",
" <td>1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>-1.000000</td>\n",
" <td>-0.207863</td>\n",
" <td>0.948673</td>\n",
" <td>-0.256013</td>\n",
" <td>-1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>-0.507464</td>\n",
" <td>0.376993</td>\n",
" <td>0.157470</td>\n",
" <td>0.791349</td>\n",
" <td>1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>1.000000</td>\n",
" <td>-0.509091</td>\n",
" <td>0.129875</td>\n",
" <td>-0.214538</td>\n",
" <td>0.746456</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>1.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.282582</td>\n",
" <td>0.124795</td>\n",
" <td>-1.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>-1.000000</td>\n",
" <td>-0.554200</td>\n",
" <td>1.000000</td>\n",
" <td>-0.541893</td>\n",
" <td>0.336246</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2 3 4\n",
"0 -0.843185 -0.585136 -0.461297 -1.000000 -0.367999\n",
"1 -0.848863 -0.014929 0.079529 0.464519 -0.787048\n",
"2 0.499702 1.000000 1.000000 0.235484 0.338507\n",
"3 -0.219157 -0.162251 0.897867 1.000000 -1.000000\n",
"4 -0.451423 0.518030 0.712854 0.073103 1.000000\n",
"5 -1.000000 -0.207863 0.948673 -0.256013 -1.000000\n",
"6 -0.507464 0.376993 0.157470 0.791349 1.000000\n",
"7 1.000000 -0.509091 0.129875 -0.214538 0.746456\n",
"8 1.000000 -1.000000 0.282582 0.124795 -1.000000\n",
"9 -1.000000 -0.554200 1.000000 -0.541893 0.336246"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_df1[abs(test_df1) > 1] = np.sign(test_df1)\n",
"test_df1"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Binary decomposition of categorical variables\n",
"Very often in machine learning we need to replace a categorical variable with `n` distinct value in a vector in $n$-dimensional space. This can be a boring and cumbersome (and error-prone) process."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"sector = np.repeat([\"Automotive\", \"Energy\", \"Transportation\", \"Infrastructure\"], 5)\n",
"company = np.random.randint(0, 1000, size=len(sector))\n",
"revenue = np.random.random(size=len(sector)) * 10 ** 9\n",
"size = revenue * 10 **(-5) + np.random.random(size=len(sector)) * 10 ** 3.5\n",
"clients = pd.DataFrame({\"sector\": sector, \"company\": company, \"revenue\": revenue, \"size\": size})"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269dd014400>"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nrkJggg==\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269dcf1c940>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"clients.plot(x=\"size\", y=\"revenue\", kind='scatter')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"In the `clients` datasets there is a clear correlation between size and revenue (duh!). But we want to go further and see whether the industry affects the revenue (we shouldn't try to do it anyway because we have too little data points, but that's for another day). In order to do that we want to use a method that requires standardized variables (mean 0, variance 1) along all axis. That means industry as well.\n",
"\n",
"\n",
"Let's see how to approach this."
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Automotive</th>\n",
" <th>Energy</th>\n",
" <th>Infrastructure</th>\n",
" <th>Transportation</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Automotive Energy Infrastructure Transportation\n",
"6 0 1 0 0\n",
"15 0 0 1 0\n",
"16 0 0 1 0\n",
"10 0 0 0 1"
]
},
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"binary_industries = pd.get_dummies(clients.sector)\n",
"binary_industries.sample(frac=.2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"All the datapoints have now a binary decomposition! It's now a matter of scaling it."
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Automotive</th>\n",
" <th>Energy</th>\n",
" <th>Infrastructure</th>\n",
" <th>Transportation</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>count</th>\n",
" <td>2.000000e+01</td>\n",
" <td>2.000000e+01</td>\n",
" <td>2.000000e+01</td>\n",
" <td>2.000000e+01</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>-1.221245e-16</td>\n",
" <td>-3.330669e-17</td>\n",
" <td>-6.661338e-17</td>\n",
" <td>-3.330669e-17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>1.025978e+00</td>\n",
" <td>1.025978e+00</td>\n",
" <td>1.025978e+00</td>\n",
" <td>1.025978e+00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" <td>-5.773503e-01</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>-5.551115e-17</td>\n",
" <td>-5.551115e-17</td>\n",
" <td>-5.551115e-17</td>\n",
" <td>-5.551115e-17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>1.732051e+00</td>\n",
" <td>1.732051e+00</td>\n",
" <td>1.732051e+00</td>\n",
" <td>1.732051e+00</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Automotive Energy Infrastructure Transportation\n",
"count 2.000000e+01 2.000000e+01 2.000000e+01 2.000000e+01\n",
"mean -1.221245e-16 -3.330669e-17 -6.661338e-17 -3.330669e-17\n",
"std 1.025978e+00 1.025978e+00 1.025978e+00 1.025978e+00\n",
"min -5.773503e-01 -5.773503e-01 -5.773503e-01 -5.773503e-01\n",
"25% -5.773503e-01 -5.773503e-01 -5.773503e-01 -5.773503e-01\n",
"50% -5.773503e-01 -5.773503e-01 -5.773503e-01 -5.773503e-01\n",
"75% -5.551115e-17 -5.551115e-17 -5.551115e-17 -5.551115e-17\n",
"max 1.732051e+00 1.732051e+00 1.732051e+00 1.732051e+00"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.preprocessing import scale\n",
"binary_industries_scaled = pd.DataFrame(scale(binary_industries))\n",
"binary_industries_scaled.columns = binary_industries.columns\n",
"binary_industries_scaled.describe()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Reattaching everything to clients is a matter of using `join`"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>company</th>\n",
" <th>revenue</th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" <th>Automotive</th>\n",
" <th>Energy</th>\n",
" <th>Infrastructure</th>\n",
" <th>Transportation</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>962</td>\n",
" <td>4.541239e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6049.947310</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>439</td>\n",
" <td>2.832645e+07</td>\n",
" <td>Energy</td>\n",
" <td>3224.815102</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>229</td>\n",
" <td>8.869656e+08</td>\n",
" <td>Transportation</td>\n",
" <td>11370.846510</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>406</td>\n",
" <td>2.831127e+08</td>\n",
" <td>Automotive</td>\n",
" <td>4427.557218</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>33</td>\n",
" <td>9.096190e+07</td>\n",
" <td>Automotive</td>\n",
" <td>1631.131274</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>810</td>\n",
" <td>3.003936e+08</td>\n",
" <td>Automotive</td>\n",
" <td>4938.201337</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>380</td>\n",
" <td>2.631976e+08</td>\n",
" <td>Energy</td>\n",
" <td>5513.558508</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>481</td>\n",
" <td>2.220322e+08</td>\n",
" <td>Transportation</td>\n",
" <td>2512.758196</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>618</td>\n",
" <td>7.264740e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>7575.894157</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>924</td>\n",
" <td>8.510332e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" <td>-0.577350</td>\n",
" <td>-0.577350</td>\n",
" <td>1.732051</td>\n",
" <td>-0.577350</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" company revenue sector size Automotive Energy \\\n",
"14 962 4.541239e+08 Transportation 6049.947310 -0.577350 -0.577350 \n",
"6 439 2.832645e+07 Energy 3224.815102 -0.577350 1.732051 \n",
"11 229 8.869656e+08 Transportation 11370.846510 -0.577350 -0.577350 \n",
"2 406 2.831127e+08 Automotive 4427.557218 1.732051 -0.577350 \n",
"3 33 9.096190e+07 Automotive 1631.131274 1.732051 -0.577350 \n",
"0 810 3.003936e+08 Automotive 4938.201337 1.732051 -0.577350 \n",
"9 380 2.631976e+08 Energy 5513.558508 -0.577350 1.732051 \n",
"10 481 2.220322e+08 Transportation 2512.758196 -0.577350 -0.577350 \n",
"16 618 7.264740e+08 Infrastructure 7575.894157 -0.577350 -0.577350 \n",
"19 924 8.510332e+08 Infrastructure 10292.408394 -0.577350 -0.577350 \n",
"\n",
" Infrastructure Transportation \n",
"14 -0.577350 1.732051 \n",
"6 -0.577350 -0.577350 \n",
"11 -0.577350 1.732051 \n",
"2 -0.577350 -0.577350 \n",
"3 -0.577350 -0.577350 \n",
"0 -0.577350 -0.577350 \n",
"9 -0.577350 -0.577350 \n",
"10 -0.577350 1.732051 \n",
"16 1.732051 -0.577350 \n",
"19 1.732051 -0.577350 "
]
},
"execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.join(binary_industries_scaled).sample(frac=0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Plotting in pandas: slightly less painful than matplotlib\n",
"pandas doesn't have a kitchen sink, but it can, among the myriad other things, plot. \n",
"\n",
"The `plot` method of a dataframe is just a wrapper around `plt.plot`: we already saw above that it can do basic plotting pretty easily"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269de2ace80>"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nrkJggg==\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269de29f5c0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"clients.plot(x=\"size\", y=\"revenue\", kind='scatter')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Plotting also works on series"
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269de2c46d8>"
]
},
"execution_count": 89,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAEECAYAAADJSpQfAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XtcVHXeB/DP7ww3QRQHFRUiRFQMwyQxM9NIzEtuWiZl\nbVu7tm7qVrZtabvPru1mT4nmrq3p9lht+2w9JbWbXbRaKm0rNS8MppAKG3nNG4iCiMCc7/PHJMWC\nzgAz8zswn/frta+dy5kzHwb7cOY3Z34/JSICIiJq1wzdAYiIyPdY9kREAYBlT0QUAFj2REQBgGVP\nRBQAWPZERAEgyN0GtbW1mD9/Purq6uB0OjFs2DBMnTq1wTaFhYXIzs5GTEwMAGDo0KGYMmWKbxIT\nEVGzuT2yDw4Oxvz585GdnY1FixYhPz8fxcXFjbYbMGAAFi5ciIULF3pc9AUFBc1P7GNWzARYMxcz\neYaZPGfFXO0lk0fDOKGhoQBcR/lOp7PJbVry3az28iL6gxVzMZNnmMlzVszVXjK5HcYBANM0MW/e\nPBw5cgRjx45FUlJSo22Kiorw0EMPwW6344477kBcXFyzwxARkW94VPaGYSA7OxtVVVVYtGgRDhw4\n0KDMExMTsXz5coSGhsLhcGDRokVYunSpz0ITEVHzqObOjfP6668jLCwMEydOPO82s2fPxsKFC9Gx\nY8cGtxcUFDR4+5GVldXMuEREBAA5OTn1l1NSUpCSknLB7d0e2Z86dQpBQUEIDw9HTU0NduzYgUmT\nJjXYpry8HFFRUQBQ/+Htfxb9+QIdOnTIXQS/ioyMREVFhe4YjVgxFzN5hpk8Z8VcVszUq1evZh8s\nuy378vJyPPPMMzBNEyKC4cOHIy0tDbm5uVBKITMzE5s2bUJubi5sNhtCQkIwZ86cFv8QRETkfc0e\nxvE2Htl7xoq5mMkzzOQ5K+ayYqZevXo1+zH8Bi0RUQBg2RMRBQCWPVGAkbo61O7YpjsG+RnLnijA\nyPo1OP34LyEH9+qOQn7EsicKIHLqBGTNawi5Zhxk7eu645AfseyJAoj843+hhl+LDj/6OaQwD3LU\nWmfDke+w7IkChHy1G7LTATXxVqjwCKhrJkDe+4fuWOQnLHuiACCmCfOV/4G66UdQHcIBAGr0DyDb\nNkDKjmlOZ11SfQZSV6s7hld4NBEaEbVt8tkHgM0GNeya+ttUx05QIzIh/1wNdetP9YWzKDGdMJ98\nGCePHQYu6g3Vuz+Q2A+qdz8gujuUUrojNgvLnqidk6pKyOqXYNw3H8po+GZejZkMc/7PIROmQnWK\n0pTQmmTLp0BIKDo/+w9U7HRASvZANn8CWfUcYJpAYn+o3v2gEvsDCX3r3zFZFcueqJ2Tt16BuuwK\nqIv7NLpPRdmhhl4N+eBNqJvu1JDOmsTphLz1Cozb74HqEA6VnAqVnOq6TwQoOw6U7IaU7IH51v8B\n+0sAezdX8Sf2c70L6BUPZbNp/km+w7Inasfk4F7I5n/B+N0z591Gjb0J5oJfQMZOgYpoPFttIJJN\n64AoOzBgUKP7lFJAdDcguhvUkBGu7evqgIN7ISW7geIvYea+CZwoAy7u8+3Rfz+gd3+oLtH+/lHq\nseyJ2ikRcX0oO/EWqMhO591OdY2BSk2HrHsHauKtfkxoTVJXC3n7VRg/ecDjcXkVFOQq9ov7ANdM\ncO3ndCXwdRGkZDfMTz8A/vYMEBTiGv45N/Z/cRJUaJgvf5x6LHui9mrbZ0DlKahR491uqibcDDP7\nEUjmJKiwDn4IZ13yaS7QIxaq34UXA3FHRXQEUgZDpQx27VcEOHYY8tVuoGQPzG0bgIN7gZhe3334\nm9gfiIlt9NmKN7DsidohOVsN87W/uI5OPRg3Vj3ioPoNhPzrPajrbvRDQmuSmrOQNTkwZv3a6/tW\nSgHde0J17wl8e1aU1NYA+76ClOwBCvNhrskBKiuAhCSo3v2/Hf7p55UPz1n2RO2QvPs6VJ9kqP4D\nPX6MmjAV5tO/h2RcDxUc4sN01iUfv+c6s6Z3X788nwoOAfokQ/VJ/i5DxUngqz2u4Z+P3gFKioCI\njq5hn/oPf5s/nz3LnqidkWOHIR+/C+M3S5v1OBWfCMQnQj77AOrbcedAItVnIO/9HcYDv9eaQ0V2\nBgalQw1Kd+UyTeDIQchXe4CS3TA3rgOuvrbZ+2XZE7Uz5qrnoMZMhrJ3bfZjjeuzYK5cDBlxnetD\nxwAiH70D1f9SqLgE3VEaUIYB9LwIqudFwFWjW7wfTpdA1I7Izm3AN/uhxkxu0eNVn2Sgawxk88de\nTmZtUlUJyX0T6oZpuqP4DMueqJ2QulqYrz4H45a7oYKDW7wf4/osyLuvQ0ynF9NZm+S+CZWaDtUj\nTncUn2HZE7UT8sFbrrM9UtNbt6PkVKBDBGTbRu8EszipOAVZtxZq4i26o/gUy56oHZDyUsj7/4Bx\n692t3pdSynV0v/Y117nh7Zy8/3eoIVdBdeuhO4pPseyJ2gF5/UWoq8dCdW/+KXlNSk0HIMAXW72z\nP4uS8jLIJ7lQE7J0R/E5lj1RGydFhZA9BVATpnptn0op13n3a3Pa9dG9vPs61PBrW3TmUlvDsidq\nw8R0wnzlWaib7/L6NAfq8uHA6Upg1xde3a9VSOkxyOcfQ42fojuKX7Dsidow+df7QIcIqPSrvb5v\nZdigxk+BufY1r+/bCmTNKqiRY6E6ddEdxS9Y9kRtlFSecs25Pu2nPls1SV1xDXD0G8i/d/lk/7rI\n0UMQx0aosYEzDxDLnqiNktUvuc4iievts+dQQUFQ49rf0b28vQrq2h9ARUTqjuI3br8PXVtbi/nz\n56Ourg5OpxPDhg3D1KmNPwh64YUXkJ+fj9DQUMyePRsJCQm+yEtEAGTfvyF5G2E8ttznz6VGZELW\n5ED2l0Bd5Ls/LP4ih/ZBCvJg3Pas7ih+5fbIPjg4GPPnz0d2djYWLVqE/Px8FBcXN9jG4XDgyJEj\nePrppzFjxgysXLnSZ4GJAp1rUZKVUJNv98uRqQoOgRozCdJOju7lrVegrpts+TVjvc2jYZzQ0FAA\nrqN8p7PxV6i3bNmCUaNGAQD69u2LqqoqlJeXezEmEZ0jn38M1JyFGjHGb8+pRo2D7N4BOXzAb8/p\nC7Lv35DiQqiM63VH8TuPyt40TTz88MOYMWMGUlNTkZSU1OD+srIyREd/t7ai3W5HWVmZd5MSEaS6\nCvL3v8K47WdQhv8Ws1ZhHaAyroe8+3e/PacvmG/+H9T4m/22FKCVeFT2hmEgOzsbK1asQFFREQ4c\naNt/3YnaKnknB2pAaoPFLvxFXTsRsn0zpPSo35/bG+Tfu4D9JVAjx+qOokWzJqwODw9HSkoK8vPz\nERf33exwdrsdpaWl9ddLS0tht9sbPb6goAAFBQX117OyshAZaa1Pw0NCQiyXCbBmLmbyjLcyOQ/t\nQ+WGDxC56C8wWrm/FmWKjMSZ0RMhH72N8J/MadXzezWXhyrXrELolB8h1B7tfmM/ZWqNnJyc+ssp\nKSlISbnwmrluy/7UqVMICgpCeHg4ampqsGPHDkyaNKnBNkOGDMH777+P4cOHY8+ePYiIiEBUVOM1\nE5sKVFFR4S6CX0VGRlouE2DNXMzkGW9kEhGYLyyFGjcFp23BQCv319JMMmoczN/MRt2YG6GiGh/Q\ntZavfn+yewfMwwdhXj4CNc3cv1X/TWVlNW8+H7dlX15ejmeeeQamaUJEMHz4cKSlpSE3NxdKKWRm\nZiItLQ0OhwP33nsvwsLCMHPmzBb/EETUhO2bgeNHoa6dqDWG6tQFatg1rvnfp/5YaxZPiQjM1S9D\n/WBawK2+9X1uf/L4+HgsXLiw0e1jxjQ8E2D69OneS0VE9aS2BmbO8zB+OBMqqOWLkniLGnsjzN/d\nDxk/BapjJ91x3CtwAJWnoK4YqTuJVvwGLZHFyftvAHEJUJcM1h0FAKDs3aDSroR8+I7uKG65jupf\ngjHpNr+evWRFLHsiC5PSY5AP34KRZa13zmr8FMj6tZAzVbqjXNj2zwGnE0gbrjuJdix7IguT116A\nyrgeqmuM7igNqO69oC65DLL+Xd1RzktME+bql2FMvh3KYNXxFSCyKPlyO+TrIqhx1pxvXU2YCvng\nTUjNWd1RmiRbPwVCQr9ddYtY9kQWJHV1MF9dCSPrJ1AhobrjNEnFXgwk9od8kqs7SiPidLqmf558\nu8+mf25rWPZEFiTr1wKduwCDr9Qd5YKMCVmQ9/8BqavVHaUB2bQe6BwFDLhMdxTLYNkTWYycKoes\nyYFxq+8WJfEW1bsv0DMOsnGd7ij1pK4W8vYrMCb90PKvnz+x7IksRt74G9SwDKhe8bqjeMSYkAV5\n93VIEzPi6iCffgD0iIXqd+HpAwINy57IQqSkCLJjG9QPbtUdxXP9UoDOXVwfiGomNWdd74om/VB3\nFMth2RNZhJgmzFeehbrxDqjwCN1xPKaUch3dr30NYppas8i/3gMSklzDS9QAy57IImTjR4BSUFdm\n6I7SfAPTgKBg1xw+mkj1Gci7f4cx6TZtGayMZU9kAVJ1GvLG32BMm9EmvwDkOrqfCnNNDkRESwZZ\ntwaq/6U+XYC9LWt7/6qI2iF5+xWo1HSohDY8/DB4GFBzFijM9/tTS9VpyD9XQ/1gmt+fu61g2RNp\nJgf3QT7/GOrGO3RHaRVlGFDjb4a5Nsf9xl4mH7wJdekQqJ5x7jcOUCx7Io1EBOar/wN1/S1QkZ11\nx2k1NXQkUHYcUlTot+eUylOuIZy2dAaTBix7Ip3yNgAVJ6GuGa87iVcomw1q3BS/Ht3Le/+Auvwq\nqG49/PacbRHLnkgTOXsWZs4LMKb9DMrWfuZaV8NHAwe+huwt9vlzyckTkE9zoSY0b4m+QMSyJ9JE\n3nsdqk8yVP+BuqN4lQoOhrruRphrX/P5c8m7r0NdmQFl7+rz52rrWPZEGsixw5D1a6FubhvruDaX\nGjkWKCqEHNrns+eQsmOQTeuhxltzCmirYdkTaWDmPA+VOandHpGq0DCo0T+AvPu6z55D1uRAjbwO\nqlMXnz1He8KyJ/Iz2ZkHHNwLdd1k3VF8SmVcD9m5DXLssNf3LUe/geRtgBp7k9f33V6x7In8SOpq\nYa5aCeOWu6GCQ3TH8SkVHgE1cjzkvb97fd/yzqtQGROhIiK9vu/2imVPzSa1tZAvt8OsOKk7Spsj\nH74DdO0RMEvlqcwbIFs/g5wo9do+5Zv9kJ15UJk3eG2fgSBIdwBqG6T6DLBzGyRvo2sYomt3VJyp\ngrr7Qag+ybrjtQlSXgZ573UYc7MDZlENFdkJavhoyD/fgLrlbq/sU956BWrM5DY1M6gVsOzpvOR0\nBWT7ZkjeRmD3DqBPMlTalTBuvRuqUxeE7d6O0888DjVhKtToHwRMgbWU/P2vUCOug+oRqzuKX6mx\nk2HOvxcyYWqrvyUs+0sgRYUw7rrPS+kCB8ueGpDyMkj+JlfBf10EJKdCDbkK6idzoMI7Ntg2eMgI\nGPYYmH9eCCkuhHHnfVAdwjUltzYp/hKy6wsYjy3XHcXvVFQ01JARkA/eavX8P+abL0ONnwIVGual\ndIGDZU+uc77zNkIcG4FvDkClDoFxzQQgJQ0qNPSCj1XdesCYtxCy6jmYCx6Acc88qIs4xez3iel0\nLUpy811QYR10x9FCjbsJ5uMPQsbe2OigwVPy1W5g31dQP3vYy+kCA8s+AIkIcGifq+DzNgIny6AG\nD4Mx8VYg+VKooOBm7U8Fh0D9cBbMzz+GueQ3UFPuhDFijI/Stz01H60BQsNck4QFKNWtB9SlQyAf\nrYGaeEuL9mG++TLUxKx2fxaTr7DsA4SYJrC3+LuCr6t1jb9PmwEkJUMZrZ+bxbhiFCQ+EeaKJ2EW\nFULddo/bdwbtnZw6gerXXoRx/6MB/5mGmnAzzEW/gmTe0Ox3OLJ7J3DsMNTwTB+la//cln1paSmW\nLVuGkydPQimF0aNHY8KECQ22KSwsRHZ2NmJiYgAAQ4cOxZQp/AqzbuJ0AkUFEMcmiGOT6+gy7UoY\nM34JxPfxSfmonhfB+NViyEvLYT7xSxj3zIXqEXhzjIvphHyaC1n9MsKun4paDm1B9bwI6JsC+df7\nzfpCmYjAfPMlqIm3QgXx+LSl3L5yNpsNd955JxISElBdXY25c+di0KBBiI1teEbBgAEDMHfuXJ8F\nJc9IbS3wZb7rCH77ZiC6u2uI5oHfuf5j8wMV1gGY/gvgX+/DXDgP6rZ7YKSP8MtzW4GUFMF8eQUQ\nHAzjgd8j7JJU1FZU6I5lCcb1U2H+6TFIxgTPh2MK84GKU1DDRvk2XDvntuyjoqIQFRUFAAgLC0Ns\nbCzKysoalb2udSepiXPg4y52HcFPvAWqa4yWTEopqFHjIAl9YT67EGZRAdTUn0AFN+/zgLZEKk5B\n3vhfyBdboW76kWs2xgAfuvlPKr4PENcb8tmHHs3hLyIwV78EdcNtXhlqDGTNek909OhR7N27F337\nNl4ns6ioCA899BDsdjvuuOMOxMUF3lt3f3J3DrxVqIv7wPivJTD/8jQke55rWCe6u+5YXvX9IRs1\ndCSM3y9r8RkngcC4firM55ZARoxxPyyzfTNQVwd1+XD/hGvHlHh4SF5dXY1HH30UU6ZMQXp6eqP7\nlFIIDQ2Fw+HAiy++iKVLlzbaR0FBAQoKCuqvZ2VlocJib29DQkJQU1OjO0YjISEhqD7yDWq3fIra\nLZ+grngXggemIXjo1QhKuxJGhP/LpTmvlYjg7JrXcPbtVxH+s4cQnHal9kzeUPfvXTjz/B+B4GCE\n/+R+2C5O0p7JE7ozVfxuDkIzxiNk5NgGt38/l5gmKub9FB1umY5gjWWv+7VqSmRkJHJyvlsNLCUl\nBSkpKRd8jEdl73Q68eSTT2Lw4MGNPpxtyuzZs7Fw4UJ07Oi+gA4dOuR2G3+KjIy03B8g87MPYHz2\nIZwH90KlDoEafKVH58D7WkteKykuhPk/i6GGjYKa9EOvr9Dkr99fc4ZsrPhvSncmKXTAfGUljN8t\ngzK+m6Lr+7nMLZ9CclfDeGSR1uEw3a9VU3r16tXsx3g0EdqKFSsQFxd33qIvLy+vv1xc7FqKzJOi\nJ/fk1AnIqucRdvOPYDz1VxjTfwGVdqX2om8plXQJjN/8AbL33zCX/AZSXqY7UrOI6YT5r/dgzp8N\nhITC+P0yGMOv5dh8cw24DAjrADg2Nnm3OJ2Qt16GMfl2vrZe4nbMfteuXfjkk08QHx+Phx9+GEop\nTJs2DceOHYNSCpmZmdi0aRNyc3Nhs9kQEhKCOXPm+CN7QJD8zVAD0xA8aCiqLXZ00VIqsjOM++dD\n3smBueAXMO7+BVRyqu5Ybv3nWTb8pnDLKaVcY/dvvwojbXijQpfP1wOdolx/FMgr3JZ9cnIyVq1a\ndcFtxo0bh3HjxnktFH1HHBthXNX+vkiiDBvUDdMgSckwn3sKKuN6qPE3N3hLbxXfDdlsgbrpTp5l\n4y2pQ4HVLwM7twGXDqm/WepqIW+/CuPH9/N19iLr/ZdF9aSqEij+Ehh4ue4oPqMuGQzj10sgO7e5\nzr+uPKU7Ur3GQzbPcMjGi5RhQI2/GeaanAanbstnHwLde0H1a18LsevGsrcw+WIL0P/Sdj95luoS\nDePBx6F6xcN87AHIv3fpjuQasvnvhyAb18F44Pcwbv0pT6f0AZU+Aqg4CezZCQCQmhrImhwYk2/X\nnKz94XePLUzyNkKlBcb5xSooCGrqjyFJA2BqnCOfQzb+pQwb1LgpMNfkwNb/UtR88BYQnwjVu5/u\naO0Oj+wtSs5WA7u+gBoUGMvXnaMGD4MxLxuy8SOYzy6EnKnyy/NyyEYfdWUGcOQgZNcXqH7rFRiT\neFTvCyx7q9qZB/TuF5ALKqvuPWHMy4aK6ARzwQOQ/SU+fT4O2eilgoKhrrsJ5vL/RtCAQTzLyUc4\njGNRgTSE0xQVHAJ1xyyYm9b5bI58DtlYh7p6DGTTOoTdfBf8814u8LDsLUhqayE7t8LI+onuKNoZ\nwzIg8X1g/nmh1+bIbzCXTfrVMH7/DI/kNVMhobD9+inYIiOBdvJ9EqvhMI4V7doO9LoYqrN1JjTT\nSfWKh/GrxUBdHcwnfgk5fKDF+2owZDPndzCmzWDRU0Dgkb0FSd5GqMt9M1FYW6XCOgB3/wL4+L0W\nzZHPIRsKdCx7ixGnE5L/OYwWrtPZnimloK4ZD+nd99thHfdz5HPIhsiFwzhWU1TgWl2qnc357k3q\n4iQY//UHyInjMLPnQUqPNrkdh2yIvsMje4txnYXDIRx3VERHGLN+BfnnapiPPwjjrvugUl3fSWg4\nZPMjqGEZlpxzh8ifWPYWIqbpmvjswQW6o7QJSimosTdCEvvDXLkYalghzsbGw1z1AodsiP4Dy95K\nSvYAHSKgenBJx+ZQfS9xLX344tOo+boYxpzfQcUn6o5FZCksewsRx0autdlCqlMUbPf91pKrChFZ\nAQcyLUJEXOP1gzleT0Tex7K3igNfAyIA5wUhIh9g2VvEublw+EUfIvIFlr1FSN4GnnJJRD7DsrcA\nOXwAOF0JcMEGIvIRlr0FiGMT1OBh/OIPEfkM28UCZBuHcIjIt1j2mknpMaD0CNBvoO4oRNSOsew1\nE8dGqEFDoWw23VGIqB1j2WsmjsBefpCI/INlr5GcOgHs/xoYMEh3FCJq51j2Gkn+51AD06CCQ3RH\nIaJ2jmWvkWv5QQ7hEJHvuZ31srS0FMuWLcPJkyehlMLo0aMxYcKERtu98MILyM/PR2hoKGbPno2E\nhARf5G035HQl8NVu4J55uqMQUQBwW/Y2mw133nknEhISUF1djblz52LQoEGIjY2t38bhcODIkSN4\n+umnUVRUhJUrV+Lxxx/3afC2Tr7YAvS/1LWQNhGRj7kdxomKiqo/Sg8LC0NsbCzKysoabLNlyxaM\nGjUKANC3b19UVVWhvLzc+2nbkXMTnxER+UOzxuyPHj2KvXv3om/fvg1uLysrQ3R0dP11u93e6A8C\nfUeqzwC7v6hfM5WIyNc8XqmquroaS5YswV133YWwsLAWPVlBQQEKCgrqr2dlZSEyMrJF+/KVkJAQ\nn2eqKchDTd9L0LFHT48f449czcVMnmEmz1kxlxUzAUBOTk795ZSUFKSkpFxwe4/K3ul04qmnnsLI\nkSORnt74aNRut6O0tLT+emlpKex2e6PtmgpktSXk/LGsnbnhI2DQ0GY9jxWX22MmzzCT56yYy6qZ\nsrKymvUYj4ZxVqxYgbi4uCbPwgGAIUOG4OOPPwYA7NmzBxEREYiKimpWkEAhtbWQndugLrtCdxQi\nCiBuj+x37dqFTz75BPHx8Xj44YehlMK0adNw7NgxKKWQmZmJtLQ0OBwO3HvvvQgLC8PMmTP9kb1t\n+jIfiL0YqlMX3UmIKIC4Lfvk5GSsWrXK7Y6mT5/ulUDtHc/CISId+A1aPxKnE7J9M9Rgzl1PRP7F\nsvenPTuB6O5Q0d10JyGiAMOy9yNxcC4cItKDZe8nYprfrjXLIRwi8j+Wvb+U7AHCO0L1iHW/LRGR\nl7Hs/YRn4RCRTix7PxARSN4GqDQO4RCRHix7f9hfAigFxCXoTkJEAYpl7wfi2Ag1+EoopXRHIaIA\nxbL3A9nGIRwi0otl72PyzQHgzGmgdz/dUYgogLHsfcw1hDMMyuBLTUT6sIF8jKdcEpEVsOx9SEqP\nAqVHgb4XXkGGiMjXWPY+JI6NUIOGQtlsuqMQUYBj2fuQ5HHiMyKyBpa9j8jJE8DBvUDyIN1RiIhY\n9r4i+Z9DDbwcKjhYdxQiIpa9r/AsHCKyEpa9D8jpSqBkNzAwTXcUIiIALHufkO2bgf6pUKFhuqMQ\nEQFg2fuEa/lBzoVDRNbBsvcyqT4D7N4BlZquOwoRUT2Wvbft3AYk9ocK76g7CRFRPZa9l/EsHCKy\nIpa9F0ltDWRnHtRlV+iOQkTUAMvemwq3AxclQHWK0p2EiKgBlr0XiWMDh3CIyJKC3G2wYsUK5OXl\noXPnzli8eHGj+wsLC5GdnY2YmBgAwNChQzFlyhTvJ7U4qauDbN8M44bbdEchImrEbdlnZGRg/Pjx\nWLZs2Xm3GTBgAObOnevVYG1OUQHQtQeUvZvuJEREjbgdxklOTkZERMQFtxERrwVqq1xn4fCLVERk\nTV4Zsy8qKsJDDz2EJ554AgcOHPDGLtsUMU2IYxPUYJY9EVmT22EcdxITE7F8+XKEhobC4XBg0aJF\nWLp0aZPbFhQUoKCgoP56VlYWIiMjWxvBq0JCQpqdqW73TlR16oxOfZN9lKpluXyNmTzDTJ6zYi4r\nZgKAnJyc+sspKSlISbnw8qetLvuwsO8m+xo8eDCee+45VFZWomPHxt8gbSpQRUVFayN4VWRkZLMz\nmZ99CAy6wqc/S0ty+RozeYaZPGfFXFbNlJWV1azHeDSMIyLnHZcvLy+vv1xcXAwATRZ9eyUikG0b\nOPEZEVma2yP7pUuXorCwEBUVFZg5cyaysrJQV1cHpRQyMzOxadMm5ObmwmazISQkBHPmzPFHbuvY\n/xVgGEBsgu4kRETn5bbs77///gveP27cOIwbN85rgdqac2fhKKV0RyEiOi9+g7aVOPEZEbUFLPtW\nkG8OAGeqgIS+uqMQEV0Qy74VJG8D1OBhUAZfRiKyNrZUK4hjE9TlHMIhIutj2beQHD8ClB0Dki7R\nHYWIyC2WfQuJYxPUoKFQNpvuKEREbrHsW4hn4RBRW8KybwE5eQI4tBdITtUdhYjIIyz7FhDHJqiB\nQ6CCg3VHISLyCMu+BcSxkXPhEFGbwrJvJjldAZTsAVLSdEchIvIYy76ZZPtmIDkVKjTM/cZERBbB\nsm8mnoVDRG0Ry74ZpLoK2L0DKnWI7ihERM3Csm8G2ZEHJA2ACg+cxVmIqH1g2TeHYyMXFSeiNoll\n7yGprYHszIO67ArdUYiImo1l76nCfOCi3lCdonQnISJqNpa9h84tP0hE1Bax7D0gdXWQLzZDDR6m\nOwoRUYuw7D2xZyfQrSeUvZvuJERELcKy94DwLBwiauNY9m6IabpmueR4PRG1YSx7d77aBXTsBBXT\nS3cSIqLsL5BQAAAMBklEQVQWY9m7wbNwiKg9YNlfgIhw4jMiahdY9hey7yvAZgNiL9adhIioVVj2\nFyB5rrNwlFK6oxARtUqQuw1WrFiBvLw8dO7cGYsXL25ymxdeeAH5+fkIDQ3F7NmzkZCQ4O2cWohj\nI4wf3687BhFRq7k9ss/IyMCvf/3r897vcDhw5MgRPP3005gxYwZWrlzp1YC6yDf7geozwMVJuqMQ\nEbWa27JPTk5GRETEee/fsmULRo0aBQDo27cvqqqqUF5e7r2EmriGcIZBGRzpIqK2r9VNVlZWhujo\n6PrrdrsdZWVlrd2tdjwLh4jaE+2HrbJjK+TYYYjp1B2lnhw7DJw4DvQdoDsKEZFXuP2A1h273Y7S\n0tL666WlpbDb7U1uW1BQgIKCgvrrWVlZMNathfOb/ZCTJ2DE9IKt10UwesW7/r+n67IR4b9lAENC\nQhDypQNm+giEd7bO3PUhISGIjIzUHaMBZvIMM3nOirmsmAkAcnJy6i+npKQgJSXlgtt7VPYiAhFp\n8r4hQ4bg/fffx/Dhw7Fnzx5EREQgKqrpkmwqkNz3WxgA5Gw1cOQQ6o4cBA4fBLZugBw+CBw5BISG\nAj1ioWJigR5xUD1igR6xQHQMlM3myY/gscjISFRvXA/j+ixUVFR4dd+tERkZaak8ADN5ipk8Z8Vc\nVs2UlZXVrMe4LfulS5eisLAQFRUVmDlzJrKyslBXVwelFDIzM5GWlgaHw4F7770XYWFhmDlzZovC\nq9AwID4RKj6xwe0iApwoBY4cdJX/4QMwCxzAkYPAqXKga4zrD0GPb/8QnPuD0MJ3A+aJUuDQfiA5\ntUWPJyKyIiXnO2T3k0OHDrX4sXL2LHD00LfvAA4A3xyEnHtnEBLy7R+BOCDm2//vEQt0vfC7gZCN\nH6G6wAHj7gdbnMsXrHp0wUzuMZPnrJjLipl69Wr+xIytHrPXSYWGutaFvah3g9tFBCgvAw4fqC9/\n88t81x+BkyeAbj2+/QPQcFhIRUSidssnUCOu0/QTERH5Rpsu+/NRSgFdooEu0VADBjW4T2pc7wZw\n+NthoS/zYa5b4xoWCgoGnHUwfjZPU3IiIt9ol2V/ISokFIjrDcT1xvdnvBER4OQJRAQHoSo0VFs+\nIiJf0H6evVUopaCi7LD1iNUdhYjI61j2REQBgGVPRBQAWPZERAGAZU9EFABY9kREAYBlT0QUAFj2\nREQBgGVPRBQAWPZERAGAZU9EFABY9kREAYBlT0QUAFj2REQBgGVPRBQAWPZERAGAZU9EFABY9kRE\nAYBlT0QUAFj2REQBgGVPRBQAWPZERAGAZU9EFABY9kREAYBlT0QUAII82Sg/Px8vvvgiRAQZGRmY\nPHlyg/sLCwuRnZ2NmJgYAMDQoUMxZcoU76clIqIWcVv2pmni+eefx29/+1t06dIFjzzyCNLT0xEb\nG9tguwEDBmDu3Lk+C0pERC3ndhinuLgYPXv2RLdu3RAUFISrrroKW7ZsabSdiPgkIBERtZ7bsi8r\nK0N0dHT9dbvdjrKyskbbFRUV4aGHHsITTzyBAwcOeDclERG1ikdj9u4kJiZi+fLlCA0NhcPhwKJF\ni7B06VJv7JqIiLzAbdnb7XYcP368/npZWRnsdnuDbcLCwuovDx48GM899xwqKyvRsWPHBtsVFBSg\noKCg/npWVhZ69erV4vC+EhkZqTtCk6yYi5k8w0yes2IuK2bKycmpv5ySkoKUlJQLbu92GCcpKQmH\nDx/GsWPHUFdXh88++wxDhgxpsE15eXn95eLiYgBoVPTnAmVlZdX/7/thrcKKmQBr5mImzzCT56yY\ny6qZvt+l7ooe8ODI3jAMTJ8+HQsWLICI4Nprr0VcXBxyc3OhlEJmZiY2bdqE3Nxc2Gw2hISEYM6c\nOV75gYiIyDs8GrO/7LLLGo3Bjxkzpv7yuHHjMG7cOO8mIyIir7E9+uijj+oM0L17d51P3yQrZgKs\nmYuZPMNMnrNirvaQSQlPkCciavc4Nw4RUQBg2RMRBQCvfKmqJdxNruYPK1asQF5eHjp37ozFixcD\nACorK/HHP/4Rx44dQ/fu3fHAAw8gPDzcb5lKS0uxbNkynDx5EkopjB49GhMmTNCaq7a2FvPnz0dd\nXR2cTieGDRuGqVOnan+tANfcTY888gjsdjvmzp1riUyzZ89GeHg4lFKw2Wx44okntOeqqqrCn//8\nZ+zfvx9KKcycORM9e/bUlunQoUP44x//CKUURARHjhzBLbfcgpEjR2p9nd555x2sW7cOSinEx8dj\n1qxZqK6u1ppp7dq1+PDDDwGgdX0gGjidTvn5z38uR48eldraWvnlL38pBw4c8HuOL7/8UkpKSuTB\nBx+sv+1vf/ubrF69WkRE3njjDXnppZf8munEiRNSUlIiIiJnzpyR++67Tw4cOKA9V3V1tYi4fne/\n+tWvpKioSHsmEZG3335bli5dKk8++aSI6P/9iYjMnj1bKioqGtymO9eyZcvko48+EhGRuro6OX36\ntPZM5zidTpkxY4YcO3ZMa6bS0lKZPXu21NbWiojIkiVLZN26dVoz7du3Tx588EGpqakRp9Mpjz32\nmHzzzTctyqRlGMfTydV8LTk5GREREQ1u27p1K0aNGgUAuOaaa/yeKyoqCgkJCQBc30yOjY1FaWmp\n9lyhoaEAXEf5TqcTgP7XqrS0FA6HA6NHj66/TXcmwDUpoPzHeQ86c1VVVWHXrl3IyMgAANhsNoSH\nh1vitQKAHTt2ICYmBl27dtWeyTRNVFdXw+l0oqamBna7XWumgwcPIikpCcHBwTAMAwMGDMDmzZux\nbdu2ZmfSMozT1ORq5755q9vJkycRFRUFwFW8J0+e1Jbl6NGj2Lt3L/r166c9l2mamDdvHo4cOYKx\nY8ciKSlJe6a//vWvuOOOO1BVVVV/m+5MAKCUwoIFC2AYBjIzMzF69GituY4ePYrIyEgsX74ce/fu\nRWJiIu666y5LvFYAsGHDBowYMQKA3t+f3W7HxIkTMWvWLISGhiI1NRWpqalaM1100UV49dVXUVlZ\nieDgYDgcDiQmJqK8vLzZmbSN2bcVSiktz1tdXY0lS5bgrrvuajD30Dn+zmUYBrKzs1FVVYXFixdj\n//79WjOd+6wlISGhwXxLOjOd89hjj6FLly44deoUFixY0OT8T/7MZZomSkpKMH36dPTp0wcvvvgi\nVq9erTXTOXV1ddi6dStuv/32Ju/3Z6bTp09j69atWL58OcLDw7FkyRJ88sknWjPFxsZi0qRJWLBg\nAcLCwpCQkADDaDwg40kmLWXvyeRqukRFRdX/1SwvL0fnzp39nsHpdOKpp57CyJEjkZ6ebplcABAe\nHo5LLrkE+fn5WjPt2rULW7duhcPhQE1NDc6cOYM//elPlnidunTpAgDo1KkT0tPTUVxcrDWX3W5H\ndHQ0+vTpAwAYNmwYVq9ebYnXKj8/H4mJiejUqRMAvf/Od+zYge7du9fP6zV06FDs3r1b++uUkZFR\nPwT3yiuvIDo6ukWZtIzZezK5mr/85/jq5ZdfjvXr1wMA1q9fryXXihUrEBcXhwkTJlgi16lTp+qH\nSmpqarBjxw7ExsZqzXTbbbdhxYoVWLZsGebMmYOBAwfi3nvv1f77O3v2LKqrqwG43p198cUXiI+P\n15orKioK0dHROHToEABXqcXFxWl/rQDg008/xVVXXVV/XWemrl27oqioCDU1NRARy7xOp06dAgAc\nP34cmzdvxogRI1qUSds3aPPz8/GXv/ylfnI1HadeLl26FIWFhaioqEDnzp2RlZWF9PR0/OEPf8Dx\n48fRrVs3PPDAA40+xPWlXbt2Yf78+YiPj4dSCkopTJs2DUlJSdpy7du3D8888wxM04SIYPjw4bjp\npptQWVmp9bU6p7CwEG+//Xb9qZc6Mx09ehSLFi2CUgpOpxNXX301Jk+erD3X119/jWeffRZ1dXWI\niYnBrFmzYJqm1kxnz57FrFmzsGzZMnTo0AEAtL9Or732GjZs2ACbzYaEhATcc889qK6u1ppp/vz5\nqKyshM1mw5133omUlJQWvU6cLoGIKADwG7RERAGAZU9EFABY9kREAYBlT0QUAFj2REQBgGVPRBQA\nWPZERAGAZU9EFAD+H75h1qkGSE+ZAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269de2d29b0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10)).plot()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"If it finds multiple columns, it tries to plot them all in the same plot (with the index as the `x`)"
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269de339b70>"
]
},
"execution_count": 90,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAEQCAYAAAC+z7+sAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXl4VOXZuO/3zJKZyUwy2VnCKiAQEBBQXMGtVq0FtUWt\n9dP+qlU/P2v5uqj1c2lrW9tq3cXWaltrrYpWFPcFsLggi4AQ9h1CyJ6Zyewz5/39cWbJJJN9QkI4\n93Vx5eznmZeZ5zzneZ9FSCklOjo6OjoDFqWvBdDR0dHR6V10Ra+jo6MzwNEVvY6Ojs4AR1f0Ojo6\nOgMcXdHr6OjoDHB0Ra+jo6MzwDFm4iI333wzNpsNIQQGg4Hf/va3NDU18fDDD1NTU0NxcTELFizA\nZrNl4nY6Ojo6Ol0gIxa9EIJ77rmH3//+9/z2t78FYPHixUyePJlHHnmEsrIyXnvttU5dq7y8PBMi\n6aRBH9veRR/f3kMf245pb4wyouillLTMu1qzZg2zZ88GYM6cOaxevbpT19L/Q3sPfWx7F318ew99\nbDum1xW9EIL77ruPO+64g48++ggAl8uF0+kEwOl04nK5enyf9j5IR1+Evji3L67bkx9EX8jT367b\n03O7c92BNH79bWx7a19/vGd7ZETR/+pXv+J3v/sdd9xxB++99x5btmxpdYwQosf3Odp++P3xi9Lf\n5Olv1+3pud257kAav/42tr21rz/esz1EpmvdLFq0CIvFwtKlS7nnnntwOp00Njbyi1/8goceeqjV\n8eXl5SnCz58/P5Pi6Ojo6BwzvPzyy4nlsrIyysrKgAwo+mAwiJQSi8VCIBDg17/+Nd/61rfYuHEj\ndrudefPmsXjxYrxeL1dddVWnrnno0KGeiKTTBg6HA4/H09diDFj08e099LHtmCFDhrS5r8fhlS6X\niz/84Q8IIYhGo5xxxhlMmTKF4447joceeohly5ZRVFTEggULenorHR0dHZ1ukHHXTSbQLfreQbeK\nehd9fHsPfWw7pj2LXs+M1dHR0Rng6IpeR0dHZ4CTkRIIRwK73Z6REM3+hJSSpqamvhZDR0dngHPU\nKHohxIDz0Tkcjr4WQUdH5xhAd93o6OjoDHB0Ra+jo6MzwNEVvY6Ojs4AR1f0Ojo6OgMcXdFnmG99\n61uUlZURDof7WhQdHR0dQFf0GeXgwYOsWrUKIQTvv/9+X4ujo6OjA+iKPqMsWrSI6dOnM3/+/JQq\ncjo6Ojp9ia7oM8grr7zCpZdeyiWXXMLHH39MXV1dX4uko6Ojoyv6TLFq1SoOHTrExRdfzOTJkxk5\ncmSn++Tq6Ojo9CZHTWZsZ4he/82MXMfw9BtdPueVV17hzDPPTLRPnDt3LosWLeK6667LiEw6Ojo6\n3WVAKfruKOhMEAgEWLJkCaqqMm3aNABCoRBut5stW7YwYcKEPpFLR0dHBwaYou8r3n33XQwGA0uX\nLsVkMiW233jjjSxatIi77767D6XT0dE51tF99BnglVde4YorrmDw4MEUFhYm/l1zzTUsXrwYVVX7\nWkQdHZ1jmKOmw9RA7DBzpD/TQBzD/oQ+vr2HPrYdo3eY0tHR0TmGyZiPXlVV7rjjDvLz87ntttto\namri4YcfpqamhuLiYhYsWIDNZsvU7XR0dHR0OknGLPq3336boUOHJtYXL17M5MmTeeSRRygrK9Nj\nynV0dHR6CVlX3e7+jCj6uro61q1bxznnnJPYtmbNGmbPng3AnDlzWL16dSZupaOjo6PTDPXNl1Bv\nbz9fJyOK/u9//ztXX311Sk9Xl8uVSB5yOp24XK5M3EpHR0dHpxly6ZsdHtNjRf/ll1+Sm5vLyJEj\naS+AZ6A19tbR0dHpFwT8HR7S48nYrVu3smbNGtatW0coFMLv9/PYY4/hdDppbGxM/M3NzU17fnl5\nOeXl5Yn1+fPnp22abTAYeipqv8NgMBzRBuFms1lvSN6L6OPbe/TF2EarKxE2O4q9f/+fusxZyHAI\nIKVqbllZGWVlZUCG4+g3b97MkiVLuO2223j++eex2+3MmzePxYsX4/V6ueqqqzp1HT2OfmDc71hD\nH9/eoy/GNnr9NxFnXYjynRuP6H27SvSn34PGOoa9tabNY3otjn7evHls3LiRW2+9lU2bNjFv3rze\nupWOjo5Ot5BSpnU5y3g2uzX7CEvUDYRA+eUT7R6S0Vo3EydOZOLEiQDY7XbuuuuuTF6+X3PyySdT\nW1uL0WjEaDQyY8YM7r//fgYPHtzXouno6LSB/OgN5EvPwIgxKN/7EWLocG2H36v9DQb6TrjOEvBD\nTl67h+iZsRlCCMFzzz3Htm3bWLduHYWFhcfUg05H52hElq/TFvbtRL33f5I7PLEoQW/33EVy5xbU\nN/7VQ+k6cR8pIeiHLEu7x+mKPoPEXwHNZjMXXXQR27dv72OJdHR02sXjTlmVkUjKdrlyOXLzui5f\n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\n6AkEAmGc8/9Uow9/W/x+/gAAAABJRU5ErkJggg==\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269de37d940>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ts = pd.Series(np.random.randn(1000), index=pd.bdate_range('1/1/2000', periods=1000)).cumsum()\n",
"pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list('ABCD')).cumsum().plot()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Barplots are also possible"
]
},
{
"cell_type": "code",
"execution_count": 156,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df8aac18>"
]
},
"execution_count": 156,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nZwAYHBzk+eef54033iASiZCTk8NZZ53Ft771Laqrq7OSYevWrcyaNQs49H36xBNPsHPnTs4++2yu\nvfZanE5nVnKsXr2auXPnMn/+fM4666yszPllO3fu5Mknn+TMM89k2bJlbN68mc7OTqZOncr111/P\n17/+9azkeOqpp7j88sv52te+xs6dO2lsbMRmsxGPx7nxxhu54IILMjrfKVn8d911F16vl+rq6uQ3\ncV9fH21tbbz77rv8/Oc/H/MM69evp6ioiOnTpxMMBrHb7dx8882cdtpprF69Olk4Y+2DDz4Y9bF7\n7rmHRx55ZMwz3HXXXVx44YXs37+fV199lQULFrBgwQI6OjrYtm0bt91225hnuOqqqygoKPjCtmg0\nisvlwmaz8eCDD455BoDf/OY3zJ07l7KyMtrb2xkcHGT+/Pk8++yzuFwuli1bNuYZjvz+e/jhh3E6\nnSxevJg33niD7du3Z+XvA+DHP/4xF198Me3t7TidTubPn09VVRUulysr8wM0NDTg8/n4/PPPeeqp\np7j22muZN28e27Zt4/e//z133XVXVnL85Cc/YcOGDQDcfvvtLF++HI/Hw+7du2lubuaee+7J6HxZ\n/8iGbNizZ0/yE0APczqd1NTUEAwGs5Lh008/5dZbbwVg7ty5PPfcc/zqV7/K2j+qwxoaGkY9Wvj8\n88+zkiEWi7FkyRIA/vKXvyQ/jXXJkiW89NJLWcnwgx/8gHfeeYerr76ac845BzhUPA899FBW5j+s\np6cneWS/dOlSGhoa+N73vseqVau45ZZbslL8R9q5cyf33XdfMs/f/va3rM09efJkrrnmGq655hre\ne+89XnvtNVavXk1xcTHz58/n0ksvHfMM8Xic2bNnA4eOuufNmwdAWVkZv/3tb8d8/sOGh4eJx+PY\n7XYOHDiAx+MBYOrUqRw8eDDj852SxV9YWMjzzz/PwoULjzri//JR31gZGhpieHiYCRMOnUb57ne/\ni8vl4pe//CWDg4NZyQBQXFzM9ddfT1FR0VGPrVy5MisZjvylcuHChV94bHh4OCsZLr/8cqqqqnji\niSfIz8/H5/Nhs9myMveRJk2axI4dO5gxYwahUCi5xDRhwgSy9ct3LBbjxRdfJJFIMDAwQCKRSP5Z\njNcCwPnnn8/555/PD3/4Q9555x1ef/31rBT/aaedxttvv83AwAA2m41//OMfzJ07l+3btyf/7WbD\nt7/9be6++25qamooLy/nscce4+KLL+bdd9+lpKQk4/Odkp/Vc+GFF/LOO+/wu9/9jqeffjq5plpQ\nUMB1113HxIkTxzxDb28vNpuNKVOmJLeVlJQwZcoU3n777eQR8FjLy8sjLy8Ph8Nx1GNut5tp06aN\neYb//e9/eDwecnJy+MY3vpHc3t3dzYcffkhVVdWYZwDIzc2lsrKSoaEhHnnkET777DO+853vZGXu\nw0pLS3n00Ud56qmn+OSTT/jRj36Ew+Hgs88+Y+LEiUyfPn3MM+zbt4+hoSGGhoYoKSnh7LPPZtKk\nSfT19fHf//6XuXPnjnkGOPT/bhw+wj7MZrNx1llncdFFF2UlQ2lpKc8++ywffvghN910E3//+99p\namrivffeo76+PmsHitOnTyc/P5+//vWvvP/++3z66ad89NFHeDwefD5f5n8IjdkHPlvUSy+9NN4R\nLJEhkbBGjvHKsH///sSuXbvGNcOXWSGHFTIkEtbIYYUMicTY5DDucs4j/zcakzOANXKMV4aJEycm\n1/qt8OcA1shhhQxgjRxWyABjk+OUXOM/fFL1yxKJRNau3bZCBqvkUAZr5bBCBqvksEKG8chxShZ/\nLBZjzZo1R12vn0gkWLt2rTEZrJJDGayVwwoZrJLDChnGI8cpWfwXXnghg4ODI54Nz/QbIaycwSo5\nlMFaOayQwSo5rJBhPHKckm/gEhGR0Rl3cldExHQqfhERw6j4RUQMo+IXETGMil9ExDD/B/b0nsev\nbyWyAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df89eb70>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(np.random.randint(10, 20, 10000)).value_counts().plot(kind='bar')"
]
},
{
"cell_type": "code",
"execution_count": 157,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df94cba8>"
]
},
"execution_count": 157,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n8Jn/A26oWF11yZiXAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df90b748>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(np.random.randint(10, 20, 10000)).value_counts().plot(kind='barh')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Stacked plots:"
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df53d5f8>"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nSYwlTkQksf8D07K+MKsBrPEAAAAASUVORK5CYII=\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df541ac8>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.DataFrame(np.random.randint(1, 5, 40).reshape(10, 4), columns=list(\"ABCD\")).plot(kind='bar', stacked=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Histograms and density plot are a few characters away:"
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df6880b8>"
]
},
"execution_count": 94,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\ne+45OY6jF154IWXPIhcuXKivfvWrkqRAICDLstTf3+/xVN741a9+pa985SuSpK997WuKRqMeT5Q8\niURCtbW1Ki0tVUlJiaTJPX/OuCi4rnvbq741a9aora1N0q0nxOLiYo8mS75/XovOzk794he/0J49\nezR79mwPJ0u+f1yLgoICvfbaa2psbNSxY8fk9/t18ODBlHnB8M+/FyUlJbpw4YIk6cMPP1QikVBm\nZqZX4yXVP6+F3+/XxYsXJUl//OMftWjRIq9GS7qmpibl5+dr8+bNZttknj9n1L9orq+v18WLF9Xf\n36+srCxVVVWppKREdXV16u3tVU5OjsLh8JgXHR82Y61FS0uLhoeHzX/wy5YtU3V1tceTTr+x1mLj\nxo3m+zt37tSrr76aEh9JHWstSktLdfz4cV29elWzZ8/WU089pS996UtejzrtxlqLRYsW6Yc//KFu\n3ryp2bNnq7q6Wl/84he9HnXaXbp0SS+//LIKCgpkWZYsy9KWLVsUCATu+flzRkUBAOCtGff2EQDA\nO0QBAGAQBQCAQRQAAAZRAAAYRAEAYBAFAIBBFAAAxv8DP+oc+voKjTYAAAAASUVORK5CYII=\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df59d860>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(np.random.randint(10, 20, 10000)).hist(bins=5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"pandas offers KDE distributions (similar to `seaborn`)"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df69e358>"
]
},
"execution_count": 95,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df5616a0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(np.random.normal(size=10000)).plot(kind='kde', color='tomato')\n",
"pd.Series(np.random.normal(size=10000)).hist(normed=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"pandas offers furthermore other plotting capabilities similar to seaborn (such as pandas `scatter_matrix` and seaborn `pairplot`). Deciding what to use is really a matter of preferences but keep in mind that libraries only devoted to plotting are usually more advanced than general purposes libraries (duh!)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Data aggregation and grouping\n",
"Grouping data is one of the most used features in data analysis. SQL has a very expressive and simple syntax to allow it\n",
"\n",
"```sql\n",
"SELECT \n",
" category, avg(price)\n",
"FROM\n",
" inventory\n",
"GROUP BY\n",
" category\n",
"```\n",
"\n",
"While the syntax is simple and expressive in SQL, the amount of aggregate functions (like `sum, avg, std`) is somewhat limited. Writing new aggregate functions can be cumbersome (even though you can write it in Python in databases such as Postgres). Here pandas really shines. But let's first see how grouping in pandas works."
]
},
{
"cell_type": "code",
"execution_count": 96,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>company</th>\n",
" <th>revenue</th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>800</td>\n",
" <td>4.209641e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>7210.052325</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>670</td>\n",
" <td>4.451962e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6034.546870</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>187</td>\n",
" <td>8.718245e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>9773.384384</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>141</td>\n",
" <td>4.589730e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6739.277077</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>924</td>\n",
" <td>8.510332e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>810</td>\n",
" <td>3.003936e+08</td>\n",
" <td>Automotive</td>\n",
" <td>4938.201337</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" company revenue sector size\n",
"18 800 4.209641e+08 Infrastructure 7210.052325\n",
"13 670 4.451962e+08 Transportation 6034.546870\n",
"17 187 8.718245e+08 Infrastructure 9773.384384\n",
"12 141 4.589730e+08 Transportation 6739.277077\n",
"19 924 8.510332e+08 Infrastructure 10292.408394\n",
"0 810 3.003936e+08 Automotive 4938.201337"
]
},
"execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.sample(frac=0.3)"
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"sector\n",
"Automotive 2.831127e+08\n",
"Energy 3.047790e+08\n",
"Infrastructure 8.510332e+08\n",
"Transportation 4.541239e+08\n",
"Name: revenue, dtype: float64"
]
},
"execution_count": 97,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\")['revenue'].agg(np.median)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The syntax is in pricipal pretty simple:\n",
"\n",
"```python\n",
"df.groupby(column or [columns])<select columns where you want to perform the aggregate>.agg(aggregate function)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Some functions are readily available and there's no need to use `agg`"
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>revenue</th>\n",
" <th>size</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Automotive</th>\n",
" <td>3.167589e+08</td>\n",
" <td>4788.954217</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Energy</th>\n",
" <td>4.832984e+08</td>\n",
" <td>6105.981512</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Infrastructure</th>\n",
" <td>7.465784e+08</td>\n",
" <td>9083.477437</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Transportation</th>\n",
" <td>4.934582e+08</td>\n",
" <td>6541.475193</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" revenue size\n",
"sector \n",
"Automotive 3.167589e+08 4788.954217\n",
"Energy 4.832984e+08 6105.981512\n",
"Infrastructure 7.465784e+08 9083.477437\n",
"Transportation 4.934582e+08 6541.475193"
]
},
"execution_count": 98,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\")[['revenue', 'size']].mean()"
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>0</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Automotive</th>\n",
" <th>revenue</th>\n",
" <td>3.167589e+08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>size</th>\n",
" <td>4.788954e+03</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Energy</th>\n",
" <th>revenue</th>\n",
" <td>4.832984e+08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>size</th>\n",
" <td>6.105982e+03</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Infrastructure</th>\n",
" <th>revenue</th>\n",
" <td>7.465784e+08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>size</th>\n",
" <td>9.083477e+03</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Transportation</th>\n",
" <th>revenue</th>\n",
" <td>4.934582e+08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>size</th>\n",
" <td>6.541475e+03</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0\n",
"sector \n",
"Automotive revenue 3.167589e+08\n",
" size 4.788954e+03\n",
"Energy revenue 4.832984e+08\n",
" size 6.105982e+03\n",
"Infrastructure revenue 7.465784e+08\n",
" size 9.083477e+03\n",
"Transportation revenue 4.934582e+08\n",
" size 6.541475e+03"
]
},
"execution_count": 99,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.DataFrame(clients.groupby(\"sector\")[['revenue', 'size']].mean().stack())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Other useful methods are `count, min, max, median`, etc.\n",
"\n",
"In SQL you can't, but in pandas it's possible to get the groups as they are"
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Automotive\n",
" company revenue sector size\n",
"0 810 3.003936e+08 Automotive 4938.201337\n",
"1 0 1.321524e+08 Automotive 2550.244875\n",
"2 406 2.831127e+08 Automotive 4427.557218\n",
"3 33 9.096190e+07 Automotive 1631.131274\n",
"4 224 7.771738e+08 Automotive 10397.636380\n",
"Energy\n",
" company revenue sector size\n",
"5 131 3.047790e+08 Energy 3244.562719\n",
"6 439 2.832645e+07 Energy 3224.815102\n",
"7 840 8.729771e+08 Energy 8793.012323\n",
"8 350 9.472119e+08 Energy 9753.958909\n",
"9 380 2.631976e+08 Energy 5513.558508\n",
"Infrastructure\n",
" company revenue sector size\n",
"15 745 8.625963e+08 Infrastructure 10565.647926\n",
"16 618 7.264740e+08 Infrastructure 7575.894157\n",
"17 187 8.718245e+08 Infrastructure 9773.384384\n",
"18 800 4.209641e+08 Infrastructure 7210.052325\n",
"19 924 8.510332e+08 Infrastructure 10292.408394\n",
"Transportation\n",
" company revenue sector size\n",
"10 481 2.220322e+08 Transportation 2512.758196\n",
"11 229 8.869656e+08 Transportation 11370.846510\n",
"12 141 4.589730e+08 Transportation 6739.277077\n",
"13 670 4.451962e+08 Transportation 6034.546870\n",
"14 962 4.541239e+08 Transportation 6049.947310\n"
]
}
],
"source": [
"group_obj = clients.groupby(\"sector\")[['revenue', 'size']]\n",
"for name, group in group_obj:\n",
" print(name)\n",
" print(group)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Another extremly nice feature is dictionary mapping when grouping. Let's say we have the following dataset and we want to group by odd and even rows"
]
},
{
"cell_type": "code",
"execution_count": 101,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>A</th>\n",
" <th>B</th>\n",
" <th>C</th>\n",
" <th>D</th>\n",
" <th>E</th>\n",
" <th>F</th>\n",
" <th>G</th>\n",
" <th>H</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" A B C D E F G H\n",
"0 4 2 2 2 1 1 4 2\n",
"1 1 2 4 4 4 3 2 3\n",
"2 3 1 4 4 1 4 4 3\n",
"3 1 1 3 2 2 2 1 3\n",
"4 1 4 2 4 3 4 3 4\n",
"5 3 1 3 2 3 1 2 3\n",
"6 1 2 3 1 3 3 4 2\n",
"7 1 1 1 3 3 2 3 3\n",
"8 4 3 1 3 3 1 4 4\n",
"9 3 1 4 4 4 1 3 3"
]
},
"execution_count": 101,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"to_group = pd.DataFrame(np.random.randint(1, 5, 80).reshape(10, 8), columns=list(\"ABCDEFGH\"))\n",
"to_group"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"This is easy to do with pandas if we have a mapping dictionary"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{0: 'even',\n",
" 1: 'odd',\n",
" 2: 'even',\n",
" 3: 'odd',\n",
" 4: 'even',\n",
" 5: 'odd',\n",
" 6: 'even',\n",
" 7: 'odd',\n",
" 8: 'even',\n",
" 9: 'odd'}"
]
},
"execution_count": 102,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouping_dict = dict([(el, \"even\") if el % 2 == 0 else (el, \"odd\") for el in range(10)])\n",
"grouping_dict"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>A</th>\n",
" <th>B</th>\n",
" <th>C</th>\n",
" <th>D</th>\n",
" <th>E</th>\n",
" <th>F</th>\n",
" <th>G</th>\n",
" <th>H</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>even</th>\n",
" <td>2.6</td>\n",
" <td>2.4</td>\n",
" <td>2.4</td>\n",
" <td>2.8</td>\n",
" <td>2.2</td>\n",
" <td>2.6</td>\n",
" <td>3.8</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>odd</th>\n",
" <td>1.8</td>\n",
" <td>1.2</td>\n",
" <td>3.0</td>\n",
" <td>3.0</td>\n",
" <td>3.2</td>\n",
" <td>1.8</td>\n",
" <td>2.2</td>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" A B C D E F G H\n",
"even 2.6 2.4 2.4 2.8 2.2 2.6 3.8 3\n",
"odd 1.8 1.2 3.0 3.0 3.2 1.8 2.2 3"
]
},
"execution_count": 103,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"to_group.groupby(grouping_dict).mean()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Note that pandas did the groupby with the rows. If we want to do it with the columns we can pass `axis=1`. Grouping could also happens with a function: the output of the function then becomes the grouping key"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>A</th>\n",
" <th>B</th>\n",
" <th>C</th>\n",
" <th>D</th>\n",
" <th>E</th>\n",
" <th>F</th>\n",
" <th>G</th>\n",
" <th>H</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2.6</td>\n",
" <td>2.4</td>\n",
" <td>2.4</td>\n",
" <td>2.8</td>\n",
" <td>2.2</td>\n",
" <td>2.6</td>\n",
" <td>3.8</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.8</td>\n",
" <td>1.2</td>\n",
" <td>3.0</td>\n",
" <td>3.0</td>\n",
" <td>3.2</td>\n",
" <td>1.8</td>\n",
" <td>2.2</td>\n",
" <td>3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" A B C D E F G H\n",
"0 2.6 2.4 2.4 2.8 2.2 2.6 3.8 3\n",
"1 1.8 1.2 3.0 3.0 3.2 1.8 2.2 3"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"to_group.groupby(lambda x: x % 2).mean()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Grouping by index level is also a possibility. Let's say we have the following MultiIndex"
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th>province</th>\n",
" <th colspan=\"3\" halign=\"left\">FL</th>\n",
" <th colspan=\"3\" halign=\"left\">ZH</th>\n",
" <th colspan=\"3\" halign=\"left\">NH</th>\n",
" </tr>\n",
" <tr>\n",
" <th>day</th>\n",
" <th>9</th>\n",
" <th>10</th>\n",
" <th>11</th>\n",
" <th>12</th>\n",
" <th>13</th>\n",
" <th>14</th>\n",
" <th>15</th>\n",
" <th>16</th>\n",
" <th>17</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>6</td>\n",
" <td>7</td>\n",
" <td>5</td>\n",
" <td>9</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>7</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>9</td>\n",
" <td>4</td>\n",
" <td>8</td>\n",
" <td>8</td>\n",
" <td>2</td>\n",
" <td>6</td>\n",
" <td>5</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1</td>\n",
" <td>8</td>\n",
" <td>8</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>9</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>3</td>\n",
" <td>4</td>\n",
" <td>5</td>\n",
" <td>2</td>\n",
" <td>6</td>\n",
" <td>7</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>5</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>7</td>\n",
" <td>1</td>\n",
" <td>5</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>1</td>\n",
" <td>7</td>\n",
" <td>7</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>5</td>\n",
" <td>7</td>\n",
" <td>5</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>1</td>\n",
" <td>7</td>\n",
" <td>6</td>\n",
" <td>7</td>\n",
" <td>5</td>\n",
" <td>9</td>\n",
" <td>2</td>\n",
" <td>7</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>9</td>\n",
" <td>1</td>\n",
" <td>9</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>7</td>\n",
" <td>5</td>\n",
" <td>6</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>9</td>\n",
" <td>9</td>\n",
" <td>9</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>4</td>\n",
" <td>9</td>\n",
" <td>8</td>\n",
" <td>1</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"province FL ZH NH \n",
"day 9 10 11 12 13 14 15 16 17\n",
"0 6 7 5 9 1 1 2 7 9\n",
"1 2 9 4 8 8 2 6 5 3\n",
"2 1 8 8 1 3 9 4 3 6\n",
"3 1 2 2 1 1 2 1 4 5\n",
"4 3 4 5 2 6 7 2 1 2\n",
"5 5 4 4 7 1 5 4 3 1\n",
"6 1 7 7 2 2 5 7 5 1\n",
"7 1 7 6 7 5 9 2 7 4\n",
"8 9 1 9 1 1 7 5 6 3\n",
"9 9 9 9 3 2 4 9 8 1"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"group_index = pd.MultiIndex.from_arrays([np.repeat([\"FL\", \"ZH\", \"NH\"], 3), range(9, 18)], names=[\"province\", \"day\"])\n",
"to_group_idx = pd.DataFrame(np.random.randint(1, 10, 90).reshape(10, 9), columns=group_index)\n",
"to_group_idx"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"To group the data by province we use"
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th>province</th>\n",
" <th>FL</th>\n",
" <th>NH</th>\n",
" <th>ZH</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>6.000000</td>\n",
" <td>6.000000</td>\n",
" <td>3.666667</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>5.000000</td>\n",
" <td>4.666667</td>\n",
" <td>6.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>5.666667</td>\n",
" <td>4.333333</td>\n",
" <td>4.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1.666667</td>\n",
" <td>3.333333</td>\n",
" <td>1.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>4.000000</td>\n",
" <td>1.666667</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>4.333333</td>\n",
" <td>2.666667</td>\n",
" <td>4.333333</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>5.000000</td>\n",
" <td>4.333333</td>\n",
" <td>3.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>4.666667</td>\n",
" <td>4.333333</td>\n",
" <td>7.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>6.333333</td>\n",
" <td>4.666667</td>\n",
" <td>3.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>9.000000</td>\n",
" <td>6.000000</td>\n",
" <td>3.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"province FL NH ZH\n",
"0 6.000000 6.000000 3.666667\n",
"1 5.000000 4.666667 6.000000\n",
"2 5.666667 4.333333 4.333333\n",
"3 1.666667 3.333333 1.333333\n",
"4 4.000000 1.666667 5.000000\n",
"5 4.333333 2.666667 4.333333\n",
"6 5.000000 4.333333 3.000000\n",
"7 4.666667 4.333333 7.000000\n",
"8 6.333333 4.666667 3.000000\n",
"9 9.000000 6.000000 3.000000"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"to_group_idx.groupby(level='province', axis=1).mean()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Using aggregate functions in pandas\n",
"Besides using all numpy and pandas functions that produce aggregate results, you can define your own functions"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>revenue</th>\n",
" <th>size</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Automotive</th>\n",
" <td>6.862119e+08</td>\n",
" <td>8766.505106</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Energy</th>\n",
" <td>9.188855e+08</td>\n",
" <td>6529.143807</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Infrastructure</th>\n",
" <td>4.508603e+08</td>\n",
" <td>3355.595601</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Transportation</th>\n",
" <td>6.649335e+08</td>\n",
" <td>8858.088313</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" revenue size\n",
"sector \n",
"Automotive 6.862119e+08 8766.505106\n",
"Energy 9.188855e+08 6529.143807\n",
"Infrastructure 4.508603e+08 3355.595601\n",
"Transportation 6.649335e+08 8858.088313"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extremes_dst(ar):\n",
" return ar.max() - ar.min()\n",
"\n",
"clients.groupby(\"sector\")[['revenue', 'size']].agg(extremes_dst)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Some other methods, unexpectedly, also work, even though they're not aggregate methods"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>revenue</th>\n",
" <th>size</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"8\" valign=\"top\">Automotive</th>\n",
" <th>count</th>\n",
" <td>5.000000e+00</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>3.167589e+08</td>\n",
" <td>4788.954217</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>2.731509e+08</td>\n",
" <td>3412.984887</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>9.096190e+07</td>\n",
" <td>1631.131274</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>1.321524e+08</td>\n",
" <td>2550.244875</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>2.831127e+08</td>\n",
" <td>4427.557218</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>3.003936e+08</td>\n",
" <td>4938.201337</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>7.771738e+08</td>\n",
" <td>10397.636380</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"8\" valign=\"top\">Energy</th>\n",
" <th>count</th>\n",
" <td>5.000000e+00</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>4.832984e+08</td>\n",
" <td>6105.981512</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>4.044683e+08</td>\n",
" <td>3056.455303</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>2.832645e+07</td>\n",
" <td>3224.815102</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>2.631976e+08</td>\n",
" <td>3244.562719</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>3.047790e+08</td>\n",
" <td>5513.558508</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>8.729771e+08</td>\n",
" <td>8793.012323</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>9.472119e+08</td>\n",
" <td>9753.958909</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"8\" valign=\"top\">Infrastructure</th>\n",
" <th>count</th>\n",
" <td>5.000000e+00</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>7.465784e+08</td>\n",
" <td>9083.477437</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>1.913677e+08</td>\n",
" <td>1574.551048</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>4.209641e+08</td>\n",
" <td>7210.052325</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>7.264740e+08</td>\n",
" <td>7575.894157</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>8.510332e+08</td>\n",
" <td>9773.384384</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>8.625963e+08</td>\n",
" <td>10292.408394</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>8.718245e+08</td>\n",
" <td>10565.647926</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"8\" valign=\"top\">Transportation</th>\n",
" <th>count</th>\n",
" <td>5.000000e+00</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>4.934582e+08</td>\n",
" <td>6541.475193</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>2.416536e+08</td>\n",
" <td>3165.876242</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>2.220322e+08</td>\n",
" <td>2512.758196</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>4.451962e+08</td>\n",
" <td>6034.546870</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>4.541239e+08</td>\n",
" <td>6049.947310</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>4.589730e+08</td>\n",
" <td>6739.277077</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>8.869656e+08</td>\n",
" <td>11370.846510</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" revenue size\n",
"sector \n",
"Automotive count 5.000000e+00 5.000000\n",
" mean 3.167589e+08 4788.954217\n",
" std 2.731509e+08 3412.984887\n",
" min 9.096190e+07 1631.131274\n",
" 25% 1.321524e+08 2550.244875\n",
" 50% 2.831127e+08 4427.557218\n",
" 75% 3.003936e+08 4938.201337\n",
" max 7.771738e+08 10397.636380\n",
"Energy count 5.000000e+00 5.000000\n",
" mean 4.832984e+08 6105.981512\n",
" std 4.044683e+08 3056.455303\n",
" min 2.832645e+07 3224.815102\n",
" 25% 2.631976e+08 3244.562719\n",
" 50% 3.047790e+08 5513.558508\n",
" 75% 8.729771e+08 8793.012323\n",
" max 9.472119e+08 9753.958909\n",
"Infrastructure count 5.000000e+00 5.000000\n",
" mean 7.465784e+08 9083.477437\n",
" std 1.913677e+08 1574.551048\n",
" min 4.209641e+08 7210.052325\n",
" 25% 7.264740e+08 7575.894157\n",
" 50% 8.510332e+08 9773.384384\n",
" 75% 8.625963e+08 10292.408394\n",
" max 8.718245e+08 10565.647926\n",
"Transportation count 5.000000e+00 5.000000\n",
" mean 4.934582e+08 6541.475193\n",
" std 2.416536e+08 3165.876242\n",
" min 2.220322e+08 2512.758196\n",
" 25% 4.451962e+08 6034.546870\n",
" 50% 4.541239e+08 6049.947310\n",
" 75% 4.589730e+08 6739.277077\n",
" max 8.869656e+08 11370.846510"
]
},
"execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"group_obj.describe()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"When needed (and desired) multiple aggregate functions can be passed"
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"3\" halign=\"left\">revenue</th>\n",
" <th colspan=\"3\" halign=\"left\">size</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>mean</th>\n",
" <th>median</th>\n",
" <th>std</th>\n",
" <th>mean</th>\n",
" <th>median</th>\n",
" <th>std</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Automotive</th>\n",
" <td>3.167589e+08</td>\n",
" <td>2.831127e+08</td>\n",
" <td>2.731509e+08</td>\n",
" <td>4788.954217</td>\n",
" <td>4427.557218</td>\n",
" <td>3412.984887</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Energy</th>\n",
" <td>4.832984e+08</td>\n",
" <td>3.047790e+08</td>\n",
" <td>4.044683e+08</td>\n",
" <td>6105.981512</td>\n",
" <td>5513.558508</td>\n",
" <td>3056.455303</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Infrastructure</th>\n",
" <td>7.465784e+08</td>\n",
" <td>8.510332e+08</td>\n",
" <td>1.913677e+08</td>\n",
" <td>9083.477437</td>\n",
" <td>9773.384384</td>\n",
" <td>1574.551048</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Transportation</th>\n",
" <td>4.934582e+08</td>\n",
" <td>4.541239e+08</td>\n",
" <td>2.416536e+08</td>\n",
" <td>6541.475193</td>\n",
" <td>6049.947310</td>\n",
" <td>3165.876242</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" revenue size \\\n",
" mean median std mean \n",
"sector \n",
"Automotive 3.167589e+08 2.831127e+08 2.731509e+08 4788.954217 \n",
"Energy 4.832984e+08 3.047790e+08 4.044683e+08 6105.981512 \n",
"Infrastructure 7.465784e+08 8.510332e+08 1.913677e+08 9083.477437 \n",
"Transportation 4.934582e+08 4.541239e+08 2.416536e+08 6541.475193 \n",
"\n",
" \n",
" median std \n",
"sector \n",
"Automotive 4427.557218 3412.984887 \n",
"Energy 5513.558508 3056.455303 \n",
"Infrastructure 9773.384384 1574.551048 \n",
"Transportation 6049.947310 3165.876242 "
]
},
"execution_count": 109,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\")[['revenue', 'size']].agg([np.mean, np.median, np.std])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Or we can pass specific functions for specific columns"
]
},
{
"cell_type": "code",
"execution_count": 110,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>revenue</th>\n",
" <th>size</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Automotive</th>\n",
" <td>3.167589e+08</td>\n",
" <td>4427.557218</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Energy</th>\n",
" <td>4.832984e+08</td>\n",
" <td>5513.558508</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Infrastructure</th>\n",
" <td>7.465784e+08</td>\n",
" <td>9773.384384</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Transportation</th>\n",
" <td>4.934582e+08</td>\n",
" <td>6049.947310</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" revenue size\n",
"sector \n",
"Automotive 3.167589e+08 4427.557218\n",
"Energy 4.832984e+08 5513.558508\n",
"Infrastructure 7.465784e+08 9773.384384\n",
"Transportation 4.934582e+08 6049.947310"
]
},
"execution_count": 110,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\").agg({\"revenue\": np.mean, \"size\": np.median})"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Another useful bit: if you don't want the grouped-by-keys to be the index of the returned dataframe, use `as_index=False`"
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>sector</th>\n",
" <th>revenue</th>\n",
" <th>size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Automotive</td>\n",
" <td>3.167589e+08</td>\n",
" <td>4427.557218</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Energy</td>\n",
" <td>4.832984e+08</td>\n",
" <td>5513.558508</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Infrastructure</td>\n",
" <td>7.465784e+08</td>\n",
" <td>9773.384384</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Transportation</td>\n",
" <td>4.934582e+08</td>\n",
" <td>6049.947310</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" sector revenue size\n",
"0 Automotive 3.167589e+08 4427.557218\n",
"1 Energy 4.832984e+08 5513.558508\n",
"2 Infrastructure 7.465784e+08 9773.384384\n",
"3 Transportation 4.934582e+08 6049.947310"
]
},
"execution_count": 111,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\", as_index=False).agg({\"revenue\": np.mean, \"size\": np.median})"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Besides `aggregation`, there is a `transform` keyword that apply a transformation to each group and then places the results in a serie or dataframe with the \"right\" index. An example is worth a thousand words here:"
]
},
{
"cell_type": "code",
"execution_count": 112,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>company</th>\n",
" <th>revenue</th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" <th>sector_avg_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>439</td>\n",
" <td>2.832645e+07</td>\n",
" <td>Energy</td>\n",
" <td>3224.815102</td>\n",
" <td>6105.981512</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>924</td>\n",
" <td>8.510332e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" <td>9083.477437</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>962</td>\n",
" <td>4.541239e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6049.947310</td>\n",
" <td>6541.475193</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>131</td>\n",
" <td>3.047790e+08</td>\n",
" <td>Energy</td>\n",
" <td>3244.562719</td>\n",
" <td>6105.981512</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>670</td>\n",
" <td>4.451962e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6034.546870</td>\n",
" <td>6541.475193</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>618</td>\n",
" <td>7.264740e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>7575.894157</td>\n",
" <td>9083.477437</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" company revenue sector size sector_avg_size\n",
"6 439 2.832645e+07 Energy 3224.815102 6105.981512\n",
"19 924 8.510332e+08 Infrastructure 10292.408394 9083.477437\n",
"14 962 4.541239e+08 Transportation 6049.947310 6541.475193\n",
"5 131 3.047790e+08 Energy 3244.562719 6105.981512\n",
"13 670 4.451962e+08 Transportation 6034.546870 6541.475193\n",
"16 618 7.264740e+08 Infrastructure 7575.894157 9083.477437"
]
},
"execution_count": 112,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients['sector_avg_size'] = pd.DataFrame(clients.groupby('sector')['size'].transform(np.mean))\n",
"clients.sample(frac=0.3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is, at the end of the day, similar to a SQL window function!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Transform allows for nice operations on datasets, like de-meaning"
]
},
{
"cell_type": "code",
"execution_count": 158,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" <th>sector_avg_size</th>\n",
" <th>sector_demean_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>Transportation</td>\n",
" <td>6739.277077</td>\n",
" <td>6541.475193</td>\n",
" <td>197.801885</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" <td>9083.477437</td>\n",
" <td>1208.930957</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>Infrastructure</td>\n",
" <td>7575.894157</td>\n",
" <td>9083.477437</td>\n",
" <td>-1507.583280</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Energy</td>\n",
" <td>3244.562719</td>\n",
" <td>6105.981512</td>\n",
" <td>-2861.418793</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>Infrastructure</td>\n",
" <td>9773.384384</td>\n",
" <td>9083.477437</td>\n",
" <td>689.906947</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>Transportation</td>\n",
" <td>6049.947310</td>\n",
" <td>6541.475193</td>\n",
" <td>-491.527883</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" sector size sector_avg_size sector_demean_size\n",
"12 Transportation 6739.277077 6541.475193 197.801885\n",
"19 Infrastructure 10292.408394 9083.477437 1208.930957\n",
"16 Infrastructure 7575.894157 9083.477437 -1507.583280\n",
"5 Energy 3244.562719 6105.981512 -2861.418793\n",
"17 Infrastructure 9773.384384 9083.477437 689.906947\n",
"14 Transportation 6049.947310 6541.475193 -491.527883"
]
},
"execution_count": 158,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"demean = lambda ar: ar - ar.mean()\n",
"clients['sector_demean_size'] = pd.DataFrame(clients.groupby('sector')['size'].transform(demean))\n",
"clients[['sector', 'size', 'sector_avg_size', 'sector_demean_size']].sample(frac=0.3)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"There is another function which is extremly useful is `apply`. It goes a step further than `transform` because it basically accept a dataframe as input and tries to glue back the results"
]
},
{
"cell_type": "code",
"execution_count": 159,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" <th>sector_avg_size</th>\n",
" <th>sector_demean_size</th>\n",
" </tr>\n",
" <tr>\n",
" <th>sector</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Automotive</th>\n",
" <th>4</th>\n",
" <td>Automotive</td>\n",
" <td>10397.636380</td>\n",
" <td>4788.954217</td>\n",
" <td>5608.682163</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Automotive</td>\n",
" <td>4938.201337</td>\n",
" <td>4788.954217</td>\n",
" <td>149.247120</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Energy</th>\n",
" <th>8</th>\n",
" <td>Energy</td>\n",
" <td>9753.958909</td>\n",
" <td>6105.981512</td>\n",
" <td>3647.977397</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>Energy</td>\n",
" <td>8793.012323</td>\n",
" <td>6105.981512</td>\n",
" <td>2687.030811</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Infrastructure</th>\n",
" <th>15</th>\n",
" <td>Infrastructure</td>\n",
" <td>10565.647926</td>\n",
" <td>9083.477437</td>\n",
" <td>1482.170489</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" <td>9083.477437</td>\n",
" <td>1208.930957</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"2\" valign=\"top\">Transportation</th>\n",
" <th>11</th>\n",
" <td>Transportation</td>\n",
" <td>11370.846510</td>\n",
" <td>6541.475193</td>\n",
" <td>4829.371317</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>Transportation</td>\n",
" <td>6739.277077</td>\n",
" <td>6541.475193</td>\n",
" <td>197.801885</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" sector size sector_avg_size \\\n",
"sector \n",
"Automotive 4 Automotive 10397.636380 4788.954217 \n",
" 0 Automotive 4938.201337 4788.954217 \n",
"Energy 8 Energy 9753.958909 6105.981512 \n",
" 7 Energy 8793.012323 6105.981512 \n",
"Infrastructure 15 Infrastructure 10565.647926 9083.477437 \n",
" 19 Infrastructure 10292.408394 9083.477437 \n",
"Transportation 11 Transportation 11370.846510 6541.475193 \n",
" 12 Transportation 6739.277077 6541.475193 \n",
"\n",
" sector_demean_size \n",
"sector \n",
"Automotive 4 5608.682163 \n",
" 0 149.247120 \n",
"Energy 8 3647.977397 \n",
" 7 2687.030811 \n",
"Infrastructure 15 1482.170489 \n",
" 19 1208.930957 \n",
"Transportation 11 4829.371317 \n",
" 12 197.801885 "
]
},
"execution_count": 159,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def top_n(df, n, column):\n",
" return df.sort_values(by=column, ascending=False)[:n]\n",
"clients.groupby(\"sector\").apply(top_n, 2, \"size\")[['sector', 'size', 'sector_avg_size', 'sector_demean_size']]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Enjoy a brief moment of solitude and silence and try to understand what just happended."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"What has happened here? The top_n function is called on each piece of the DataFrame, then the results are glued together using `pandas.concat`, labeling the pieces with the group names. The result therefore has a hierarchical index whose inner level contains index values from the original DataFrame.\n",
"\n",
"The group name can be disabled by using `group_keys=False`"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>company</th>\n",
" <th>revenue</th>\n",
" <th>sector</th>\n",
" <th>size</th>\n",
" <th>sector_avg_size</th>\n",
" <th>sector_demean_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>224</td>\n",
" <td>7.771738e+08</td>\n",
" <td>Automotive</td>\n",
" <td>10397.636380</td>\n",
" <td>4788.954217</td>\n",
" <td>5608.682163</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>810</td>\n",
" <td>3.003936e+08</td>\n",
" <td>Automotive</td>\n",
" <td>4938.201337</td>\n",
" <td>4788.954217</td>\n",
" <td>149.247120</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>350</td>\n",
" <td>9.472119e+08</td>\n",
" <td>Energy</td>\n",
" <td>9753.958909</td>\n",
" <td>6105.981512</td>\n",
" <td>3647.977397</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>840</td>\n",
" <td>8.729771e+08</td>\n",
" <td>Energy</td>\n",
" <td>8793.012323</td>\n",
" <td>6105.981512</td>\n",
" <td>2687.030811</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>745</td>\n",
" <td>8.625963e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>10565.647926</td>\n",
" <td>9083.477437</td>\n",
" <td>1482.170489</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>924</td>\n",
" <td>8.510332e+08</td>\n",
" <td>Infrastructure</td>\n",
" <td>10292.408394</td>\n",
" <td>9083.477437</td>\n",
" <td>1208.930957</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>229</td>\n",
" <td>8.869656e+08</td>\n",
" <td>Transportation</td>\n",
" <td>11370.846510</td>\n",
" <td>6541.475193</td>\n",
" <td>4829.371317</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>141</td>\n",
" <td>4.589730e+08</td>\n",
" <td>Transportation</td>\n",
" <td>6739.277077</td>\n",
" <td>6541.475193</td>\n",
" <td>197.801885</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" company revenue sector size sector_avg_size \\\n",
"4 224 7.771738e+08 Automotive 10397.636380 4788.954217 \n",
"0 810 3.003936e+08 Automotive 4938.201337 4788.954217 \n",
"8 350 9.472119e+08 Energy 9753.958909 6105.981512 \n",
"7 840 8.729771e+08 Energy 8793.012323 6105.981512 \n",
"15 745 8.625963e+08 Infrastructure 10565.647926 9083.477437 \n",
"19 924 8.510332e+08 Infrastructure 10292.408394 9083.477437 \n",
"11 229 8.869656e+08 Transportation 11370.846510 6541.475193 \n",
"12 141 4.589730e+08 Transportation 6739.277077 6541.475193 \n",
"\n",
" sector_demean_size \n",
"4 5608.682163 \n",
"0 149.247120 \n",
"8 3647.977397 \n",
"7 2687.030811 \n",
"15 1482.170489 \n",
"19 1208.930957 \n",
"11 4829.371317 \n",
"12 197.801885 "
]
},
"execution_count": 125,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clients.groupby(\"sector\", group_keys=False).apply(top_n, 2, \"size\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Intermezzo: Reading external data\n",
"\n",
"Creating fake data is nice, but what you actually end up doing much more often is reading external data.\n",
"\n",
"For example if you have a `csv` of `xls` file, you can use the built-in functions `read_csv` or `read_excel`\n",
"\n",
"```python\n",
" pd.read_csv(filepath_or_buffer, sep=',', dialect=None, compression=None, doublequote=True, escapechar=None, quotechar='\"', quoting=0, skipinitialspace=False, lineterminator=None, header='infer', index_col=None, names=None, prefix=None, skiprows=None, skipfooter=None, skip_footer=0, na_values=None, na_fvalues=None, true_values=None, false_values=None, delimiter=None, converters=None, dtype=None, usecols=None, engine=None, delim_whitespace=False, as_recarray=False, na_filter=True, compact_ints=False, use_unsigned=False, low_memory=True, buffer_lines=None, warn_bad_lines=True, error_bad_lines=True, keep_default_na=True, thousands=None, comment=None, decimal='.', parse_dates=False, keep_date_col=False, dayfirst=False, date_parser=None, memory_map=False, float_precision=None, nrows=None, iterator=False, chunksize=None, verbose=False, encoding=None, squeeze=False, mangle_dupe_cols=True, tupleize_cols=False, infer_datetime_format=False, skip_blank_lines=True)\n",
" ```"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"* filepath_or_buffer : Most important: what should be read.\n",
" Can be a string or file handle / StringIO\n",
" The string could be a URL such as\n",
" http://, ftp://, s3://, and file://. \n",
" Local files can be opened with relative paths, without URL's.\n",
"* sep : Separator, default ','\n",
" If None, will try to automatically determine\n",
" this. Regular expressions are accepted.\n",
"* quotechar : A single character (such as `\"` or `'`)\n",
"* dtype : Type name or dict of column -> type\n",
" Data type for data or columns. E.g. {'a': np.float64, 'b': np.int32}\n",
" (Unsupported with engine='python')\n",
"* header : int, list of ints\n",
" Row number(s) to use as the column names, and the start of the\n",
" data. Defaults to 0 if no ``names`` passed, otherwise ``None``.\n",
"* skiprows : list-like or integer\n",
" Line numbers to skip (0-indexed) or number of lines to skip (int)\n",
" at the start of the file\n",
"* index_col : int or sequence or False, default None\n",
" Column to use as the row labels of the DataFrame.\n",
"* names : array-like\n",
" List of column names to use. If file contains no header row, then you\n",
" should explicitly pass header=None\n",
"* na_values : list-like or dict, default None\n",
" Additional strings to recognize as NA/NaN. If dict passed, specific\n",
" per-column NA values\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"* true_values : list\n",
" Values to consider as True\n",
"* false_values : list\n",
" Values to consider as False\n",
"* parse_dates : boolean, list of ints or names, list of lists, or dict\n",
" If True -> try parsing the index.\n",
" If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a separate date column.\n",
" If [[1, 3]] -> combine columns 1 and 3 and parse as a single date column.\n",
" {'foo' : [1, 3]} -> parse columns 1, 3 as date and call result 'foo'\n",
" A fast-path exists for iso8601-formatted dates.\n",
"* date_parser : function\n",
" Function to use for converting a sequence of string columns to an\n",
" array of datetime instances.\n",
"* encoding : string, default None\n",
" Encoding to use for UTF when reading/writing (ex. 'utf-8'). `List of Python\n",
" standard encodings\n",
" <https://docs.python.org/3/library/codecs.html#standard-encodings>`_"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The `read_excel` has similar options, use `pd.read_excel?` on the notebook to take a peek.\n",
"\n",
"Besides reading external data, pandas offers the ability to load data already loaded in memory. The general syntax is, again, quite simple, but the devil is in the details."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Quantile bucket analysis with cut and qcut\n",
"`cut` and `qcut` are handy tools to do bucket analysis. `cut` gives equal lenght buckets, while `qcut` gives equal size buckets"
]
},
{
"cell_type": "code",
"execution_count": 116,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"distribution = np.random.randn(1000)"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x269df799208>"
]
},
"execution_count": 132,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nqKgY0/pTahqnvb1d9913n+bNm5fpKCm9/fbb+v3vf68ZM2aotrY203FSam1t1SOPPJLpGFllqp3Q\n727S3d2tS5cuaf78+ZmOMqKhoSFt27ZNn332mVavXq2SkpJMRxrmyx3jq1evjmn9tJf9zp07FY/H\nk9cdx5FlWVq/fr2am5v1ox/96JbbMmW0nGVlZVq/fr3Wr1+vlpYW/e53v8vYuX1S5ZSkX//617Jt\nW48++mhGMkpjywkzDAwM6NChQ6qurr7lr+SpZNq0adq3b5+uXr2q/fv3q7Ozc0qdBeDL92eKi4sV\niUTG1JVpL/sdO3aMuPxf//qXuru79cILL8hxHMViMW3btk0//vGPlZeXl+aUt8/53x599FHt3r07\nY2WfKmdbW5vOnTunl19+OU2JRjbW7+dUEggE1Nvbm7wei8UUCAQymCj7JRIJHTx4UMuXL9fSpUsz\nHSclr9erYDCo8+fPT6myv3jxotrb23Xu3Dldv35dX3zxhRoaGvT888/f9j5TZhpn3rx5+tnPfpa8\nvmnTJu3du3dKHo3T1dWlr371q5KUsX/KMhbnz5/Xb37zG7366qu65557Mh0n65SUlKirq0s9PT2a\nNWuW/vSnP2nz5s2ZjnVbjuNk9K/hsWhsbFRRUdGUPArnS5cvX5bH45HX69X169f1/vvva+3atZmO\ndYunnnpKTz31lCTpwoULOnHixKhFL02hsv9vU/VNT0l666239J///EeWZSk/P1/f/e53Mx1pRD//\n+c81ODioXbt2Sbr5Jm1NTU2GUw33l7/8Rb/4xS90+fJl7dmzR8XFxXrxxRczHSurTuhXX1+vCxcu\nqL+/Xxs3blQoFNKqVasyHesWFy9e1MmTJzVv3jxt2bJFlmVpw4YNWrx4caaj3aKvr0+vvfaahoaG\n5DiOysvL9dBDD2U61oRxugQAMMCUO/QSAOA+yh4ADEDZA4ABKHsAMABlDwAGoOwBwACUPQAYgLIH\nAAP8P34ngIc9kkVeAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x269df806780>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd.Series(distribution).hist()"
]
},
{
"cell_type": "code",
"execution_count": 117,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"[(-1.819, -0.178], (-1.819, -0.178], (-1.819, -0.178], (-1.819, -0.178], (-1.819, -0.178], (1.462, 3.103], (-1.819, -0.178], (1.462, 3.103], (-1.819, -0.178], (-0.178, 1.462]]\n",
"Categories (4, object): [(-3.466, -1.819] < (-1.819, -0.178] < (-0.178, 1.462] < (1.462, 3.103]]"
]
},
"execution_count": 117,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.cut(distribution, 4)[:10]"
]
},
{
"cell_type": "code",
"execution_count": 118,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(-3.466, -1.819] 47\n",
"(-1.819, -0.178] 410\n",
"(-0.178, 1.462] 485\n",
"(1.462, 3.103] 58\n",
"dtype: int64"
]
},
"execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.cut(distribution, 4).value_counts()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"`qcut` in action"
]
},
{
"cell_type": "code",
"execution_count": 119,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[[-3.459, -0.768], (-0.768, -0.0346], (-0.768, -0.0346], [-3.459, -0.768], [-3.459, -0.768], (0.592, 3.103], [-3.459, -0.768], (0.592, 3.103], (-0.768, -0.0346], (0.592, 3.103]]\n",
"Categories (4, object): [[-3.459, -0.768] < (-0.768, -0.0346] < (-0.0346, 0.592] < (0.592, 3.103]]"
]
},
"execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.qcut(distribution, 4)[:10]"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[-3.459, -0.768] 250\n",
"(-0.768, -0.0346] 250\n",
"(-0.0346, 0.592] 250\n",
"(0.592, 3.103] 250\n",
"dtype: int64"
]
},
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.qcut(distribution, 4).value_counts()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"These two tools combined with `groupby` and `apply` allows for some powerful quantile bucket analysis"
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0 (-1.585, 0.193]\n",
"1 (-1.585, 0.193]\n",
"2 (-1.585, 0.193]\n",
"3 (0.193, 1.971]\n",
"4 (0.193, 1.971]\n",
"5 (1.971, 3.749]\n",
"6 (-1.585, 0.193]\n",
"7 (-3.37, -1.585]\n",
"8 (-1.585, 0.193]\n",
"9 (-1.585, 0.193]\n",
"Name: data1, dtype: category\n",
"Categories (4, object): [(-3.37, -1.585] < (-1.585, 0.193] < (0.193, 1.971] < (1.971, 3.749]]"
]
},
"execution_count": 121,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quantile_df = pd.DataFrame({'data1': np.random.randn(1000),\n",
" 'data2': np.random.randn(1000)})\n",
"factor = pd.cut(quantile_df.data1, 4)\n",
"factor[:10]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The `factor` object can be used in `groupby`. Then the function `get_stats` can be used to perform our quantile bucket analysis"
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"4\" halign=\"left\">0</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>count</th>\n",
" <th>max</th>\n",
" <th>mean</th>\n",
" <th>min</th>\n",
" </tr>\n",
" <tr>\n",
" <th>data1</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>(-3.37, -1.585]</th>\n",
" <td>65</td>\n",
" <td>1.963258</td>\n",
" <td>-0.071195</td>\n",
" <td>-2.452785</td>\n",
" </tr>\n",
" <tr>\n",
" <th>(-1.585, 0.193]</th>\n",
" <td>508</td>\n",
" <td>2.772137</td>\n",
" <td>0.063859</td>\n",
" <td>-3.501748</td>\n",
" </tr>\n",
" <tr>\n",
" <th>(0.193, 1.971]</th>\n",
" <td>404</td>\n",
" <td>2.509448</td>\n",
" <td>-0.019210</td>\n",
" <td>-3.486455</td>\n",
" </tr>\n",
" <tr>\n",
" <th>(1.971, 3.749]</th>\n",
" <td>23</td>\n",
" <td>2.124271</td>\n",
" <td>0.013707</td>\n",
" <td>-2.262153</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 \n",
" count max mean min\n",
"data1 \n",
"(-3.37, -1.585] 65 1.963258 -0.071195 -2.452785\n",
"(-1.585, 0.193] 508 2.772137 0.063859 -3.501748\n",
"(0.193, 1.971] 404 2.509448 -0.019210 -3.486455\n",
"(1.971, 3.749] 23 2.124271 0.013707 -2.262153"
]
},
"execution_count": 133,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def get_stats(group):\n",
" return {'min': group.min(), 'max': group.max(),\n",
" 'count': group.count(), 'mean': group.mean()}\n",
"pd.DataFrame(quantile_df.groupby(factor)['data2'].apply(get_stats)).unstack().sort_index()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Exercises\n",
"\n",
"* Execute the same analysis with `qcut`;\n",
"* Take the following dataframe and substitute `np.nan` with the group mean;\n",
"\n",
"```python\n",
"clients_subset = {'company': {0: 884, 1: 899, 2: 726, 3: 614, 4: 518, 5: 990, 6: 829, 7: 167, 8: 404, 9: 689, \n",
" 10: 750, 11: 745, 12: 509, 13: 984, 14: 747, 15: 440, 16: 259, 17: 873, 18: 699, \n",
" 19: 25}, \n",
" 'revenue': {0: 730619956.25072956, 1: np.nan, 2: np.nan, 3: 867634112.38782251, \n",
" 4: 196262014.94352257, \n",
" 5: 814864994.40613306, 6: 994426880.45623696, 7: 476683824.89750028, \n",
" 8: 356848182.07014269, 9: np.nan, 10: 639683029.55835235, 11: 747424142.78062439, \n",
" 12: nan, 13: 115353731.78738773, 14: 75707086.225602731, 15: 748278115.28668964, \n",
" 16: 957862503.83525848, 17: 493083188.27699083, 18: 985416381.32175076, \n",
" 19: np.nan}, \n",
" 'sector': {0: 'Automotive', 1: 'Automotive', 2: 'Automotive', 3: 'Automotive', \n",
" 4: 'Automotive', 5: 'Energy', 6: 'Energy', 7: 'Energy', 8: 'Energy', \n",
" 9: 'Energy', 10: 'Transportation', 11: 'Transportation', 12: 'Transportation', \n",
" 13: 'Transportation', 14: 'Transportation', 15: 'Infrastructure', \n",
" 16: 'Infrastructure', 17: 'Infrastructure', 18: 'Infrastructure', \n",
" 19: 'Infrastructure'}}\n",
"```\n",
"\n",
"* Take the following dataframe and compute the weighted group average \n",
"\n",
"```python\n",
"DataFrame({'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'],\n",
" 'data': np.random.randn(8),\n",
" 'weights': np.random.rand(8)})\n",
"```"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment