{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "oFDW_KLSoCMT" }, "source": [ "# Lecture 5: Advanced Pandas\n", "\n", "[Data Visualization · 1-DAV-105](https://bbrejova.github.io/viz/)\n", "\n", "Lecture by Broňa Brejová" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this lecture we cover some more advanced parts of Pandas which are often used in data processing." ] }, { "cell_type": "markdown", "metadata": { "id": "7Wh_dY4voIKp" }, "source": [ "As usual, we start by importing libraries. We also import the country data set from World Bank https://databank.worldbank.org/home under CC BY 4.0 license (see Lecture 03).\n" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "id": "d4IujUHNqM6y" }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "from IPython.display import Markdown\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "pd.options.display.float_format = '{:,.2f}'.format" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "id": "puB0lqRSyXk0" }, "outputs": [], "source": [ "url = 'https://bbrejova.github.io/viz/data/World_bank.csv'\n", "countries = pd.read_csv(url).set_index('Country')" ] }, { "cell_type": "markdown", "metadata": { "id": "z61tIyOxyFt9" }, "source": [ "## Hierarchical index (MultiIndex)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "oOBT6bzYFr2Q" }, "source": [ "### A small example table\n", "\n", "To illustrate a hierarchical index, we first create a very small table consisting of two countries and their population in two years, and convert this table from wide to long format." ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 354 }, "executionInfo": { "elapsed": 2220, "status": "ok", "timestamp": 1615829146871, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "zwOteqhkyLVh", "outputId": "2ec5634d-49ee-4751-dd0c-6f84abb5d9d8" }, "outputs": [ { "data": { "text/markdown": [ "**A small subset of countries table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2010Population2020
Country
Slovak Republic5,391,428.005,458,827.00
Austria8,363,404.008,916,864.00
\n", "
" ], "text/plain": [ " Population2010 Population2020\n", "Country \n", "Slovak Republic 5,391,428.00 5,458,827.00\n", "Austria 8,363,404.00 8,916,864.00" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Changed to long format:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CountryYearPopulation
0Slovak Republic20105,391,428.00
1Austria20108,363,404.00
2Slovak Republic20205,458,827.00
3Austria20208,916,864.00
\n", "
" ], "text/plain": [ " Country Year Population\n", "0 Slovak Republic 2010 5,391,428.00\n", "1 Austria 2010 8,363,404.00\n", "2 Slovak Republic 2020 5,458,827.00\n", "3 Austria 2020 8,916,864.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "example_countries = countries.loc[[\"Slovak Republic\", \"Austria\"], \n", " [\"Population2010\", \"Population2020\"]]\n", "display(Markdown(\"**A small subset of countries table:**\"), example_countries)\n", "# change to long format\n", "example_long = (example_countries.reset_index()\n", " .melt(id_vars=['Country'], \n", " var_name='Year', \n", " value_name='Population'))\n", "# change year from string such as \"Population2010\" to int 2010\n", "example_long.Year = example_long.Year.apply(lambda x : int(x[-4:]))\n", "display(Markdown(\"**Changed to long format:**\"), example_long)" ] }, { "cell_type": "markdown", "metadata": { "id": "-l_XpvIhE_2o" }, "source": [ "### An index with duplicate labels\n", "\n", "The original wide table had country as index, but in the long table, each country can have multiple rows. Pandas still allows us to use country as index with [duplicate values](https://pandas.pydata.org/docs/user_guide/duplicates.html). Selecting the name of the country then gives us multiple rows." ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 385 }, "executionInfo": { "elapsed": 2214, "status": "ok", "timestamp": 1615829146873, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "-3socJuT1Ttr", "outputId": "b6e44fb5-4e0b-4905-c3ae-839e7fe1ec73" }, "outputs": [ { "data": { "text/markdown": [ "**Table with country as index:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearPopulation
Country
Slovak Republic20105,391,428.00
Austria20108,363,404.00
Slovak Republic20205,458,827.00
Austria20208,916,864.00
\n", "
" ], "text/plain": [ " Year Population\n", "Country \n", "Slovak Republic 2010 5,391,428.00\n", "Austria 2010 8,363,404.00\n", "Slovak Republic 2020 5,458,827.00\n", "Austria 2020 8,916,864.00" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Selecting multiple rows using `example_long_indexed.loc['Slovak Republic']`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearPopulation
Country
Slovak Republic20105,391,428.00
Slovak Republic20205,458,827.00
\n", "
" ], "text/plain": [ " Year Population\n", "Country \n", "Slovak Republic 2010 5,391,428.00\n", "Slovak Republic 2020 5,458,827.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# set country name as index in a copy of the table\n", "example_long_indexed = example_long.set_index('Country')\n", "# display table with index\n", "display(Markdown(\"**Table with country as index:**\"), example_long_indexed)\n", "# select Slovakia from this table\n", "display(Markdown(\"**Selecting multiple rows using `example_long_indexed.loc['Slovak Republic']`:**\"))\n", "display(example_long_indexed.loc['Slovak Republic'])" ] }, { "cell_type": "markdown", "metadata": { "id": "rBNh1-z5GrC2" }, "source": [ "### Finally the hierarchical index\n", "\n", "Our table can be more naturally indexed by a pair (country, year), which uniquely specifies a row. An index consisting of two or more levels is called [hierarchical or multi-level](https://pandas.pydata.org/docs/user_guide/advanced.html). \n", "\n", "* MultiIndex can be created by `set_index` with a list of columns to use as index.\n", "* For faster operations, it is a good idea to sort the table by the index using [`sort_index`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html).\n", "* In `loc` use a tuple with one value per level, or only several initial levels.\n", "* To specify other levels, use [`xs`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.xs.html)." ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Table with a multiindex:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population
CountryYear
Austria20108,363,404.00
20208,916,864.00
Slovak Republic20105,391,428.00
20205,458,827.00
\n", "
" ], "text/plain": [ " Population\n", "Country Year \n", "Austria 2010 8,363,404.00\n", " 2020 8,916,864.00\n", "Slovak Republic 2010 5,391,428.00\n", " 2020 5,458,827.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# create MultiIndex by choosing a list of columns\n", "example_multiindexed = example_long.set_index(['Country', 'Year']).sort_index()\n", "display(Markdown(\"**Table with a multiindex:**\"), example_multiindexed)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Selecting a row by using a tuple in `loc`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Population 5,391,428.00\n", "Name: (Slovak Republic, 2010), dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Selecting a row by using a tuple in `loc`:**\"))\n", "display(example_multiindexed.loc[('Slovak Republic', 2010)])" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Selecting all rows for a country using a shorter tuple in `loc`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population
Year
20105,391,428.00
20205,458,827.00
\n", "
" ], "text/plain": [ " Population\n", "Year \n", "2010 5,391,428.00\n", "2020 5,458,827.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Selecting all rows for a country using a shorter tuple in `loc`:**\"))\n", "display(example_multiindexed.loc[('Slovak Republic',)])" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Selecting all rows for a year using `xs`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population
Country
Austria8,363,404.00
Slovak Republic5,391,428.00
\n", "
" ], "text/plain": [ " Population\n", "Country \n", "Austria 8,363,404.00\n", "Slovak Republic 5,391,428.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Selecting all rows for a year using `xs`:**\"))\n", "display(example_multiindexed.xs(2010, level='Year'))" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 779 }, "executionInfo": { "elapsed": 2208, "status": "ok", "timestamp": 1615829146873, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "Vh3GnNq513Zc", "outputId": "5b7843ec-dd7d-4ca3-8a58-b3f3c9618f3f" }, "outputs": [ { "data": { "text/markdown": [ "**Names of index levels can be used in `query`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population
CountryYear
Austria20208,916,864.00
Slovak Republic20205,458,827.00
\n", "
" ], "text/plain": [ " Population\n", "Country Year \n", "Austria 2020 8,916,864.00\n", "Slovak Republic 2020 5,458,827.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Names of index levels can be used in `query`:**\"))\n", "display(example_multiindexed.query('Year > 2015'))" ] }, { "cell_type": "markdown", "metadata": { "id": "pCRKUE-0BkrC" }, "source": [ "## Combining tables" ] }, { "cell_type": "markdown", "metadata": { "id": "sDX1Bi05JsQw" }, "source": [ "### Concatenating tables using `concat`\n", "\n", "* Function [`concat`](https://pandas.pydata.org/docs/reference/api/pandas.concat.html) can be used to concatenate several tables. \n", "* At the default settings, it combines along axis 0, meaning that the rows of second table are added after the rows of the first table. \n", "* We will also use it for `axis=1`, in which case it finds rows with the same index in both tables and combines their columns.\n", "* By default, the result has union of rows of the two tables, but intersection can be obtained by `join='inner'`. \n", "\n", "#### Example\n", "\n", "Create a second small table of countries and display both tables. Then illustrate various concatenation modes using these tables." ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**The first small table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2010Population2020
Country
Slovak Republic5,391,428.005,458,827.00
Austria8,363,404.008,916,864.00
\n", "
" ], "text/plain": [ " Population2010 Population2020\n", "Country \n", "Slovak Republic 5,391,428.00 5,458,827.00\n", "Austria 8,363,404.00 8,916,864.00" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**The second small table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AreaRegion
Country
Slovak Republic49,030.00Europe & Central Asia
Austria83,879.00Europe & Central Asia
Hungary93,030.00Europe & Central Asia
\n", "
" ], "text/plain": [ " Area Region\n", "Country \n", "Slovak Republic 49,030.00 Europe & Central Asia\n", "Austria 83,879.00 Europe & Central Asia\n", "Hungary 93,030.00 Europe & Central Asia" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "example_countries2 = countries.loc[[\"Slovak Republic\", \"Austria\", \"Hungary\"], \n", " [\"Area\", \"Region\"]]\n", "display(Markdown(\"**The first small table:**\"), example_countries)\n", "display(Markdown(\"**The second small table:**\"), example_countries2)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Tables concatenated along axis 0:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2010Population2020AreaRegion
Country
Slovak Republic5,391,428.005,458,827.00NaNNaN
Austria8,363,404.008,916,864.00NaNNaN
Slovak RepublicNaNNaN49,030.00Europe & Central Asia
AustriaNaNNaN83,879.00Europe & Central Asia
HungaryNaNNaN93,030.00Europe & Central Asia
\n", "
" ], "text/plain": [ " Population2010 Population2020 Area \\\n", "Country \n", "Slovak Republic 5,391,428.00 5,458,827.00 NaN \n", "Austria 8,363,404.00 8,916,864.00 NaN \n", "Slovak Republic NaN NaN 49,030.00 \n", "Austria NaN NaN 83,879.00 \n", "Hungary NaN NaN 93,030.00 \n", "\n", " Region \n", "Country \n", "Slovak Republic NaN \n", "Austria NaN \n", "Slovak Republic Europe & Central Asia \n", "Austria Europe & Central Asia \n", "Hungary Europe & Central Asia " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Tables concatenated along axis 0:**\"))\n", "display(pd.concat([example_countries, example_countries2]))" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Tables concatenated along axis 1:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2010Population2020AreaRegion
Country
Slovak Republic5,391,428.005,458,827.0049,030.00Europe & Central Asia
Austria8,363,404.008,916,864.0083,879.00Europe & Central Asia
HungaryNaNNaN93,030.00Europe & Central Asia
\n", "
" ], "text/plain": [ " Population2010 Population2020 Area \\\n", "Country \n", "Slovak Republic 5,391,428.00 5,458,827.00 49,030.00 \n", "Austria 8,363,404.00 8,916,864.00 83,879.00 \n", "Hungary NaN NaN 93,030.00 \n", "\n", " Region \n", "Country \n", "Slovak Republic Europe & Central Asia \n", "Austria Europe & Central Asia \n", "Hungary Europe & Central Asia " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Tables concatenated along axis 1:**\"))\n", "display(pd.concat([example_countries, example_countries2], axis=1))" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 932 }, "executionInfo": { "elapsed": 2201, "status": "ok", "timestamp": 1615829146874, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "M31lr9WEB676", "outputId": "f3af192b-5dd6-47d9-f0c6-37316e426348" }, "outputs": [ { "data": { "text/markdown": [ "**Tables concatenated along axis 1 with inner join:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2010Population2020AreaRegion
Country
Slovak Republic5,391,428.005,458,827.0049,030.00Europe & Central Asia
Austria8,363,404.008,916,864.0083,879.00Europe & Central Asia
\n", "
" ], "text/plain": [ " Population2010 Population2020 Area \\\n", "Country \n", "Slovak Republic 5,391,428.00 5,458,827.00 49,030.00 \n", "Austria 8,363,404.00 8,916,864.00 83,879.00 \n", "\n", " Region \n", "Country \n", "Slovak Republic Europe & Central Asia \n", "Austria Europe & Central Asia " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Tables concatenated along axis 1 with inner join:**\"))\n", "display(pd.concat([example_countries, example_countries2], axis=1, join='inner'))" ] }, { "cell_type": "markdown", "metadata": { "id": "pbboYuzELnoB" }, "source": [ "### Merging tables with `merge`\n", "\n", "* Function [`merge`](https://pandas.pydata.org/docs/reference/api/pandas.merge.html) works similarly as `concat` with `axis=1`, but it will match lines of two tables using any specified columns, not necessarily index. \n", "* If values in these columns repeat, it combines all matching pairs of rows.\n", "* Setting `how` in `merge` allows us to include rows that do not have a matching row in the other table. \n" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**DataFrame `tab1`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namevalue
0a1
1a2
2a3
3b4
\n", "
" ], "text/plain": [ " name value\n", "0 a 1\n", "1 a 2\n", "2 a 3\n", "3 b 4" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**DataFrame `tab2`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namevalue
0a10
1a20
2b30
\n", "
" ], "text/plain": [ " name value\n", "0 a 10\n", "1 a 20\n", "2 b 30" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Result of `pd.merge(tab1, tab2, on='name')`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namevalue_xvalue_y
0a110
1a120
2a210
3a220
4a310
5a320
6b430
\n", "
" ], "text/plain": [ " name value_x value_y\n", "0 a 1 10\n", "1 a 1 20\n", "2 a 2 10\n", "3 a 2 20\n", "4 a 3 10\n", "5 a 3 20\n", "6 b 4 30" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# a small example of how all combinations of matching rows are returned:\n", "tab1 = pd.DataFrame({'name': ['a','a','a','b'], 'value': [1,2,3,4]})\n", "tab2 = pd.DataFrame({'name': ['a','a','b'], 'value': [10,20,30]})\n", "display(Markdown(\"**DataFrame `tab1`:**\"))\n", "display(tab1)\n", "display(Markdown(\"**DataFrame `tab2`:**\"))\n", "display(tab2)\n", "display(Markdown(\"**Result of `pd.merge(tab1, tab2, on='name')`:**\"))\n", "display(pd.merge(tab1, tab2, on='name'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example of using `merge` on countries\n", "\n", "* Countries belong to various international organizations and a single country can belong to many. We will represent this as a table having one row for each pair of country and an organization it belongs to.\n", "* To combine this with other country data, we apply `merge` to get a table in which each country is copied for each organization it is in.\n", "* Then we can for example compute the total number of people living in countries covered by individual organizations. \n", "\n" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**A small country membership table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CountryMember
0Slovak RepublicNATO
1Slovak RepublicEU
2Slovak RepublicUN
3AustriaUN
4AustriaEU
\n", "
" ], "text/plain": [ " Country Member\n", "0 Slovak Republic NATO\n", "1 Slovak Republic EU\n", "2 Slovak Republic UN\n", "3 Austria UN\n", "4 Austria EU" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# we create a small membership table by parsing a CSV-format string\n", "import io\n", "membership_str = io.StringIO(\"\"\"Country,Member\n", "Slovak Republic,NATO\n", "Slovak Republic,EU\n", "Slovak Republic,UN\n", "Austria,UN\n", "Austria,EU\n", "\"\"\")\n", "membership = pd.read_csv(membership_str)\n", "display(Markdown(\"**A small country membership table:**\"), membership)" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Merged table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CountryPopulation2010Population2020Member
0Slovak Republic5,391,428.005,458,827.00NATO
1Slovak Republic5,391,428.005,458,827.00EU
2Slovak Republic5,391,428.005,458,827.00UN
3Austria8,363,404.008,916,864.00UN
4Austria8,363,404.008,916,864.00EU
\n", "
" ], "text/plain": [ " Country Population2010 Population2020 Member\n", "0 Slovak Republic 5,391,428.00 5,458,827.00 NATO\n", "1 Slovak Republic 5,391,428.00 5,458,827.00 EU\n", "2 Slovak Republic 5,391,428.00 5,458,827.00 UN\n", "3 Austria 8,363,404.00 8,916,864.00 UN\n", "4 Austria 8,363,404.00 8,916,864.00 EU" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# merging tables using column Country in both\n", "example_membership = pd.merge(example_countries, membership, on='Country')\n", "display(Markdown(\"**Merged table:**\"), example_membership)" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "np.float64(14375691.0)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# compute the total number of people in EU (here only for our two countries)\n", "display(example_membership.query('Member == \"EU\"')['Population2020'].sum())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we will see in the next section, we can also use `groupby` to compute sums for all organizations. " ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 589 }, "executionInfo": { "elapsed": 2438, "status": "ok", "timestamp": 1615829147119, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "R4Wws_N24cXQ", "outputId": "ce3eda44-8215-4939-8fe9-d9faafc4dda5" }, "outputs": [ { "data": { "text/markdown": [ "**The sum of country populations for each organization** (only for our two countries)" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Member\n", "EU 14,375,691.00\n", "NATO 5,458,827.00\n", "UN 14,375,691.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**The sum of country populations for each organization** (only for our two countries)\"))\n", "display(example_membership.groupby('Member')['Population2020'].sum())" ] }, { "cell_type": "markdown", "metadata": { "id": "xZjoqjfEAlrf" }, "source": [ "Similar operations are often done in relational databases, where `merge` is called join. More in a specialized database course in the third year. Next we will cover `groupby` function, which is also frequently used in databases." ] }, { "cell_type": "markdown", "metadata": { "id": "Ho5jlAgiH1kK" }, "source": [ "## Aggregation, split-apply-combine (`groupby`)\n", "\n", "### A simple example of `groupby` command\n", "\n", "In our big table of all countries, we have a column called `Region`. Let us say we want to compute the number of countries belonging to each region of the world. \n", "\n", "* First, `groupby` command splits countries into groups by `Region`.\n", "* Then, `size` computes the size of each group (the number of rows)." ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**The number of countries in each region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Region\n", "East Asia & Pacific 37\n", "Europe & Central Asia 58\n", "Latin America & Caribbean 42\n", "Middle East & North Africa 21\n", "North America 3\n", "South Asia 8\n", "Sub-Saharan Africa 48\n", "dtype: int64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**The number of countries in each region:**\"))\n", "display(countries.groupby('Region').size())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### General principles\n", "\n", "Pandas follow the [split-apply-combine strategy](https://pandas.pydata.org/docs/user_guide/groupby.html) introduced in R by [Hadley Wickham](https://www.jstatsoft.org/article/view/v040i01/v40i01.pdf).\n", "\n", "**Split**: split data into groups, often by values in some column, such as `Region` in the `countries` table.\n", "\n", "**Apply**: apply some computation on each group, obtaining some result (single value, Series, DataFrame).\n", "\n", "**Combine**: concatenate results for all groups together to a new table.\n", "\n", "\n", "**Typical operations in the apply step:**\n", "\n", "* **aggregation**: e.g. compute group size, mean, median etc.\n", "* **transformation**: e.g. compute percentage or rank of each item within a group\n", "* **filtering**: e.g. include only groups that are large enough \n", "\n", "In Pandas, this is done by combination of [`groupby`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html#pandas.DataFrame.groupby) for the split step and additional functions for the apply step. The combine step is done implicitly. Pandas library provides many options, we will cover only basics." ] }, { "cell_type": "markdown", "metadata": { "id": "QsiYPrp1KCw2" }, "source": [ "### Simple aggregation in the apply step\n", "\n", "Apply functions such as `sum`, `mean`, `median`, `min`, `max`, `size`, `count`, `describe` after `groupby`.\n", "\n", "* `size` gives the number of rows in the group (see example above).\n", "* `count` gives the number of non-missing values in each column." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Sums of country indicators in each region**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ " (including nonsense sums such as life expectation or GDP per capita)" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2000Population2010Population2020AreaGDP2000GDP2010GDP2020Expectancy2000Expectancy2010Expectancy2020Fertility2000Fertility2010Fertility2020
Region
East Asia & Pacific2,025,976,167.002,187,065,378.002,340,350,517.0024,794,669.42233,980.83506,478.43569,610.582,436.612,454.652,520.88103.9291.5880.30
Europe & Central Asia862,786,208.00889,169,626.00922,353,365.0028,813,751.77883,386.741,752,994.151,966,242.674,053.364,204.814,255.0694.74100.0993.30
Latin America & Caribbean521,281,151.00588,873,865.00650,534,988.0020,523,017.36194,902.34462,544.16522,816.202,931.713,013.732,957.72108.0790.7476.61
Middle East & North Africa321,037,455.00397,997,552.00479,966,650.0011,385,553.90172,013.59327,153.10293,809.501,496.971,557.331,568.0971.5459.8652.64
North America312,909,973.00343,397,156.00369,582,572.0019,715,550.00116,885.13198,088.01214,882.96234.66240.36239.795.315.284.45
South Asia1,406,945,496.001,660,546,144.001,882,531,621.005,135,270.005,525.8716,479.9221,370.63511.70546.95568.0931.6224.6619.56
Sub-Saharan Africa671,212,484.00879,797,424.001,151,302,077.0024,328,265.8743,582.79108,587.6696,165.832,547.642,803.973,003.10262.34237.78205.94
\n", "
" ], "text/plain": [ " Population2000 Population2010 Population2020 \\\n", "Region \n", "East Asia & Pacific 2,025,976,167.00 2,187,065,378.00 2,340,350,517.00 \n", "Europe & Central Asia 862,786,208.00 889,169,626.00 922,353,365.00 \n", "Latin America & Caribbean 521,281,151.00 588,873,865.00 650,534,988.00 \n", "Middle East & North Africa 321,037,455.00 397,997,552.00 479,966,650.00 \n", "North America 312,909,973.00 343,397,156.00 369,582,572.00 \n", "South Asia 1,406,945,496.00 1,660,546,144.00 1,882,531,621.00 \n", "Sub-Saharan Africa 671,212,484.00 879,797,424.00 1,151,302,077.00 \n", "\n", " Area GDP2000 GDP2010 GDP2020 \\\n", "Region \n", "East Asia & Pacific 24,794,669.42 233,980.83 506,478.43 569,610.58 \n", "Europe & Central Asia 28,813,751.77 883,386.74 1,752,994.15 1,966,242.67 \n", "Latin America & Caribbean 20,523,017.36 194,902.34 462,544.16 522,816.20 \n", "Middle East & North Africa 11,385,553.90 172,013.59 327,153.10 293,809.50 \n", "North America 19,715,550.00 116,885.13 198,088.01 214,882.96 \n", "South Asia 5,135,270.00 5,525.87 16,479.92 21,370.63 \n", "Sub-Saharan Africa 24,328,265.87 43,582.79 108,587.66 96,165.83 \n", "\n", " Expectancy2000 Expectancy2010 Expectancy2020 \\\n", "Region \n", "East Asia & Pacific 2,436.61 2,454.65 2,520.88 \n", "Europe & Central Asia 4,053.36 4,204.81 4,255.06 \n", "Latin America & Caribbean 2,931.71 3,013.73 2,957.72 \n", "Middle East & North Africa 1,496.97 1,557.33 1,568.09 \n", "North America 234.66 240.36 239.79 \n", "South Asia 511.70 546.95 568.09 \n", "Sub-Saharan Africa 2,547.64 2,803.97 3,003.10 \n", "\n", " Fertility2000 Fertility2010 Fertility2020 \n", "Region \n", "East Asia & Pacific 103.92 91.58 80.30 \n", "Europe & Central Asia 94.74 100.09 93.30 \n", "Latin America & Caribbean 108.07 90.74 76.61 \n", "Middle East & North Africa 71.54 59.86 52.64 \n", "North America 5.31 5.28 4.45 \n", "South Asia 31.62 24.66 19.56 \n", "Sub-Saharan Africa 262.34 237.78 205.94 " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Sums of country indicators in each region**\"))\n", "display(Markdown(\" (including nonsense sums such as life expectation or GDP per capita)\"))\n", "display(countries.groupby('Region').sum(numeric_only=True))" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 971 }, "executionInfo": { "elapsed": 531, "status": "ok", "timestamp": 1615830985216, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "pR_XM_DVIOl-", "outputId": "b202e8ac-6597-4d3c-f008-6867b2842865" }, "outputs": [ { "data": { "text/markdown": [ "**Specifically sum only population in 2020 per region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Region\n", "East Asia & Pacific 2,340,350,517.00\n", "Europe & Central Asia 922,353,365.00\n", "Latin America & Caribbean 650,534,988.00\n", "Middle East & North Africa 479,966,650.00\n", "North America 369,582,572.00\n", "South Asia 1,882,531,621.00\n", "Sub-Saharan Africa 1,151,302,077.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Specifically sum only population in 2020 per region:**\"))\n", "display(countries.groupby('Region')['Population2020'].sum())" ] }, { "cell_type": "markdown", "metadata": { "id": "QKvHsuDqKG7Z" }, "source": [ "### Transformation in the apply step\n", "\n", "Here we use [`transform`](https://pandas.pydata.org/docs/user_guide/groupby.html#the-transform-method) method which gets a function which is used on every group and should produce a group with the same index. We could write our own function (e.g. a lambda expression) or we can use one the built-in functions specified by a string. \n", "\n", "Here we compute for each country what percentage is its population from the population of the region." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**For each country, what is the total population of its region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan 1,882,531,621.00\n", "Albania 922,353,365.00\n", "Algeria 479,966,650.00\n", "American Samoa 2,340,350,517.00\n", "Andorra 922,353,365.00\n", " ... \n", "Virgin Islands 650,534,988.00\n", "West Bank and Gaza 479,966,650.00\n", "Yemen 479,966,650.00\n", "Zambia 1,151,302,077.00\n", "Zimbabwe 1,151,302,077.00\n", "Name: Population2020, Length: 217, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**For each country, what fraction is its population within region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan 0.02\n", "Albania 0.00\n", "Algeria 0.09\n", "American Samoa 0.00\n", "Andorra 0.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# group countries by region, compute the sum of each region \n", "# and copy the regional sum for each country\n", "region_sums = countries.groupby('Region')['Population2020'].transform('sum')\n", "display(Markdown(\"**For each country, what is the total population of its region:**\"))\n", "display(region_sums)\n", "# now divide the population of the country by the regional total\n", "pop_within_group = countries['Population2020'] / region_sums\n", "display(Markdown(\"**For each country, what fraction is its population within region:**\"))\n", "display(pop_within_group.head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bellow we see an alternative form of the same computation when transformation is done via a lambda function that takes a list `x` of country sizes within a region and divides them by the sum of `x`. \n", "\n", "The use of lambda functions applied on each element is often convenient but might be slow on large data.\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**For each country, what fraction is its population within region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan 0.02\n", "Albania 0.00\n", "Algeria 0.09\n", "American Samoa 0.00\n", "Andorra 0.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pop_within_group = (countries.groupby('Region')['Population2020']\n", " .transform(lambda x : x / x.sum()))\n", "display(Markdown(\"**For each country, what fraction is its population within region:**\"))\n", "display(pop_within_group.head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lambda expression `lambda x : x / x.sum()` above is a shorthand for defining a function which gets `x` and returns `x / x.sum()`. Below we show a version with function explictly defined." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**For each country, what fraction is its population within region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan 0.02\n", "Albania 0.00\n", "Algeria 0.09\n", "American Samoa 0.00\n", "Andorra 0.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def group_fraction(x):\n", " return x / x.sum()\n", "pop_within_group = (countries.groupby('Region')['Population2020']\n", " .transform(group_fraction))\n", "display(Markdown(\"**For each country, what fraction is its population within region:**\"))\n", "display(pop_within_group.head())" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Add back region name using concat:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2020Region
Country
Afghanistan0.02South Asia
Albania0.00Europe & Central Asia
Algeria0.09Middle East & North Africa
American Samoa0.00East Asia & Pacific
Andorra0.00Europe & Central Asia
\n", "
" ], "text/plain": [ " Population2020 Region\n", "Country \n", "Afghanistan 0.02 South Asia\n", "Albania 0.00 Europe & Central Asia\n", "Algeria 0.09 Middle East & North Africa\n", "American Samoa 0.00 East Asia & Pacific\n", "Andorra 0.00 Europe & Central Asia" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Look up value for Slovakia:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Population2020 0.01\n", "Region Europe & Central Asia\n", "Name: Slovak Republic, dtype: object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Add back region name using concat:**\"))\n", "pop_within_group2 = pd.concat([pop_within_group, countries['Region']], axis=1)\n", "display(pop_within_group2.head())\n", "\n", "display(Markdown(\"**Look up value for Slovakia:**\"))\n", "display(pop_within_group2.loc[\"Slovak Republic\"])" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 821 }, "executionInfo": { "elapsed": 2758, "status": "ok", "timestamp": 1615829147452, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "HUsclvesKK9z", "outputId": "b74ea1cb-49d6-48f9-b26e-572528616209" }, "outputs": [ { "data": { "text/markdown": [ "**Check that the sum of each region is 1:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Population2020
Region
East Asia & Pacific1.00
Europe & Central Asia1.00
Latin America & Caribbean1.00
Middle East & North Africa1.00
North America1.00
South Asia1.00
Sub-Saharan Africa1.00
\n", "
" ], "text/plain": [ " Population2020\n", "Region \n", "East Asia & Pacific 1.00\n", "Europe & Central Asia 1.00\n", "Latin America & Caribbean 1.00\n", "Middle East & North Africa 1.00\n", "North America 1.00\n", "South Asia 1.00\n", "Sub-Saharan Africa 1.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Check that the sum of each region is 1:**\"))\n", "display(pop_within_group2.groupby('Region').sum())" ] }, { "cell_type": "markdown", "metadata": { "id": "5-wxNPSEKLza" }, "source": [ "### Filtering in the apply step\n", "\n", "Finally, `groupby` can be followed by [`filter`](https://pandas.pydata.org/docs/user_guide/groupby.html#filtration) to use only some of the groups in the result.\n", "\n", "Here we report all countries in regions that have at least one billion inhabitants." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 555 }, "executionInfo": { "elapsed": 2750, "status": "ok", "timestamp": 1615829147452, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "b_5e0c2ZPrEZ", "outputId": "4d904ba0-f133-4523-a296-816d04d8fa7c" }, "outputs": [ { "data": { "text/markdown": [ "**Filtered data:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ISO3RegionIncome GroupPopulation2000Population2010Population2020AreaGDP2000GDP2010GDP2020Expectancy2000Expectancy2010Expectancy2020Fertility2000Fertility2010Fertility2020
Country
AfghanistanAFGSouth AsiaLow income19,542,983.0028,189,672.0038,972,231.00652,860.00NaN562.50512.0655.3060.8562.587.536.104.75
American SamoaASMEast Asia & PacificHigh income58,229.0054,849.0046,189.00200.00NaN10,446.8615,609.78NaNNaNNaNNaNNaNNaN
AngolaAGOSub-Saharan AfricaLower middle income16,394,062.0023,364,186.0033,428,486.001,246,700.00556.883,586.661,450.9146.0256.7362.266.646.195.37
AustraliaAUSEast Asia & PacificHigh income19,028,802.0022,031,750.0025,649,247.007,741,220.0021,870.4252,147.0251,868.2579.2381.7083.201.761.931.58
BangladeshBGDSouth AsiaLower middle income129,193,327.00148,391,139.00167,420,950.00147,570.00413.10776.862,233.3165.7868.6471.973.222.342.00
\n", "
" ], "text/plain": [ " ISO3 Region Income Group Population2000 \\\n", "Country \n", "Afghanistan AFG South Asia Low income 19,542,983.00 \n", "American Samoa ASM East Asia & Pacific High income 58,229.00 \n", "Angola AGO Sub-Saharan Africa Lower middle income 16,394,062.00 \n", "Australia AUS East Asia & Pacific High income 19,028,802.00 \n", "Bangladesh BGD South Asia Lower middle income 129,193,327.00 \n", "\n", " Population2010 Population2020 Area GDP2000 \\\n", "Country \n", "Afghanistan 28,189,672.00 38,972,231.00 652,860.00 NaN \n", "American Samoa 54,849.00 46,189.00 200.00 NaN \n", "Angola 23,364,186.00 33,428,486.00 1,246,700.00 556.88 \n", "Australia 22,031,750.00 25,649,247.00 7,741,220.00 21,870.42 \n", "Bangladesh 148,391,139.00 167,420,950.00 147,570.00 413.10 \n", "\n", " GDP2010 GDP2020 Expectancy2000 Expectancy2010 \\\n", "Country \n", "Afghanistan 562.50 512.06 55.30 60.85 \n", "American Samoa 10,446.86 15,609.78 NaN NaN \n", "Angola 3,586.66 1,450.91 46.02 56.73 \n", "Australia 52,147.02 51,868.25 79.23 81.70 \n", "Bangladesh 776.86 2,233.31 65.78 68.64 \n", "\n", " Expectancy2020 Fertility2000 Fertility2010 Fertility2020 \n", "Country \n", "Afghanistan 62.58 7.53 6.10 4.75 \n", "American Samoa NaN NaN NaN NaN \n", "Angola 62.26 6.64 6.19 5.37 \n", "Australia 83.20 1.76 1.93 1.58 \n", "Bangladesh 71.97 3.22 2.34 2.00 " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Check sums in regions for selected countries:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Region\n", "East Asia & Pacific 2,340,350,517.00\n", "South Asia 1,882,531,621.00\n", "Sub-Saharan Africa 1,151,302,077.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# filter gets a function returning a boolean value for each group\n", "filtered = (countries.groupby(\"Region\")\n", " .filter(lambda x : x['Population2020'].sum() > 1e9))\n", "display(Markdown(\"**Filtered data:**\"))\n", "display(filtered.head())\n", "display(Markdown(\"**Check sums in regions for selected countries:**\"))\n", "display(filtered.groupby('Region')['Population2020'].sum())" ] }, { "cell_type": "markdown", "metadata": { "id": "bYMuUXnjKTQG" }, "source": [ "### Grouping by multiple values\n", "\n", "Function `groupby` can get a single column, but also a list of columns or a Series which will be used as if it was a column of the table. " ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 477 }, "executionInfo": { "elapsed": 2744, "status": "ok", "timestamp": 1615829147453, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "FR2TAQWAQhUJ", "outputId": "21a885ed-31f4-462c-b7ce-282b1931ee10" }, "outputs": [ { "data": { "text/markdown": [ "**Populations split by both region and income group**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Region Income Group \n", "East Asia & Pacific High income 223,971,823.00\n", " Low income 25,867,467.00\n", " Lower middle income 301,779,468.00\n", " Upper middle income 1,788,731,759.00\n", "Europe & Central Asia High income 522,292,344.00\n", " Lower middle income 94,487,207.00\n", " Upper middle income 305,573,814.00\n", "Latin America & Caribbean High income 34,033,357.00\n", " Lower middle income 40,120,621.00\n", " Upper middle income 547,890,556.00\n", "Middle East & North Africa High income 68,156,525.00\n", " Low income 53,056,642.00\n", " Lower middle income 304,739,289.00\n", " Upper middle income 54,014,194.00\n", "North America High income 369,582,572.00\n", "South Asia Low income 38,972,231.00\n", " Lower middle income 1,843,044,952.00\n", " Upper middle income 514,438.00\n", "Sub-Saharan Africa High income 98,462.00\n", " Low income 549,157,331.00\n", " Lower middle income 533,054,222.00\n", " Upper middle income 68,992,062.00\n", "Name: Population2020, dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Populations split by both region and income group**\"))\n", "display(countries.groupby(['Region', \"Income Group\"])['Population2020'].sum())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Now we create a Series classifying each country as small, medium and large using cutoff 1 million for small and 100 million for medium. \n", "* We then use this Series in `groupby`.\n", "* The classification is created by [`pd.cut`](https://pandas.pydata.org/docs/reference/api/pandas.cut.html) function.\n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Country size classification:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan medium\n", "Albania medium\n", "Algeria medium\n", "American Samoa small\n", "Andorra small\n", "Name: SizeCategory, dtype: category\n", "Categories (3, object): ['small' < 'medium' < 'large']" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "bin_ends = [0, 1e6, 1e8, 1e10]\n", "bin_labels = [\"small\", \"medium\", \"large\"]\n", "size_groups = pd.cut(countries['Population2020'],\n", " bins=bin_ends, labels=bin_labels).rename(\"SizeCategory\")\n", "display(Markdown(\"**Country size classification:**\"))\n", "display(size_groups.head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can use `size_groups` Series in `groupby`. \n", "\n", "Parameter [`observed=True`](https://pandas.pydata.org/docs/user_guide/groupby.html#handling-of-un-observed-categorical-values) is related to the fact that `size_groups` is has a categorial variable type to be explained next." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 743 }, "executionInfo": { "elapsed": 2740, "status": "ok", "timestamp": 1615829147455, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "8f2a6JumWavk", "outputId": "1f8275ec-215d-4ee9-e84f-e64249ce5371" }, "outputs": [ { "data": { "text/markdown": [ "**The number of countries in each size group:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "SizeCategory\n", "small 57\n", "medium 146\n", "large 14\n", "dtype: int64" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**The number of countries in each size group and region:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Region SizeCategory\n", "East Asia & Pacific small 18\n", " medium 15\n", " large 4\n", "Europe & Central Asia small 12\n", " medium 45\n", " large 1\n", "Latin America & Caribbean small 19\n", " medium 21\n", " large 2\n", "Middle East & North Africa small 1\n", " medium 19\n", " large 1\n", "North America small 1\n", " medium 1\n", " large 1\n", "South Asia small 2\n", " medium 3\n", " large 3\n", "Sub-Saharan Africa small 4\n", " medium 42\n", " large 2\n", "dtype: int64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# now use size_groups in groupby\n", "display(Markdown(\"**The number of countries in each size group:**\"))\n", "display(countries.groupby(size_groups, observed=True).size())\n", "display(Markdown(\"**The number of countries in each size group and region:**\"))\n", "display(countries.groupby(['Region', size_groups], observed=True).size())" ] }, { "cell_type": "markdown", "metadata": { "id": "7eSiXzIuKhxb" }, "source": [ "## Categorical variables\n", "\n", "Categorical variables have values from a small set, such as region and income group in the table of countries. So far we have represented them only as strings, but we can explicitly convert them to a [categorical data type](https://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html) in Pandas. \n", "\n", "This has several advantages:\n", "* Strings are internally replaced by numerical IDs within the table, potentially saving memory.\n", "* Categories can be ordered and then sorting, minimum, maximum etc works as desired, not alphabetically.\n", "* Pandas is aware of the full set of possible values. For example categories without members can appear in the `groupby` results.\n", "\n", "#### Example\n", "Income groups in our table are strings, we will convert them to an ordered categorical variable." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "**Income Group column in the old table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan Low income\n", "Albania Upper middle income\n", "Algeria Lower middle income\n", "Name: Income Group, dtype: object" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Income Group column in the new table:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Country\n", "Afghanistan Low income\n", "Albania Upper middle income\n", "Algeria Lower middle income\n", "Name: Income Group, dtype: category\n", "Categories (4, object): ['Low income' < 'Lower middle income' < 'Upper middle income' < 'High income']" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# creating a categorical type\n", "cat_type = pd.api.types.CategoricalDtype(categories=[\"Low income\", \n", " \"Lower middle income\", \n", " \"Upper middle income\", \n", " \"High income\"], \n", " ordered=True)\n", "# converting Income Group column to cat_type in a new DataFrame\n", "countries_cat = countries.astype({'Income Group': cat_type})\n", "\n", "display(Markdown(\"**Income Group column in the old table:**\"), \n", " countries['Income Group'].head(3))\n", "display(Markdown(\"**Income Group column in the new table:**\"), \n", " countries_cat['Income Group'].head(3))\n" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 176 }, "executionInfo": { "elapsed": 3389, "status": "ok", "timestamp": 1615829148118, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "K8veGb27bQ1T", "outputId": "39fe6d0d-a2bd-469c-9e34-95cc71f92893" }, "outputs": [ { "data": { "text/markdown": [ "**Minimum and maximum income group in the table with categorical values:** (manually fixed order):" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "'Low income'" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "'High income'" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**Minimum and maximum income group in the table with strings** (alphabetical order):" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "'High income'" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "'Upper middle income'" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(\"**Minimum and maximum income group in the table with categorical values:**\"\n", " \" (manually fixed order):\"))\n", "display(countries_cat['Income Group'].min())\n", "display(countries_cat['Income Group'].max())\n", "\n", "display(Markdown(\"**Minimum and maximum income group in the table with strings**\"\n", " \" (alphabetical order):\"))\n", "display(countries['Income Group'].dropna().min())\n", "display(countries['Income Group'].dropna().max())\n" ] }, { "cell_type": "markdown", "metadata": { "id": "ehCAAh08oOtw" }, "source": [ "* Note that if categories do not need a fixed order, they can be created automatically by the `astype` function as in the code below. \n", "* Notice that `groupby` creates even empty groups which would not happen with strings. This is caused by `observed=False` setting." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 3379, "status": "ok", "timestamp": 1615829148120, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "fXYnAPgjnD9H", "outputId": "e5b81f18-f46f-412c-f744-1b7b4ed40d40" }, "outputs": [ { "data": { "text/plain": [ "Income Group Region \n", "Low income East Asia & Pacific 1\n", " Europe & Central Asia 0\n", " Latin America & Caribbean 0\n", " Middle East & North Africa 2\n", " North America 0\n", " South Asia 1\n", " Sub-Saharan Africa 22\n", "Lower middle income East Asia & Pacific 13\n", " Europe & Central Asia 4\n", " Latin America & Caribbean 4\n", " Middle East & North Africa 8\n", " North America 0\n", " South Asia 6\n", " Sub-Saharan Africa 19\n", "Upper middle income East Asia & Pacific 9\n", " Europe & Central Asia 16\n", " Latin America & Caribbean 19\n", " Middle East & North Africa 3\n", " North America 0\n", " South Asia 1\n", " Sub-Saharan Africa 6\n", "High income East Asia & Pacific 14\n", " Europe & Central Asia 38\n", " Latin America & Caribbean 18\n", " Middle East & North Africa 8\n", " North America 3\n", " South Asia 0\n", " Sub-Saharan Africa 1\n", "dtype: int64" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert region to an unordered category\n", "countries_cat2 = countries_cat.astype({'Region': 'category'})\n", "# count the number of countries for each combination of income group and region\n", "countries_cat2.groupby(['Income Group', 'Region'], observed=False).size()" ] }, { "cell_type": "markdown", "metadata": { "id": "fJFl10croaMr" }, "source": [ "## Dates and times\n", "\n", "An important type of data sets are time series, where some variables are measured repeatedly over time. Pandas has an extensive support [for work with times and dates](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html). Here we show only a small example.\n", "\n", "* We illustrate this on the movie dataset from [Kaggle](https://www.kaggle.com/rounakbanik/the-movies-dataset) (see lecture 04). \n", "* The column labeled `release_date` is recognized as date by passing `parse_dates` parameter to `read_csv`.\n", "* Then we call function [`day_name()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Timestamp.day_name.html) to get the day of week for each release day and use [`value_counts`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.value_counts.html) to see which days are most frequent as movie release dates. \n", "* We also use the release date as the x-coordinate in a scatterplot. " ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 7146, "status": "ok", "timestamp": 1615829151892, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "-lnKOdAYeYFh", "outputId": "7a0cfd65-edff-4c8d-a827-f08d3fbcb83c" }, "outputs": [ { "data": { "text/plain": [ "release_date\n", "Friday 639\n", "Thursday 515\n", "Wednesday 474\n", "Tuesday 175\n", "Saturday 94\n", "Monday 87\n", "Sunday 65\n", "Name: count, dtype: int64" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# import data, including parsing of dates\n", "url = 'https://bbrejova.github.io/viz/data/Movies_small.csv'\n", "movies = pd.read_csv(url, parse_dates=['release_date'])\n", "# get days of week for realse dates\n", "days = movies['release_date'].apply(lambda x : x.day_name())\n", "days.value_counts()" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 291 }, "executionInfo": { "elapsed": 7140, "status": "ok", "timestamp": 1615829151893, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "ZYV4NZQQh7GJ", "outputId": "8bf596e3-4dbd-4470-cadf-99d73536c611" }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# use release date is x-coordinate\n", "sns.scatterplot(data=movies, x='release_date', y='budget')\n", "pass" ] }, { "cell_type": "markdown", "metadata": { "id": "1hNULi15KzNU" }, "source": [ "## Missing values\n", "\n", "Data sets are often incomplete, and Pandas provides techniques for [working with missing data](https://pandas.pydata.org/pandas-docs/stable/user_guide/missing_data.html).\n", "\n", "* Missing data are typically imported as `np.nan` (not-a-number).\n", "* These cannot occur in int-type columns, so ints are converted to floats, but can be handled in a [special way](https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html).\n", "\n", "Bellow we show a small example what happens when working with missing data, including functions [`isna`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.isna.html), [`dropna`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dropna.html), [`fillna`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dropna.html).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 760 }, "executionInfo": { "elapsed": 518, "status": "ok", "timestamp": 1615831412405, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "LozhzxD2jryz", "outputId": "aa912b8b-3467-4bb4-802a-97b29f0621ee" }, "outputs": [ { "data": { "text/markdown": [ "**`a.sum()` skips missing values:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "np.float64(6.0)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a.count()` counts non-missing values:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "np.int64(3)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a.mean()` also considers only non-missing:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "np.float64(2.0)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a > 2` evaluates missing values as `False`, similarly `<`, `==`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0 False\n", "1 False\n", "2 False\n", "3 True\n", "dtype: bool" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a == np.nan` also evaluates as `False`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0 False\n", "1 False\n", "2 False\n", "3 False\n", "dtype: bool" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a.isna()` can be used to detect missing values:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0 False\n", "1 False\n", "2 True\n", "3 False\n", "dtype: bool" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a.dropna()` omits missing values:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0 1.00\n", "1 2.00\n", "3 3.00\n", "dtype: float64" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "**`a.fillna(-1)` replaces them with a specified value:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0 1.00\n", "1 2.00\n", "2 -1.00\n", "3 3.00\n", "dtype: float64" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# create a small Series with one missing value\n", "a = pd.Series([1, 2, np.nan, 3])\n", "display(Markdown(\"**`a.sum()` skips missing values:**\"), \n", " a.sum())\n", "display(Markdown(\"**`a.count()` counts non-missing values:**\"), \n", " a.count())\n", "display(Markdown(\"**`a.mean()` also considers only non-missing:**\"),\n", " a.mean())\n", "display(Markdown(\"**`a > 2` evaluates missing values as `False`, similarly `<`, `==`:**\"),\n", " a > 2)\n", "display(Markdown(\"**`a == np.nan` also evaluates as `False`:**\"),\n", " a == np.nan)\n", "display(Markdown(\"**`a.isna()` can be used to detect missing values:**\"),\n", " a.isna())\n", "display(Markdown(\"**`a.dropna()` omits missing values:**\"),\n", " a.dropna())\n", "display(Markdown(\"**`a.fillna(-1)` replaces them with a specified value:**\"),\n", " a.fillna(-1))" ] }, { "cell_type": "markdown", "metadata": { "id": "7U8a-3t1p2Z5" }, "source": [ "## Pandas efficiency\n", "\n", "Below we show several examples how different ways of implementing the same operation can have very different running time on large data. Pandas functions are usually much faster than manual iteration. However, if you do not work on huge data sets, the difference is not so important.\n", "\n", "To measure time, we use a special Jupyter command [`%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). It runs the code several times to estimate the time per one repeat." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "id": "untgb_rLp8cE" }, "outputs": [], "source": [ "# generate a Series of million random numbers and also convert it to Python list\n", "length = int(1e6)\n", "xs = pd.Series(np.random.uniform(0,100, length))\n", "xl = list(xs)" ] }, { "cell_type": "markdown", "metadata": { "id": "7Rtsncav1a4Q" }, "source": [ "Below we see that method `sum()` on Series is faster than Python built-in `sum` on a Python list, but Python built-in `sum` on Series is much slower, because it iterates over elements of Series. " ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 18118, "status": "ok", "timestamp": 1615829162885, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "Su29-nZp4QOm", "outputId": "7f2c36ea-73d8-4586-adfa-3819f371d445" }, "outputs": [ { "data": { "text/markdown": [ "**Method `sum` on `Series` `xs.sum()`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "450 μs ± 22.2 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" ] }, { "data": { "text/markdown": [ "**Python `sum` on Python list `sum(xl)`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "4.71 ms ± 64.3 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] }, { "data": { "text/markdown": [ "**Python `sum` on Series `sum(xs)`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "40.9 ms ± 874 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "display(Markdown(\"**Method `sum` on `Series` `xs.sum()`:**\"))\n", "%timeit result = xs.sum()\n", "display(Markdown(\"**Python `sum` on Python list `sum(xl)`:**\"))\n", "%timeit result = sum(xl)\n", "display(Markdown(\"**Python `sum` on Series `sum(xs)`:**\"))\n", "%timeit result = sum(xs)" ] }, { "cell_type": "markdown", "metadata": { "id": "uovOLunW7C45" }, "source": [ "Below we compare three ways of generating a sequence of squared values. Multiplying Series with `*` is the fastest, Python list comprehension is much slower and `apply` function from Pandas is even slower." ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 33667, "status": "ok", "timestamp": 1615829178439, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "OMuAjvNEswKo", "outputId": "1dccfaab-36d6-4365-de99-e14e6d82d1fa" }, "outputs": [ { "data": { "text/markdown": [ "**Pandas `Series` multiplication `x2s = xs * xs`**:" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "766 μs ± 102 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" ] }, { "data": { "text/markdown": [ "**Python list comprehension on a list `x2l = [x * x for x in xl]`:**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "38.4 ms ± 3.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] }, { "data": { "text/markdown": [ "**Pandas `apply` function `x2s = xs.apply(lambda x : x * x)`**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "159 ms ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "display(Markdown(\"**Pandas `Series` multiplication `x2s = xs * xs`**:\"))\n", "%timeit x2s = xs * xs\n", "display(Markdown(\"**Python list comprehension on a list `x2l = [x * x for x in xl]`:**\"))\n", "%timeit x2l = [x * x for x in xl]\n", "display(Markdown(\"**Pandas `apply` function `x2s = xs.apply(lambda x : x * x)`**\"))\n", "%timeit x2s = xs.apply(lambda x : x * x)" ] }, { "cell_type": "markdown", "metadata": { "id": "9jJM7IOm7fnL" }, "source": [ "The code below creates the Series of squares by creating a Series filled with zeroes and then assigning individual values using for-loop. This is again much slower than all methods above, so to make the code reasonably fast, we run it on data which is 100 times smaller than above. " ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 9666, "status": "ok", "timestamp": 1615829434685, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "FhgHPxcavvBm", "outputId": "02ff6fd8-cc34-4452-b09c-1f52037bf0bb" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "103 ms ± 1.43 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "length2 = 10000\n", "xs_small = xs.iloc[0:length2]\n", "def assignments(len, x):\n", " x2 = pd.Series([0.0] * len)\n", " for i in range(len): \n", " x2[i] = x[i] * x[i]\n", " return x2\n", "%timeit x2s_small = assignments(length2, xs_small)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "WeZFyCsp8VOB" }, "source": [ "Finally the code below is even worse. It appends individual squares to a Series which starts with size 1. We run it on even smaller list of size 1000." ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 3908, "status": "ok", "timestamp": 1615829713827, "user": { "displayName": "Brona Brejova", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjGyr69ecECqZOZ-_5-o1v7SpP5TdLQGU7-pHl4UQ=s64", "userId": "10789993073610145432" }, "user_tz": -60 }, "id": "2ZBrEYDqkO_S", "outputId": "ebfc575b-f6c3-43ca-8244-6fc865fd4ab2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "169 ms ± 4.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "length3 = 1000\n", "xs_tiny = xs.iloc[0:length3]\n", "def assignments(len, x):\n", " x2 = pd.Series([0.0])\n", " for i in range(len): \n", " x2[i] = x[i] * x[i]\n", " return x2\n", "%timeit x2s_tiny = assignments(length3, xs_tiny)" ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "L05_Pandas_2.ipynb", "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 1 }