{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# First steps in pandas\n", "\n", "*This very short introduction to pandas is mainly based on the excellent [pandas documentation](https://pandas.pydata.org/docs/user_guide/10min.html).*\n", "\n", "To use this tutorial, I recommend the following procedure:\n", "\n", "1. On your machine, create a new folder called `pandas`\n", "1. Download this tutorial as .ipynb (on the top right of this webpage, select the download button) and move it to your `pandas` folder\n", "1. Open Visual Studio Code and select the \"Explorer\" symbol on the top left in the [Activity Bar](https://code.visualstudio.com/docs/getstarted/userinterface)\n", "1. Select \"Open Folder\" and choose your folder `pandas`. This folder is now your project directory\n", "1. In the Explorer, open the file `pandas-intro-short.ipynb`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import pandas\n", "\n", "- To load the pandas package and start working with it, import the package. \n", "- The community agreed alias for pandas is `pd`, so loading pandas as pd is assumed standard practice for all of the pandas documentation:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data creation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- To manually store data in a table, create a DataFrame:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# create the DataFrame and name it my_df\n", "\n", "my_df = pd.DataFrame(\n", " { \n", " 'name': [ \"Tom\", \"Lisa\", \"Peter\"],\n", " 'height': [1.68, 1.93, 1.72],\n", " 'weight': [48.4, 89.8, 84.2],\n", " 'gender': ['male', 'female', 'male'] \n", " }\n", ")" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameheightweightgender
0Tom1.6848.4male
1Lisa1.9389.8female
2Peter1.7284.2male
\n", "
" ], "text/plain": [ " name height weight gender\n", "0 Tom 1.68 48.4 male\n", "1 Lisa 1.93 89.8 female\n", "2 Peter 1.72 84.2 male" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# show my_df\n", "my_df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://pandas.pydata.org/docs/_images/02_io_readwrite.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- pandas supports many different file formats or data sources out of the box (csv, excel, sql, json, parquet, …)\n", "- each of them import data with the prefix `read_*`\n", "- Import data, available as a CSV file in a GitHub repo:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameID%HeightAverage Height ParentsGender
0Stefanie1162161.5female
1Peter2163163.5male
2Stefanie3163163.2female
3Manuela4164165.1female
4Simon5164163.2male
\n", "
" ], "text/plain": [ " Name ID% Height Average Height Parents Gender\n", "0 Stefanie 1 162 161.5 female\n", "1 Peter 2 163 163.5 male\n", "2 Stefanie 3 163 163.2 female\n", "3 Manuela 4 164 165.1 female\n", "4 Simon 5 164 163.2 male" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv(\"https://raw.githubusercontent.com/kirenz/datasets/master/height_unclean.csv\", delimiter=\";\", decimal=\",\")\n", "\n", "# show head\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameID%HeightAverage Height ParentsGender
0Stefanie1162161.5female
1Peter2163163.5male
2Stefanie3163163.2female
3Manuela4164165.1female
4Simon5164163.2male
\n", "
" ], "text/plain": [ " Name ID% Height Average Height Parents Gender\n", "0 Stefanie 1 162 161.5 female\n", "1 Peter 2 163 163.5 male\n", "2 Stefanie 3 163 163.2 female\n", "3 Manuela 4 164 165.1 female\n", "4 Simon 5 164 163.2 male" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same import with different style\n", "\n", "ROOT = \"https://raw.githubusercontent.com/kirenz/datasets/master/\"\n", "DATA = \"height_unclean.csv\"\n", "\n", "df = pd.read_csv(ROOT + DATA, delimiter=\";\", decimal=\",\")\n", "\n", "# show head\n", "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Store data\n", "\n", "- pandas supports many different file formats (csv, excel, sql, json, parquet, …)\n", "- each of them stores data with the prefix `to_*`\n", "- The following code will save data as an Excel file in your current directory (you may need to install [OpenPyXL](https://openpyxl.readthedocs.io/en/stable/) first. \n", "\n", ":::{note}\n", "[Anaconda installation of OpenPyXL](https://anaconda.org/anaconda/openpyxl)):\n", ":::\n", "\n", "- In the example here, the `sheet_name` is named people_height instead of the default Sheet1. By setting `index=False` the row index labels are not saved in the spreadsheet:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "df.to_excel(\"height.xlsx\", sheet_name=\"people_height\", index=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The equivalent read function `read_excel()` would reload the data to a DataFrame:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "# load excel file\n", "df_new = pd.read_excel(\"height.xlsx\", sheet_name=\"people_height\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Viewing data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Overview" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameID%HeightAverage Height ParentsGender
0Stefanie1162161.5female
1Peter2163163.5male
2Stefanie3163163.2female
3Manuela4164165.1female
4Simon5164163.2male
5Sophia6164164.4female
6Ellen7164164.0female
7Emilia8165165.2female
8Lina9165165.2female
9Marie10165165.1female
10Lena11165166.3female
11Mila12165167.4female
12Fin13165165.5male
13Eric14166166.2male
14Pia15166166.1female
15Marc16166166.5male
16Ralph17166166.6male
17Tom18167166.2male
18Steven19167167.3male
19Emanuel20168168.5male
\n", "
" ], "text/plain": [ " Name ID% Height Average Height Parents Gender\n", "0 Stefanie 1 162 161.5 female\n", "1 Peter 2 163 163.5 male\n", "2 Stefanie 3 163 163.2 female\n", "3 Manuela 4 164 165.1 female\n", "4 Simon 5 164 163.2 male\n", "5 Sophia 6 164 164.4 female\n", "6 Ellen 7 164 164.0 female\n", "7 Emilia 8 165 165.2 female\n", "8 Lina 9 165 165.2 female\n", "9 Marie 10 165 165.1 female\n", "10 Lena 11 165 166.3 female\n", "11 Mila 12 165 167.4 female\n", "12 Fin 13 165 165.5 male\n", "13 Eric 14 166 166.2 male\n", "14 Pia 15 166 166.1 female\n", "15 Marc 16 166 166.5 male\n", "16 Ralph 17 166 166.6 male\n", "17 Tom 18 167 166.2 male\n", "18 Steven 19 167 167.3 male\n", "19 Emanuel 20 168 168.5 male" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# show df\n", "df" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameID%HeightAverage Height ParentsGender
0Stefanie1162161.5female
1Peter2163163.5male
\n", "
" ], "text/plain": [ " Name ID% Height Average Height Parents Gender\n", "0 Stefanie 1 162 161.5 female\n", "1 Peter 2 163 163.5 male" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# show first 2 rows\n", "df.head(2)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameID%HeightAverage Height ParentsGender
18Steven19167167.3male
19Emanuel20168168.5male
\n", "
" ], "text/plain": [ " Name ID% Height Average Height Parents Gender\n", "18 Steven 19 167 167.3 male\n", "19 Emanuel 20 168 168.5 male" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# show last 2 rows\n", "df.tail(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The `info()` method prints information about a DataFrame including the index dtype and columns, non-null values and memory usage:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 20 entries, 0 to 19\n", "Data columns (total 5 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 Name 20 non-null object \n", " 1 ID% 20 non-null int64 \n", " 2 Height 20 non-null int64 \n", " 3 Average Height Parents 20 non-null float64\n", " 4 Gender 20 non-null object \n", "dtypes: float64(1), int64(2), object(2)\n", "memory usage: 928.0+ bytes\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Column names" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['Name', 'ID%', 'Height', 'Average Height Parents', ' Gender'], dtype='object')" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Show columns\n", "df.columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data type" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Show data types ([dtypes](https://pandas.pydata.org/docs/user_guide/basics.html#basics-dtypes))." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Name object\n", "ID% int64\n", "Height int64\n", "Average Height Parents float64\n", " Gender object\n", "dtype: object" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dtypes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The data types in this DataFrame are integers (int64), floats (float64) and strings (object)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Index" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RangeIndex(start=0, stop=20, step=1)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Only show index\n", "df.index" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Change column names\n", "\n", "- Usually, we prefer to work with columns that have the following proporties:\n", " - no leading or trailing whitespace (`\"name\"` instead of `\" name \"`, `\" name\"` or `\"name \"`)\n", " - all lowercase (`\"name\"` instead of `\"Name\"`)\n", " - now white spaces (`\"my_name\"` instead of `\"my name\"`)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simple rename" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- First, we rename columns by simply using a mapping\n", "- We rename `\"Name\"` to `\"name\"` and just print the result (we want to display errors and don't save the changes for now):" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameID%HeightAverage Height ParentsGender
0Stefanie1162161.5female
1Peter2163163.5male
2Stefanie3163163.2female
3Manuela4164165.1female
4Simon5164163.2male
5Sophia6164164.4female
6Ellen7164164.0female
7Emilia8165165.2female
8Lina9165165.2female
9Marie10165165.1female
10Lena11165166.3female
11Mila12165167.4female
12Fin13165165.5male
13Eric14166166.2male
14Pia15166166.1female
15Marc16166166.5male
16Ralph17166166.6male
17Tom18167166.2male
18Steven19167167.3male
19Emanuel20168168.5male
\n", "
" ], "text/plain": [ " name ID% Height Average Height Parents Gender\n", "0 Stefanie 1 162 161.5 female\n", "1 Peter 2 163 163.5 male\n", "2 Stefanie 3 163 163.2 female\n", "3 Manuela 4 164 165.1 female\n", "4 Simon 5 164 163.2 male\n", "5 Sophia 6 164 164.4 female\n", "6 Ellen 7 164 164.0 female\n", "7 Emilia 8 165 165.2 female\n", "8 Lina 9 165 165.2 female\n", "9 Marie 10 165 165.1 female\n", "10 Lena 11 165 166.3 female\n", "11 Mila 12 165 167.4 female\n", "12 Fin 13 165 165.5 male\n", "13 Eric 14 166 166.2 male\n", "14 Pia 15 166 166.1 female\n", "15 Marc 16 166 166.5 male\n", "16 Ralph 17 166 166.6 male\n", "17 Tom 18 167 166.2 male\n", "18 Steven 19 167 167.3 male\n", "19 Emanuel 20 168 168.5 male" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.rename(columns={\"Name\": \"name\"}, errors=\"raise\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Let`s rename Gender to gender\n", "- Again, we just want to display the result (without saving it).\n", "- Remove the # and run the following code:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "# df.rename(columns={\"Gender\": \"gender\"}, errors=\"raise\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- This raises an error. Can you spot the problem? (take a look at the end of the error statement)\n", "- The KeyError statement tells us that `\"['Gender'] not found in axis\"`\n", "- This is because variable Gender has a white space at the beginning: `[ Gender]`\n", "- We could fix this problem by typing `\" Gender\"` instead of `\"Gender\"`\n", "- However, there are useful functions (regular expressions) to deal with this kind of problems" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Trailing and leading spaces (with regex)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- We use regular expressions to deal with whitespaces\n", "- To change multiple column names at once, we use the method `.columns.str` \n", "- To replace the spaces, we use `.replace()` with `regex=True`\n", "- In the following function, we search for leading (line start and spaces) and trailing (spaces and line end) spaces and replace them with an empty string:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "# replace r\"this pattern\" with empty string r\"\"\n", "df.columns = df.columns.str.replace(r\"^ +| +$\", r\"\", regex=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Explanation for the regex (see also [Stackoverflow](https://stackoverflow.com/a/67466222)):\n", "\n", "- we start with `r` (for raw) which tells Python to treat all following input as raw text (without interpreting it)\n", "- \"`^`\": is line start\n", "- \"` +`\": (space and plus) is one or more spaces\n", "- \"`|`\": is or\n", "- \"`$`\": is line end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "To learn more about regular expressions (\"regex\"), visit the following sites:\n", "\n", "- [regular expression basics](https://www.w3schools.com/python/python_regex.asp).\n", "- [interactive regular expressions tool](https://regex101.com/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Replace special characters\n", "\n", "- Again, we use regular expressions to deal with special characters (like %, &, $ etc.)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['Name', 'ID', 'Height', 'Average Height Parents', 'Gender'], dtype='object')" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# replace r\"this pattern\" with empty string r\"\"\n", "df.columns = df.columns.str.replace(r\"%\", r\"\", regex=True)\n", "\n", "df.columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lowercase and whitespace\n", "\n", "- We can use two simple methods to convert all columns to lowercase and replace white spaces with underscores (\"_\"):" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['name', 'id', 'height', 'average_height_parents', 'gender'], dtype='object')" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.columns = df.columns.str.lower().str.replace(' ', '_')\n", "\n", "df.columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Change data type\n", "\n", "- There are several methods to [change data types in pandas](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html):\n", "\n", " - `.astype()`: Convert to a specific type (like \"int32\", \"float\" or \"catgeory\")\n", " - `to_datetime`: Convert argument to datetime.\n", " - `to_timedelta`: Convert argument to timedelta.\n", " - `to_numeric`: Convert argument to a numeric type.\n", " - `numpy.ndarray.astype`: Cast a numpy array to a specified type." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Categorical data\n", "\n", "- Categoricals are a pandas data type corresponding to categorical variables in statistics. \n", "\n", "- A categorical variable takes on a limited, and usually fixed, number of possible values (categories). Examples are gender, social class, blood type, country affiliation, observation time or rating via Likert scales.\n", "\n", "- Converting an existing column to a category dtype:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "name object\n", "id int64\n", "height int64\n", "average_height_parents float64\n", "gender category\n", "dtype: object" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"gender\"] = df[\"gender\"].astype(\"category\")\n", "\n", "df.dtypes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### String data\n", "\n", "- In our example, id is not a number (we can't perform calculations with it)\n", "- It is just a unique identifier so we should transform it to a simple string (object)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "name object\n", "id object\n", "height int64\n", "average_height_parents float64\n", "gender category\n", "dtype: object" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['id'] = df['id'].astype(str)\n", "\n", "df.dtypes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add new columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Constant" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumber
0Stefanie1162161.5female42
1Peter2163163.5male42
2Stefanie3163163.2female42
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number\n", "0 Stefanie 1 162 161.5 female 42\n", "1 Peter 2 163 163.5 male 42\n", "2 Stefanie 3 163 163.2 female 42" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# add a constant to all rows\n", "df[\"number\"] = 42\n", "\n", "df.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From existing\n", "\n", " - Create new column from existing columns" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "# calculate height in m (from cm)\n", "df['height_m'] = df.height/100 \n", "\n", "# add some random numbers\n", "df['weight'] = round(np.random.normal(45, 5, 20) * df['height_m'],2)\n", "\n", "# calculate body mass index\n", "df['bmi'] = round(df.weight / (df.height_m * df.height_m),2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Date" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- To add a date, we can use datetime and [strftime](https://strftime.org):" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
0Stefanie1162161.5female421.6257.2521.812023-03-21
1Peter2163163.5male421.6368.8025.892023-03-21
2Stefanie3163163.2female421.6373.0127.482023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m \\\n", "0 Stefanie 1 162 161.5 female 42 1.62 \n", "1 Peter 2 163 163.5 male 42 1.63 \n", "2 Stefanie 3 163 163.2 female 42 1.63 \n", "\n", " weight bmi date \n", "0 57.25 21.81 2023-03-21 \n", "1 68.80 25.89 2023-03-21 \n", "2 73.01 27.48 2023-03-21 " ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# add date\n", "from datetime import datetime\n", "\n", "df[\"date\"] = datetime.today().strftime('%Y-%m-%d')\n", "\n", "df.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary statistics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Numeric data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- [describe()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html#pandas.DataFrame.describe) shows a quick statistic summary of your numerical data.\n", "- We transpose the data (with `.T`) to make it more readable: " ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countmeanstdmin25%50%75%max
height20.0165.00001.486784162.00164.0000165.000166.0000168.00
average_height_parents20.0165.35001.687883161.50164.3000165.350166.3500168.50
number20.042.00000.00000042.0042.000042.00042.000042.00
height_m20.01.65000.0148681.621.64001.6501.66001.68
weight20.073.49007.96261957.2568.845072.56577.627590.51
bmi20.026.97752.76986221.8124.997527.11028.130033.25
\n", "
" ], "text/plain": [ " count mean std min 25% 50% \\\n", "height 20.0 165.0000 1.486784 162.00 164.0000 165.000 \n", "average_height_parents 20.0 165.3500 1.687883 161.50 164.3000 165.350 \n", "number 20.0 42.0000 0.000000 42.00 42.0000 42.000 \n", "height_m 20.0 1.6500 0.014868 1.62 1.6400 1.650 \n", "weight 20.0 73.4900 7.962619 57.25 68.8450 72.565 \n", "bmi 20.0 26.9775 2.769862 21.81 24.9975 27.110 \n", "\n", " 75% max \n", "height 166.0000 168.00 \n", "average_height_parents 166.3500 168.50 \n", "number 42.0000 42.00 \n", "height_m 1.6600 1.68 \n", "weight 77.6275 90.51 \n", "bmi 28.1300 33.25 " ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.describe().T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Obtain summary statistics for different groups (categorical data)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
genderfemalemale
heightcount11.0000009.000000
mean164.363636165.777778
std1.1200651.563472
min162.000000163.000000
25%164.000000165.000000
50%165.000000166.000000
75%165.000000167.000000
max166.000000168.000000
average_height_parentscount11.0000009.000000
mean164.863636165.944444
std1.5939091.693451
min161.500000163.200000
25%164.200000165.500000
50%165.100000166.200000
75%165.650000166.600000
max167.400000168.500000
numbercount11.0000009.000000
mean42.00000042.000000
std0.0000000.000000
min42.00000042.000000
25%42.00000042.000000
50%42.00000042.000000
75%42.00000042.000000
max42.00000042.000000
height_mcount11.0000009.000000
mean1.6436361.657778
std0.0112010.015635
min1.6200001.630000
25%1.6400001.650000
50%1.6500001.660000
75%1.6500001.670000
max1.6600001.680000
weightcount11.0000009.000000
mean72.73909174.407778
std8.9295067.013547
min57.25000066.870000
25%69.68500068.860000
50%73.01000071.740000
75%75.55000078.490000
max90.51000088.350000
bmicount11.0000009.000000
mean26.90090927.071111
std3.0988502.489942
min21.81000024.560000
25%25.59500025.000000
50%27.41000025.890000
75%27.91500028.760000
max33.25000032.060000
\n", "
" ], "text/plain": [ "gender female male\n", "height count 11.000000 9.000000\n", " mean 164.363636 165.777778\n", " std 1.120065 1.563472\n", " min 162.000000 163.000000\n", " 25% 164.000000 165.000000\n", " 50% 165.000000 166.000000\n", " 75% 165.000000 167.000000\n", " max 166.000000 168.000000\n", "average_height_parents count 11.000000 9.000000\n", " mean 164.863636 165.944444\n", " std 1.593909 1.693451\n", " min 161.500000 163.200000\n", " 25% 164.200000 165.500000\n", " 50% 165.100000 166.200000\n", " 75% 165.650000 166.600000\n", " max 167.400000 168.500000\n", "number count 11.000000 9.000000\n", " mean 42.000000 42.000000\n", " std 0.000000 0.000000\n", " min 42.000000 42.000000\n", " 25% 42.000000 42.000000\n", " 50% 42.000000 42.000000\n", " 75% 42.000000 42.000000\n", " max 42.000000 42.000000\n", "height_m count 11.000000 9.000000\n", " mean 1.643636 1.657778\n", " std 0.011201 0.015635\n", " min 1.620000 1.630000\n", " 25% 1.640000 1.650000\n", " 50% 1.650000 1.660000\n", " 75% 1.650000 1.670000\n", " max 1.660000 1.680000\n", "weight count 11.000000 9.000000\n", " mean 72.739091 74.407778\n", " std 8.929506 7.013547\n", " min 57.250000 66.870000\n", " 25% 69.685000 68.860000\n", " 50% 73.010000 71.740000\n", " 75% 75.550000 78.490000\n", " max 90.510000 88.350000\n", "bmi count 11.000000 9.000000\n", " mean 26.900909 27.071111\n", " std 3.098850 2.489942\n", " min 21.810000 24.560000\n", " 25% 25.595000 25.000000\n", " 50% 27.410000 25.890000\n", " 75% 27.915000 28.760000\n", " max 33.250000 32.060000" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.groupby(['gender']).describe().T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Categorical data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- we can also use `describe()` for categorical data" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countuniquetopfreq
gender202female11
\n", "
" ], "text/plain": [ " count unique top freq\n", "gender 20 2 female 11" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.describe(include=\"category\").T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Show unique levels and count with `value_counts()`" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "female 11\n", "male 9\n", "Name: gender, dtype: int64" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['gender'].value_counts()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Loop over list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Example of for loop to obtain statistics for specific numerical columns" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "# make a list of numerical columns\n", "list_num = ['height', 'weight']" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Median of height equals 165.0 \n", "\n", "Median of weight equals 72.565 \n", "\n" ] } ], "source": [ "# calculate median for our list\n", "for i in list_num:\n", " print(f'Median of {i} equals {df[i].median()} \\n')" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Column: height \n", " count 20.000000\n", "mean 165.000000\n", "std 1.486784\n", "min 162.000000\n", "25% 164.000000\n", "50% 165.000000\n", "75% 166.000000\n", "max 168.000000\n", "Name: height, dtype: float64 \n", "\n", "Column: weight \n", " count 20.000000\n", "mean 73.490000\n", "std 7.962619\n", "min 57.250000\n", "25% 68.845000\n", "50% 72.565000\n", "75% 77.627500\n", "max 90.510000\n", "Name: weight, dtype: float64 \n", "\n" ] } ], "source": [ "# calculate summary statistics for our list\n", "for i in list_num:\n", " print(f'Column: {i} \\n {df[i].describe().T} \\n')" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHFCAYAAAAUpjivAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA7jUlEQVR4nO3dfVxUZf7/8fdwNyDgeIM3oAhqiViKutqaSwq5qViIWJtpGS7WdmcWlia55s3WYlaWv7WNbbek2tzucTMDLRXNsLJCuzMN0rCyKE0RFVS4fn/4ZbYJJERwhuPr+XjM48G5zjnX+VyDw7w95zozNmOMEQAAgEV5ubsAAACApkTYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYARpJVlaWbDaby6Ndu3aKi4vTa6+95u7ynCIjIzVp0qRT3u/w4cOaO3eu8vLy6r1PQUGBhg4dKofDIZvNpkceeeSUj+uJXn/9dc2dO/eU97PZbA3a72R9TZkypVH6kqRdu3bJZrMpKyurSevJz8/X3LlztX///gYdB2gIwg7QyJYuXapNmzYpPz9fjz/+uLy9vZWYmKgVK1a4u7TTcvjwYc2bN++Uwk5qaqr27Nmj5557Tps2bdJVV13VdAWeQa+//rrmzZt3yvtt2rRJ1113XRNUdPpCQ0O1adMmXXrppU16nPz8fM2bN4+wgzPKx90FAFZz/vnna8CAAc7lkSNHqnXr1vrPf/6jxMREN1Z25n3yySe6/vrrlZCQ0Cj9HTt2TDabTT4+zedPlzFG5eXlCggI0KBBg9xdzknZ7XaPrg84HZzZAZqYv7+//Pz85Ovr69K+b98+3XzzzerUqZP8/PzUrVs3zZo1SxUVFZKk8vJy9evXT+ecc44OHDjg3O+7775Tx44dFRcXp8rKSknSpEmTFBQUpE8//VTDhg1TYGCg2rVrpylTpujw4cO/WmNxcbGuueYatW/fXna7XdHR0XrooYdUVVUl6cQljnbt2kmS5s2b57xMd7LLYdWX9I4fP67HHnvMuX21Tz75RElJSWrdurX8/f3Vt29fPfXUUy595OXlyWaz6ZlnntEdd9yhTp06yW63q7CwsNZjVl+GeeCBB3T//fcrMjJSAQEBiouL044dO3Ts2DHNnDlTYWFhcjgcSk5OVklJSY1+nn/+eV144YUKDAxUUFCQRowYoYKCAuf6SZMm6dFHH5Ukl0uWu3btcrZNmTJFmZmZio6Olt1ud46ttstY33zzjf70pz8pPDxcfn5+CgsL0xVXXKHvv//+JL8tV88884yio6PVokULxcTE1HrJ9IsvvtCECRNcfr/VY/jl8/fLy1j//e9/1adPH9ntdnXr1k2LFy/W3LlzXX6f9a1n7ty5mj59uiSpa9euzufuVM4WAg1iADSKpUuXGknmnXfeMceOHTNHjx41u3fvNlOnTjVeXl4mNzfXue2RI0dMnz59TGBgoHnwwQfN6tWrzezZs42Pj48ZNWqUc7sdO3aY4OBgM3bsWGOMMZWVlebiiy827du3N99++61zu5SUFOPn52e6dOli7rvvPrN69Wozd+5c4+PjYy677DKXOiMiIkxKSopzuaSkxHTq1Mm0a9fOZGZmmtzcXDNlyhQjydx0003GGGPKy8tNbm6ukWQmT55sNm3aZDZt2mQKCwtrfS5KSkrMpk2bjCRzxRVXOLc3xpjPP//cBAcHm+7du5unn37arFy50owfP95IMvfff7+zj3Xr1hlJplOnTuaKK64wr776qnnttdfM3r17az3mzp07jSQTERFhEhMTzWuvvWb+/e9/mw4dOpgePXqYiRMnmtTUVJOTk2MyMzNNUFCQSUxMdOnjvvvuMzabzaSmpprXXnvNvPLKK+bCCy80gYGB5tNPPzXGGFNYWGiuuOIKI8k5rk2bNpny8nJjjHHW3KdPH7Ns2TKzdu1a88knnzjXzZkzx3m8r7/+2oSGhpqQkBCzaNEi8+abb5rnn3/epKammm3bttU6zmqSTGRkpLngggvMCy+8YF5//XUTFxdnfHx8TFFRkXO7Tz/91DgcDtO7d2/z9NNPm9WrV5s77rjDeHl5mblz59Z4/pYuXepsy8nJMV5eXiYuLs5kZ2ebF1980fz2t781kZGR5pdvH/WpZ/fu3ebWW281kswrr7zifO4OHDhQ51iB00XYARpJddj55cNut5u///3vLttmZmYaSeaFF15wab///vuNJLN69Wpn2/PPP28kmUceecTcc889xsvLy2W9MSfCjiSzePFil/b77rvPSDIbN250tv0y7MycOdNIMu+++67LvjfddJOx2Wxm+/btxhhjfvjhhxpv1r9Gkrnllltc2q666ipjt9tNcXGxS3tCQoJp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XxMWFmauvPJK8/3339c53pMdp7bf786dO01qaqrp1KmT8fX1Ne3atTODBw829957r8s2+sXdWMYYk52dbXr37u38aIMFCxaYqVOnmtatWze4nvT0dBMWFma8vLyMJLNu3bo6xwqcLpsxxpzxhAWgUU2aNEkvvfSSysrK3F0KLO7YsWPq27evOnXqpNWrV7u7HKBeuIwFADipyZMn65JLLlFoaKi+++47ZWZmatu2bVq8eLG7SwPqjbADADipgwcP6s4779QPP/wgX19f9e/fX6+//rpzXhnQHHAZCwAAWBq3ngMAAEsj7AAAAEsj7AAAAEtjgrKkqqoqffvttwoODj5jH00PAABOjzFGBw8eVFhYWJ3fX0fY0Ynv5PnlNzADAIDmYffu3XV+qS5hR3J+TPnu3bvVsmVLN1cDAADqo7S0VOHh4b/6dSOEHf3vG4pbtmxJ2AEAoJn5tSkoTFAGAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACW5taws2HDBiUmJiosLEw2m03Lly+vsc22bds0evRoORwOBQcHa9CgQSouLnau/+677zRx4kR17NhRgYGB6t+/v1566aUzOAoAAODJ3Bp2Dh06pJiYGC1ZsqTW9UVFRYqNjVXPnj2Vl5enrVu3avbs2fL393duM3HiRG3fvl2vvvqqPv74Y40dO1bjxo1TQUHBmRoGAADwYDZjjHF3EdKJL/HKzs7WmDFjnG1XXXWVfH199cwzz5x0v6CgID322GOaOHGis61t27ZauHChJk+eXK9jl5aWyuFw6MCBA3wRKICzjjFG5eXl7i7jtBljVFFRIUmy2+2/+uWQzYG/v78lxtFU6vv+7bHfel5VVaWVK1dqxowZGjFihAoKCtS1a1elp6e7BKLY2Fg9//zzuvTSS9WqVSu98MILqqioUFxc3En7rqiocL4gpBNPFgCcrcrLy5WQkODuMlCLnJwcBQQEuLuMZs9jJyiXlJSorKxMCxYs0MiRI7V69WolJydr7NixWr9+vXO7559/XsePH1fbtm1lt9t1ww03KDs7W927dz9p3xkZGXI4HM5HeHj4mRgSAABwA48+syNJSUlJSktLkyT17dtX+fn5yszM1NChQyVJf/7zn/XTTz/pzTffVEhIiJYvX64//OEPeuut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rVu3avbs2fL393dus2nTJo0cOVLDhw/Xe++9p82bN2vKlCny8uKkFQAAkHzcefCEhAQlJCScdP2sWbM0atQoLVy40NnWrVs3l23S0tI0depUzZw509l27rnnNn6xZzljjMrLy91dxmkzxqiiokKSZLfbZbPZ3FzR6fP397fEOJorY4zz54pKNxYCeJCfvxZ+/hpxF7eGnbpUVVVp5cqVmjFjhkaMGKGCggJ17dpV6enpGjNmjCSppKRE7777rq6++moNHjxYRUVF6tmzp+677z7FxsaetO+KigrnG54klZaWNvVwmr3y8vI6gyncJycnRwEBAe4u46z1878lUza2dWMlgGeqqKhQixYt3FqDx17rKSkpUVlZmRYsWKCRI0dq9erVSk5O1tixY7V+/XpJ0pdffilJmjt3rq6//nrl5uaqf//+GjZsmL744ouT9p2RkSGHw+F8hIeHn5ExAQCAM8+jz+xIUlJSktLS0iRJffv2VX5+vjIzMzV06FDnNjfccIP++Mc/SpL69eunNWvW6Mknn1RGRkatfaenp2vatGnO5dLSUgLPr/D391dOTo67yzht5eXlSk5OliRlZ2e7zP9qrqwwhubMbrc7f14Su1d2bzcWA3iIisr/nen8+WvEXTw27ISEhMjHx0e9evVyaY+OjtbGjRslSaGhoZJU6za/vGPr5+x2u0c8+c2JzWaz3KUSf39/y40JZ97P50vZvUXYAX7BE+YUeuxlLD8/Pw0cOFDbt293ad+xY4ciIiIkSZGRkQoLC6tzGwAAcHZz65mdsrIyFRYWOpd37typLVu2qE2bNurSpYumT5+ucePGaciQIYqPj1dubq5WrFihvLw8SSfS4vTp0zVnzhzFxMSob9++euqpp/T555/rpZdectOoAACAJ3Fr2Hn//fcVHx/vXK6eR5OSkqKsrCwlJycrMzNTGRkZmjp1qqKiovTyyy+73Gl1++23q7y8XGlpadq3b59iYmL0xhtvqHv37md8PAAAwPO4NezExcX96v33qampSk1NrXObmTNnunzODgAAQDWPnbMDAADQGAg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0gg7AADA0hoUdrp166a9e/fWaN+/f7+6det22kUBAAA0lgaFnV27dqmysrJGe0VFhb755pvTLgoAAKCx+JzKxq+++qrz51WrVsnhcDiXKysrtWbNGkVGRjZacQAAAKfrlMLOmDFjJEk2m00pKSku63x9fRUZGamHHnqo0YoDAAA4XacUdqqqqiRJXbt21ebNmxUSEtIkRQEAADSWUwo71Xbu3NnYdQAAADSJBoUdSVqzZo3WrFmjkpIS5xmfak8++eRpFwYAANAYGhR25s2bp/nz52vAgAEKDQ2VzWZr7LoAAAAaRYPCTmZmprKysjRx4sTGrgcAAKBRNehzdo4eParBgwc3di0AAACNrkFh57rrrtOyZcsauxYAAIBGV+/LWNOmTXP+XFVVpccff1xvvvmm+vTpI19fX5dtFy1a1HgVAgAAnIZ6h52CggKX5b59+0qSPvnkE5d2JisDAABPUu+ws27duqasAwAAoEk0aM4OAABAc9GgW8+Tk5NrvVxls9nk7++vc845RxMmTFBUVFSd/WzYsEEPPPCAPvjgA+3Zs0fZ2dnO79+qtm3bNt11111av369qqqqdN555+mFF15Qly5dJElxcXFav369yz7jxo3Tc88915ChAQAAi2nQmR2Hw6G1a9fqww8/dIaegoICrV27VsePH9fzzz+vmJgYvf3223X2c+jQIcXExGjJkiW1ri8qKlJsbKx69uypvLw8bd26VbNnz5a/v7/Ldtdff7327NnjfPzjH/9oyLAAAIAFNejMTseOHTVhwgQtWbJEXl4n8lJVVZVuu+02BQcH67nnntONN96ou+66Sxs3bjxpPwkJCUpISDjp+lmzZmnUqFFauHChs61bt241tmvRooU6duzYkKGcEVVVVTpw4IC7y4Ck8vJy58/79+93WYb7OBwO59+S5qyi0ibJuLuMs5Yx0tH/+/YiPy+J+2Xc58RrwXPYjDGn/Mps166d3n77bfXo0cOlfceOHRo8eLB+/PFHffzxx7rooou0f//++hVis7lcxqqqqpLD4dCMGTO0ceNGFRQUqGvXrkpPT3e51BUXF6dPP/1Uxhh16NBBCQkJmjNnjoKDg096rIqKClVUVDiXS0tLFR4ergMHDqhly5b1fh7q66efflJycnKj9wtYRXZ2tlq3bu3uMhrkyJEjdf6nDTjb5eTkKCAgoEn6Li0tlcPh+NX37wb9V+r48eP6/PPPa7R//vnnqqyslCT5+/uf1m3oJSUlKisr04IFCzRy5EitXr1aycnJGjt2rMscnauvvlr/+c9/lJeXp9mzZ+vll1/W2LFj6+w7IyNDDofD+QgPD29wnQAAwLM16DLWxIkTNXnyZN19990aOHCgbDab3nvvPf31r3/VtddeK0lav369zjvvvAYXVv1N6klJSUpLS5N04rN98vPzlZmZqaFDh0o6MV+n2vnnn69zzz1XAwYM0Icffqj+/fvX2nd6errLhyRWn9lpKna73flzWe8/yHh5N9mx8CuMpKrjJ3728pE860zrWcVWVamgj1+U5PoaaW78/f2Vk5Pj7jKgE5epq8+iZ2dn15jfCffwhN9Dg8LOww8/rA4dOmjhwoX6/vvvJUkdOnRQWlqa7rrrLknS8OHDNXLkyAYXFhISIh8fH/Xq1culPTo6us55QP3795evr6+++OKLk4Ydu91+Rv+4/vwMl/H1l7x969gaODuYymPOn5vzh5HabLYmO0WPhvP39+f3AqcGhR1vb2/NmjVLs2bNUmlpqSTVuFZWfWt4Q/n5+WngwIHavn27S/uOHTsUERFx0v0+/fRTHTt2TKGhoad1fAAAYA0NCjs/dzoTesvKylRYWOhc3rlzp7Zs2aI2bdqoS5cumj59usaNG6chQ4YoPj5eubm5WrFihfLy8iSduDX92Wef1ahRoxQSEqLPPvtMd9xxh/r166ff/e53pzs0AABgAfUOO/3799eaNWvUunVr9evXr87Tzh9++GG9+nz//fcVHx/vXK6eR5OSkqKsrCwlJycrMzNTGRkZmjp1qqKiovTyyy8rNjZW0omzP2vWrNHixYtVVlam8PBwXXrppZozZ468vZkXAwAATiHsJCUlOee5/PJTjhsqLi5Ov3bne2pqqlJTU2tdFx4eXuPTkwEAAH6u3mFnzpw5tf4MAADgyRr8kaX79+/Xv/71L6Wnp2vfvn2STly++uabbxqtOAAAgNPVoAnKH330kX7/+9/L4XBo165duv7669WmTRtlZ2frq6++0tNPP93YdQIAADRIg87sTJs2TZMmTdIXX3zh8mFBCQkJ2rBhQ6MVBwAAcLoaFHY2b96sG264oUZ7p06d9N133512UQAAAI2lQWHH39/f+WGCP7d9+3a1a9futIsCAABoLA0KO0lJSZo/f76OHTvxce82m03FxcWaOXOmLr/88kYtEAAA4HQ0KOw8+OCD+uGHH9S+fXsdOXJEQ4cO1TnnnKOgoCDdd999jV0jAABAgzXobqyWLVtq48aNWrdunT744ANVVVWpf//++v3vf9/Y9QEAAJyWBn831po1a7RmzRqVlJSoqqpKn3/+uZYtWyZJevLJJxutQAAAgNPRoLAzb948zZ8/XwMGDFBoaGid35MFAADgTg0KO5mZmcrKytLEiRMbux4AAIBG1aAJykePHtXgwYMbuxYAAIBG16Cwc9111znn5wAAAHiyel/GmjZtmvPnqqoqPf7443rzzTfVp08f+fr6umy7aNGixqsQAADgNNQ77BQUFLgs9+3bV5L0ySefuLQzWRkAAHiSeoeddevWNWUdAAAATaJBc3YAAACaC8IOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNMIOAACwNLeGnQ0bNigxMVFhYWGy2Wxavnx5jW22bdum0aNHy+FwKDg4WIMGDVJxcXGN7YwxSkhIOGk/AADg7OTWsHPo0CHFxMRoyZIlta4vKipSbGysevbsqby8PG3dulWzZ8+Wv79/jW0feeQR2Wy2pi4ZAAA0Mz7uPHhCQoISEhJOun7WrFkaNWqUFi5c6Gzr1q1bje22bt2qRYsWafPmzQoNDW2SWhuLreq4jLuLOJsZI1UdP/Gzl49EQHYbW/XvAQCamFvDTl2qqqq0cuVKzZgxQyNGjFBBQYG6du2q9PR0jRkzxrnd4cOHNX78eC1ZskQdO3asV98VFRWqqKhwLpeWljZ2+ScVtOU/Z+xYAADAgycol5SUqKysTAsWLNDIkSO1evVqJScna+zYsVq/fr1zu7S0NA0ePFhJSUn17jsjI0MOh8P5CA8Pb4ohAAAAD+DRZ3YkKSkpSWlpaZKkvn37Kj8/X5mZmRo6dKheffVVrV27VgUFBafUd3p6uqZNm+ZcLi0tbdLA4+/vr5ycnCbrH/VXXl6u5ORkSVJ2dnat879w5vF7ANCUPDbshISEyMfHR7169XJpj46O1saNGyVJa9euVVFRkVq1auWyzeWXX66LLrpIeXl5tfZtt9tlt9ubouxa2Ww2BQQEnLHjoX78/f35vQDAWcBjw46fn58GDhyo7du3u7Tv2LFDERERkqSZM2fquuuuc1nfu3dvPfzww0pMTDxjtQIAAM/l1rBTVlamwsJC5/LOnTu1ZcsWtWnTRl26dNH06dM1btw4DRkyRPHx8crNzdWKFSucZ2w6duxY66TkLl26qGvXrmdqGAAAwIO5Ney8//77io+Pdy5Xz6NJSUlRVlaWkpOTlZmZqYyMDE2dOlVRUVF6+eWXFRsb666SAQBAM+PWsBMXFydj6v7UmdTUVKWmpta7z1/rDwAAnF089tZzAACAxkDYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlubWsLNhwwYlJiYqLCxMNptNy5cvr7HNtm3bNHr0aDkcDgUHB2vQoEEqLi52rr/hhhvUvXt3BQQEqF27dkpKStLnn39+BkcBAAA8mVvDzqFDhxQTE6MlS5bUur6oqEixsbHq2bOn8vLytHXrVs2ePVv+/v7ObX7zm99o6dKl2rZtm1atWiVjjIYPH67KysozNQwAAODBfNx58ISEBCUkJJx0/axZszRq1CgtXLjQ2datWzeXbf70pz85f46MjNS9996rmJgY7dq1S927d2/8os9SxhiVl5e7u4zT9vMxWGE8kuTv7y+bzebuMtCM8fr2XLy+G4dbw05dqqqqtHLlSs2YMUMjRoxQQUGBunbtqvT0dI0ZM6bWfQ4dOqSlS5eqa9euCg8PP2nfFRUVqqiocC6XlpY2dvmWU15eXmcwbY6Sk5PdXUKjyMnJUUBAgLvLQDPG69tz8fpuHB47QbmkpERlZWVasGCBRo4cqdWrVys5OVljx47V+vXrXbb9+9//rqCgIAUFBSk3N1dvvPGG/Pz8Ttp3RkaGHA6H81FXMAIAAM2bzRhj3F2EJNlsNmVnZzvP2nz77bfq1KmTxo8fr2XLljm3Gz16tAIDA/Wf//zH2XbgwAGVlJRoz549evDBB/XNN9/o7bffdpnb83O1ndkJDw/XgQMH1LJly6YZYDNnldPcxhjn795ut1vi9DCnuXG6eH17Ll7fdSstLZXD4fjV92+PvYwVEhIiHx8f9erVy6U9OjpaGzdudGmrPkNz7rnnatCgQWrdurWys7M1fvz4Wvu22+2y2+1NVrsV2Ww2y5xKbdGihbtLADwKr29YncdexvLz89PAgQO1fft2l/YdO3YoIiKizn1/nu4BAMDZza1ndsrKylRYWOhc3rlzp7Zs2aI2bdqoS5cumj59usaNG6chQ4YoPj5eubm5WrFihfLy8iRJX375pZ5//nkNHz5c7dq10zfffKP7779fAQEBGjVqlJtGBQAAPIlb5+zk5eUpPj6+RntKSoqysrIkSU8++aQyMjL09ddfKyoqSvPmzVNSUpKkE/N6rrvuOn3wwQf66aef1KFDBw0ZMkT33HOPoqKi6l1Hfa/5AQAAz1Hf92+PmaDsToQdAACan/q+f3vsnB0AAIDGQNgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtgBAACWRtjBWSc/P1/jxo1Tfn6+u0sBAJwBbg07GzZsUGJiosLCwmSz2bR8+fIa22zbtk2jR4+Ww+FQcHCwBg0apOLiYknSvn37dOuttyoqKkotWrRQly5dNHXqVB04cOAMjwTNRXl5uRYtWqTvv/9eixYtUnl5ubtLAgA0MbeGnUOHDikmJkZLliypdX1RUZFiY2PVs2dP5eXlaevWrZo9e7b8/f0lSd9++62+/fZbPfjgg/r444+VlZWl3NxcTZ48+UwOA83Is88+q71790qS9u7dq2XLlrm5IgBAU7MZY4y7i5Akm82m7OxsjRkzxtl21VVXydfXV88880y9+3nxxRd1zTXX6NChQ/Lx8anXPqWlpXI4HDpw4IBatmx5qqWjmfj666+VkpKiyspKZ5uPj4+ysrLUuXNnN1YGAGiI+r5/e+ycnaqqKq1cuVI9evTQiBEj1L59e/32t7+t9VLXz1UPuK6gU1FRodLSUpcHrM0Yo8WLF5+03UMyPwCgCXhs2CkpKVFZWZkWLFigkSNHavXq1UpOTtbYsWO1fv36WvfZu3ev/vKXv+iGG26os++MjAw5HA7nIzw8vCmGAA9SXFyszZs3u5zVkaTKykpt3rzZOQ8MAGA9Hht2qqqqJElJSUlKS0tT3759NXPmTF122WXKzMyssX1paakuvfRS9erVS3PmzKmz7/T0dB04cMD52L17d5OMAZ6jS5cuGjhwoLy9vV3avb29dcEFF6hLly5uqgwA0NQ8NuyEhITIx8dHvXr1cmmPjo6u8b/wgwcPauTIkQoKClJ2drZ8fX3r7Ntut6tly5YuD1ibzWbTbbfddtJ2m83mhqoAAGeCx4YdPz8/DRw4UNu3b3dp37FjhyIiIpzLpaWlGj58uPz8/PTqq68679QCfqlz586aMGGCM9jYbDZNmDBBnTp1cnNlAICmVL/blZpIWVmZCgsLncs7d+7Uli1b1KZNG3Xp0kXTp0/XuHHjNGTIEMXHxys3N1crVqxQXl6epBNndIYPH67Dhw/r3//+t8tk43bt2tW4ZAFcffXVysnJ0Y8//qiQkBBNmDDB3SUBAJqYW289z8vLU3x8fI32lJQUZWVlSZKefPJJZWRk6Ouvv1ZUVJTmzZunpKSkOveXTgSnyMjIetXBrednl/z8fC1evFi33XabBg8e7O5yAAANVN/3b4/5nB13IuwAAND8NPvP2QEAAGgMhB0AAGBphB0AAGBphB0AAGBphB0AAGBphB0AAGBphB0AAGBphB0AAGBphB0AAGBpbv1uLE9R/SHS1d+rBQAAPF/1+/avfRkEYUcnvlBUksLDw91cCQAAOFUHDx6Uw+E46Xq+G0tSVVWVvv32WwUHB8tms7m7HDSx0tJShYeHa/fu3XwXGmAxvL7PLsYYHTx4UGFhYfLyOvnMHM7sSPLy8lLnzp3dXQbOsJYtW/LHELAoXt9nj7rO6FRjgjIAALA0wg4AALA0wg7OOna7XXPmzJHdbnd3KQAaGa9v1IYJygAAwNI4swMAACyNsAMAACyNsAMAACyNsAOPZYzRn/70J7Vp00Y2m01btmxxSx27du1y6/EBnL5JkyZpzJgx7i4DbsKHCsJj5ebmKisrS3l5eerWrZtCQkLcXRIAoBki7MBjFRUVKTQ0VIMHD3Z3KQCAZozLWPBIkyZN0q233qri4mLZbDZFRkbKGKOFCxeqW7duCggIUExMjF566SXnPnl5ebLZbFq1apX69eungIAAXXzxxSopKVFOTo6io6PVsmVLjR8/XocPH3bul5ubq9jYWLVq1Upt27bVZZddpqKiojrr++yzzzRq1CgFBQWpQ4cOmjhxon788ccmez6As0lcXJxuvfVW3X777WrdurU6dOigxx9/XIcOHdIf//hHBQcHq3v37srJyZEkVVZWavLkyeratasCAgIUFRWlxYsX13mMX/t7Amsh7MAjLV68WPPnz1fnzp21Z88ebd68WX/+85+1dOlSPfbYY/r000+Vlpama665RuvXr3fZd+7cuVqyZIny8/O1e/duXXnllXrkkUe0bNkyrVy5Um+88Yb+9re/Obc/dOiQpk2bps2bN2vNmjXy8vJScnKyqqqqaq1tz549Gjp0qPr27av3339fubm5+v7773XllVc26XMCnE2eeuophYSE6L333tOtt96qm266SX/4wx80ePBgffjhhxoxYoQmTpyow4cPq6qqSp07d9YLL7ygzz77TPfcc4/uvvtuvfDCCyftv75/T2ARBvBQDz/8sImIiDDGGFNWVmb8/f1Nfn6+yzaTJ08248ePN8YYs27dOiPJvPnmm871GRkZRpIpKipytt1www1mxIgRJz1uSUmJkWQ+/vhjY4wxO3fuNJJMQUGBMcaY2bNnm+HDh7vss3v3biPJbN++vcHjBXDC0KFDTWxsrHP5+PHjJjAw0EycONHZtmfPHiPJbNq0qdY+br75ZnP55Zc7l1NSUkxSUpIxpn5/T2AtzNlBs/DZZ5+pvLxcl1xyiUv70aNH1a9fP5e2Pn36OH/u0KGDWrRooW7durm0vffee87loqIizZ49W++8845+/PFH5xmd4uJinX/++TVq+eCDD7Ru3ToFBQXVWFdUVKQePXo0bJAAnH7+Ovb29lbbtm3Vu3dvZ1uHDh0kSSUlJZKkzMxM/etf/9JXX32lI0eO6OjRo+rbt2+tfZ/K3xNYA2EHzUJ1AFm5cqU6derksu6X34Hj6+vr/Nlms7ksV7f9/BJVYmKiwsPD9c9//lNhYWGqqqrS+eefr6NHj560lsTERN1///011oWGhp7awADUqrbX7S9f29KJ1+MLL7ygtLQ0PfTQQ7rwwgsVHBysBx54QO+++26tfZ/K3xNYA2EHzUKvXr1kt9tVXFysoUOHNlq/e/fu1bZt2/SPf/xDF110kSRp48aNde7Tv39/vfzyy4qMjJSPDy8hwN3eeustDR48WDfffLOzra6bDJrq7wk8F3+p0SwEBwfrzjvvVFpamqqqqhQbG6vS0lLl5+crKChIKSkpDeq3devWatu2rR5//HGFhoaquLhYM2fOrHOfW265Rf/85z81fvx4TZ8+XSEhISosLNRzzz2nf/7zn/L29m5QLQAa5pxzztHTTz+tVatWqWvXrnrmmWe0efNmde3atdbtm+rvCTwXYQfNxl/+8he1b99eGRkZ+vLLL9WqVSv1799fd999d4P79PLy0nPPPaepU6fq/PPPV1RUlP7f//t/iouLO+k+YWFhevvtt3XXXXdpxIgRqqioUEREhEaOHCkvL25wBM60G2+8UVu2bNG4ceNks9k0fvx43Xzzzc5b02vTFH9P4Llsxhjj7iIAAACaCv8NBQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAQAAlkbYAXBWmzRpksaMGePuMgA0IcIOAACwNMIOAJwGY4yOHz/u7jIA1IGwA8AjHDx4UFdffbUCAwMVGhqqhx9+WHFxcbr99tslSUePHtWMGTPUqVMnBQYG6re//a3y8vKc+2dlZalVq1ZatWqVoqOjFRQUpJEjR2rPnj3ObSorKzVt2jS1atVKbdu21YwZM/TLb8wxxmjhwoXq1q2bAgICFBMTo5deesm5Pi8vTzabTatWrdKAAQNkt9v11ltvNelzA+D0EHYAeIRp06bp7bff1quvvqo33nhDb731lj788EPn+j/+8Y96++239dxzz+mjjz7SH/7wB40cOVJffPGFc5vDhw/rwQcf1DPPPKMNGzaouLhYd955p3P9Qw89pCeffFJPPPGENm7cqH379ik7O9uljj//+c9aunSpHnvsMX366adKS0vTNddco/Xr17tsN2PGDGVkZGjbtm3q06dPEz0rABqFAQA3Ky0tNb6+vubFF190tu3fv9+0aNHC3HbbbaawsNDYbDbzzTffuOw3bNgwk56ebowxZunSpUaSKSwsdK5/9NFHTYcOHZzLoaGhZsGCBc7lY8eOmc6dO5ukpCRjjDFlZWXG39/f5Ofnuxxn8uTJZvz48cYYY9atW2ckmeXLlzfO4AE0OR93hy0A+PLLL3Xs2DFdcMEFzjaHw6GoqChJ0ocffihjjHr06OGyX0VFhdq2betcbtGihbp37+5cDg0NVUlJiSTpwIED2rNnjy688ELneh8fHw0YMMB5Keuzzz5TeXm5LrnkEpfjHD16VP369XNpGzBgwOkMGcAZRNgB4HbVYcNms9XaXlVVJW9vb33wwQfy9vZ22SYoKMj5s6+vr8s6m81WY05OXaqqqiRJK1euVKdOnVzW2e12l+XAwMB69wvAvQg7ANyue/fu8vX11Xvvvafw8HBJUmlpqb744gsNHTpU/fr1U2VlpUpKSnTRRRc16BgOh0OhoaF65513NGTIEEnS8ePH9cEHH6h///6SpF69eslut6u4uFhDhw5tnMEBcDvCDgC3Cw4OVkpKiqZPn642bdqoffv2mjNnjry8vGSz2dSjRw9dffXVuvbaa/XQQw+pX79++vHHH7V27Vr17t1bo0aNqtdxbrvtNi1YsEDnnnuuoqOjtWjRIu3fv9+ljjvvvFNpaWmqqqpSbGysSktLlZ+fr6CgIKWkpDTRMwCgKRF2AHiERYsW6cYbb9Rll12mli1basaMGdq9e7f8/f0lSUuXLtW9996rO+64Q998843atm2rCy+8sN5BR5LuuOMO7dmzR5MmTZKXl5dSU1OVnJysAwcOOLf5y1/+ovbt2ysjI0NffvmlWrVqpf79++vuu+9u9DEDODNs5lQuaAPAGXLo0CF16tRJDz30kCZPnuzucgA0Y5zZAeARCgoK9Pnnn+uCCy7QgQMHNH/+fElSUlKSmysD0NwRdgB4jAcffFDbt2+Xn5+ffvOb3+itt95SSEiIu8sC0MxxGQsAAFgaXxcBAAAsjbADAAAsjbADAAAsjbADAAAsjbADAAAsjbADAAAsjbADAAAsjbADAAAsjbADAAAs7f8DBWrAZo2V9NYAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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6v3335cxxivQ5OTkqLi42Ou/359//lk33XSTWrdurf379+uPf/yj/vWvf5VZR3FxsXJzc72+RPbt2yep/C+Wk0JDQ7V3794y7T/88IMkedVSGc52fb8OfFXl5Hpfe+01RUdHn9OyzrTmxo0b67vvvqvQOvr06aPnnntOH3zwgd5//309+OCDkk7sFUpPT9eePXtUr149r7OSGjVqpE6dOmnWrFnlLvNkoCxPaGhouQcln/wbA5yCYSaggj755BNJ8pwR1KdPHx05ckRvvvmmV7+lS5d6pp80duxYZWVl6fXXX9dzzz2nFStW6PHHHy93PS+99JLX82XLlkk6/XVh+vTpo23btunjjz8uU4tlWerdu7ekE/9VSzrn/6z79OmjdevWecLLL9cXGBho2ynBV111lfz8/LRz50517dq13MdJlfVaJCYmav369fr666/Pet4+ffrIsixNnz5dPj4+6tWrlyTpyiuv1Pr165Wenq5evXp57YUZOHCgvvjiC7Vs2bLc7TtdmImPj9e6deu89t6UlpZ6nT11tirrdQTOBntmgDPwxRdfeE5zzc3N1euvv6709HQNGTJEsbGxkqQ//OEPevrppzVq1Cjt3r1bHTt21KZNmzR79mwNGDDAMzTwt7/9TS+++KJSU1PVvn17tW/fXnfeeafuu+8+XX755V7Hufj7+2v+/Pk6cuSIunXrpoyMDP3pT39SYmKievbsecp6J06cqKVLl+rqq6/WzJkzFR0drZUrV+ovf/mLbr/9drVu3VqSFBQUpOjoaP3rX/9Snz591LBhQzVq1OisL3b28MMPe47deOihh9SwYUO99NJLWrlypebNm6eQkJCzWl5liYmJ0cyZMzVt2jR9++23nusD7d+/Xx988IHq1q3ruWhgx44dJUlz585VYmKifH191alTJ8/Q1ZmaOXOm0tLS1KtXLz3wwAPq2LGjDh06pFWrVmnSpEm68MILTzlvWFiYOnTooDVr1qh3794KDAyUdCLMHDhwQAcOHFBKSkqZ9aWnpysuLk7jx49XmzZtVFhYqN27d+s///mPFi9efMphr2nTpunf//63+vTpo2nTpikgIECLFy/Wzz//LOnshuFO6tChgyTpmWeeUVBQkNxut2JjY0+7JxE4Z3YfgQzUZOWdzRQSEmI6d+5sUlJSPKfunpSbm2vGjh1rIiMjjZ+fn4mO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AACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAoxFmAACAo9kaZoqLi/Xggw8qNjZWAQEBatGihWbOnKnS0lJPn9GjR8uyLK/HZZddZmPVAACgJvGzc+Vz587V4sWLtWTJErVv314ffvihbr75ZoWEhOjuu+/29Ovfv79SU1M9z/39/e0oFwAA1EC2hpnNmzdr8ODBuvrqqyVJMTEx+sc//qEPP/zQq5/L5VJERIQdJQIAgBrO1mGmnj176u2339b27dslSZ9++qk2bdqkAQMGePXbsGGDwsLC1Lp1a916663Kycmxo1wAAFAD2bpn5r777lNeXp4uvPBC+fr6qqSkRLNmzdKwYcM8fRITEzV06FBFR0dr165dmj59uq644gp99NFHcrlcZZZZVFSkoqIiz/P8/Pxq2RYAAGAPW8PM8uXL9eKLL2rZsmVq3769PvnkE02YMEFRUVEaNWqUJOnGG2/09O/QoYO6du2q6OhorVy5Utdee22ZZc6ZM0czZsyotm0AAAD2snWYafLkybr//vv1+9//Xh07dtRNN92kiRMnas6cOaecJzIyUtHR0frmm2/KnT516lTl5eV5HtnZ2VVVPgAAqAFs3TNTUFAgHx/vPOXr6+t1avav5ebmKjs7W5GRkeVOd7lc5Q4/AQCA2snWMDNo0CDNmjVLzZs3V/v27bVlyxalpKQoKSlJknTkyBElJyfruuuuU2RkpHbv3q0HHnhAjRo10pAhQ+wsHQAA1BC2hpmnnnpK06dP17hx45STk6OoqCiNGTNGDz30kKQTe2k+//xzLV26VIcOHVJkZKR69+6t5cuXKygoyM7SAQBADWEZY4zdRVSl/Px8hYSEKC8vT8HBwXaXAwCogKNHjyoxMVGSlJaWpoCAAJsrQlU7m+9v7s0EAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAcjTADAAAc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55EzDjOfffaZ5+e77rpL99xzj/bt26eOHTuWOaupU6dOZ1XEnj17tHbtWr3++uun7RcZGano6Gh98803p+wzdepUTZo0yfM8Pz9fzZo1O6t6AACAc5xxmOncubMsy/I64DcpKcnz88lpZ3MA8EmpqakKCwvT1Vdffdp+ubm5ys7OVmRk5Cn7uFyuUw5BAQCA2ueMw8yuXbuqpIDS0lKlpqZq1KhR8vP7XzlHjhxRcnKyrrvuOkVGRmr37t164IEH1KhRI67uCgAAPM44zERHR1dJAWvXrlVWVpbXXh5J8vX11eeff66lS5fq0KFDioyMVO/evbV8+XIFBQVVSS0AAMB5KnQA8IoVK8pttyxLbrdbF1xwgWJjY89oWf369StzrRpJCggI0OrVqytSHgAAOI9UKMxcc801ZY6fkbyPm+nZs6fefPNNNWjQoFIKBQAAKE+FLpqXnp6ubt26KT09XXl5ecrLy1N6erouvfRSvfXWW/rvf/+r3Nxc3XvvvZVdLwAAgJcK7Zm5++679cwzzyguLs7T1qdPH7ndbt12223aunWrFixYUOY4GAAAgMpWoT0zO3fuVHBwcJn24OBgffvtt5KkVq1a6aeffjq36gAAAH5DhcLMJZdcosmTJ+vHH3/0tP3444+aMmWKunXrJunELQ+aNm1aOVUCAACcQoWGmZ577jkNHjxYTZs2VbNmzWRZlrKystSiRQv961//knTiOjHTp0+v1GIBAAB+rUJhpk2bNvryyy+1evVqbd++XcYYXXjhherbt698fE7s7Lnmmmsqs04AAIByVSjMSCdOw+7fv7/69+9fmfUAAACclTMOM08++aRuu+02ud1uPfnkk6ftO378+HMuDAAA4EyccZh5/PHHNWLECLndbj3++OOn7GdZFmEGAABUmwrdaLKqbjoJAABwtip0avZJx44d09dff63i4uLKqgcAAOCsVOgA4IKCAt11111asmSJJGn79u1q0aKFxo8fr6ioKN1///2VWmRN5nV/qpLj9hUC1CS/eC+UdyNZAKhMFQozU6dO1aeffqoNGzZ4nc105ZVX6uGHHz6vwkxRUZHn56BPX7axEqBmKioqUmBgoN1lAKjFKhRm3nzzTS1fvlyXXXaZLMvytLdr1047d+6stOIAAAB+S4XCzI8//qiwsLAy7T///LNXuDkfuFwuz8+HL/q95FvH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PiUlJZo0aZLq16+v0NBQTZkyRb++W4sxRvPmzVOLFi0UEBCgiy66SK+99ppn+oYNG2RZllavXq2uXbvK5XLpnXfeqdLXBsC5I8wAqHKTJk3Su+++qxUrVig9PV3vvPOOPv74Y8/0m2++We+++65efvllffbZZxo6dKj69++vb775xtOnoKBAjz32mF544QX997//VVZWlu69917P9Pnz5+vvf/+7nnvuOW3atEkHDhzQG2+84VXHgw8+qNTUVC1atEhbt27VxIkTNXLkSG3cuNGr35QpUzRnzhx9+eWX6tSpUxW9KgAqjQGAKpSfn2/q1KljXn31VU/boUOHTGBgoLn77rvNjh07jGVZ5vvvv/ear0+fPmbq1KnGGGNSU1ONJLNjxw7P9KefftqEh4d7nkdGRpo///nPnufHjx83TZs2NYMHDzbGGHPkyBHjdrtNRkaG13puueUWM2zYMGOMMevXrzeSzJtvvlk5Gw+gWvjZHaYA1G7ffvutjh8/rksvvdTTFhISojZt2kiSPv74Yxlj1Lp1a6/5ioqKFBoa6nkeGBioli1bep5HRkYqJydHkpSXl6e9e/eqR48enul+fn7q2rWrZ6hp27ZtKiwsVN++fb3Wc+zYMXXp0sWrrWvXrueyyQCqGWEGQJU6GSYsyyq3vbS0VL6+vvroo4/k6+vr1adevXqen+vUqeM1zbKsMsfEnE5paakkaeXKlWrSpInXNJfL5fW8bt26Z7xcAPYjzACoUi1btlSdOnX0wQcfqFmzZpKk/Px8ffPNN4qPj1eXLl1UUlKinJwc/e53v6vQOkJCQhQZGan33ntPvXr1kiQVFxfro48+0sUXXyxJateunVwul7KyshQfH185GwegRiDMAKhSQUFBGjVqlCZPnqyGDRsqLCxMDz/8sHx8fGRZllq3bq0RI0boD3/4g+bPn68uXbrop59+0rp169SxY0cNGDDgjNZz9913689//rNatWqltm3bKiUlRYcOHfKq495779XEiRNVWlqqnj17Kj8/XxkZGapXr55GjRpVRa8AgKpGmAFQ5VJSUjR27FgNHDhQwcHBmjJlirKzs+V2uyVJqamp+tOf/qR77rlH33//vUJDQ9WjR48zDjKSdM8992jv3r0aPXq0fHx8lJSUpCFDhigvL8/T55FHHlFYWJjmzJmjb7/9VvXr19fFF1+sBx54oNK3GUD1sczZDDoDQCX4+eef1aRJE82fP1+33HKL3eUAcDj2zACoclu2bNFXX32lSy+9VHl5eZo5c6YkafDgwTZXBqA2IMwAqBaPPfaYvv76a/n7++uSSy7RO++8o0aNGtldFoBagGEmAADgaNzOAAAAOBphBgAAOBphBgAAOBphBgAAOBphBgAAOBphBgAAOBphBgAAOBphBgAAOBphBgAAONr/B3jPzF54MiT0AAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "\n", "# obtain plots for our list\n", "for i in list_num:\n", " sns.boxplot(x=\"gender\", y=i, data=df)\n", " plt.title(\"Boxplot for metric \" + i)\n", " plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sorting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sorting by values:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
0Stefanie1162161.5female421.6257.2521.812023-03-21
1Peter2163163.5male421.6368.8025.892023-03-21
2Stefanie3163163.2female421.6373.0127.482023-03-21
3Manuela4164165.1female421.6472.1226.812023-03-21
4Simon5164163.2male421.6477.3428.762023-03-21
5Sophia6164164.4female421.6461.4322.842023-03-21
6Ellen7164164.0female421.6475.0827.912023-03-21
12Fin13165165.5male421.6566.8724.562023-03-21
11Mila12165167.4female421.6574.6327.412023-03-21
10Lena11165166.3female421.6590.5133.252023-03-21
9Marie10165165.1female421.6567.3124.722023-03-21
8Lina9165165.2female421.6576.0227.922023-03-21
7Emilia8165165.2female421.6572.0626.472023-03-21
13Eric14166166.2male421.6679.4928.852023-03-21
14Pia15166166.1female421.6680.7129.292023-03-21
15Marc16166166.5male421.6688.3532.062023-03-21
16Ralph17166166.6male421.6668.8624.992023-03-21
17Tom18167166.2male421.6769.7325.002023-03-21
18Steven19167167.3male421.6771.7425.722023-03-21
19Emanuel20168168.5male421.6878.4927.812023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m \\\n", "0 Stefanie 1 162 161.5 female 42 1.62 \n", "1 Peter 2 163 163.5 male 42 1.63 \n", "2 Stefanie 3 163 163.2 female 42 1.63 \n", "3 Manuela 4 164 165.1 female 42 1.64 \n", "4 Simon 5 164 163.2 male 42 1.64 \n", "5 Sophia 6 164 164.4 female 42 1.64 \n", "6 Ellen 7 164 164.0 female 42 1.64 \n", "12 Fin 13 165 165.5 male 42 1.65 \n", "11 Mila 12 165 167.4 female 42 1.65 \n", "10 Lena 11 165 166.3 female 42 1.65 \n", "9 Marie 10 165 165.1 female 42 1.65 \n", "8 Lina 9 165 165.2 female 42 1.65 \n", "7 Emilia 8 165 165.2 female 42 1.65 \n", "13 Eric 14 166 166.2 male 42 1.66 \n", "14 Pia 15 166 166.1 female 42 1.66 \n", "15 Marc 16 166 166.5 male 42 1.66 \n", "16 Ralph 17 166 166.6 male 42 1.66 \n", "17 Tom 18 167 166.2 male 42 1.67 \n", "18 Steven 19 167 167.3 male 42 1.67 \n", "19 Emanuel 20 168 168.5 male 42 1.68 \n", "\n", " weight bmi date \n", "0 57.25 21.81 2023-03-21 \n", "1 68.80 25.89 2023-03-21 \n", "2 73.01 27.48 2023-03-21 \n", "3 72.12 26.81 2023-03-21 \n", "4 77.34 28.76 2023-03-21 \n", "5 61.43 22.84 2023-03-21 \n", "6 75.08 27.91 2023-03-21 \n", "12 66.87 24.56 2023-03-21 \n", "11 74.63 27.41 2023-03-21 \n", "10 90.51 33.25 2023-03-21 \n", "9 67.31 24.72 2023-03-21 \n", "8 76.02 27.92 2023-03-21 \n", "7 72.06 26.47 2023-03-21 \n", "13 79.49 28.85 2023-03-21 \n", "14 80.71 29.29 2023-03-21 \n", "15 88.35 32.06 2023-03-21 \n", "16 68.86 24.99 2023-03-21 \n", "17 69.73 25.00 2023-03-21 \n", "18 71.74 25.72 2023-03-21 \n", "19 78.49 27.81 2023-03-21 " ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.sort_values(by=\"height\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Selection\n", "\n", "### Getting []\n", "\n", "Selecting a single column (equivalent to `df.height`):" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 162\n", "1 163\n", "2 163\n", "3 164\n", "4 164\n", "5 164\n", "6 164\n", "7 165\n", "8 165\n", "9 165\n", "10 165\n", "11 165\n", "12 165\n", "13 166\n", "14 166\n", "15 166\n", "16 166\n", "17 167\n", "18 167\n", "19 168\n", "Name: height, dtype: int64" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"height\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selecting via [], which slices the rows (endpoint is not included).\n" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
0Stefanie1162161.5female421.6257.2521.812023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m \\\n", "0 Stefanie 1 162 161.5 female 42 1.62 \n", "\n", " weight bmi date \n", "0 57.25 21.81 2023-03-21 " ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[0:1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### By label .loc\n", "\n", "The `.loc` attribute is the primary access method. The following are valid inputs:\n", "\n", "For getting a cross section using a label:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
0Stefanie1162161.5female421.6257.2521.812023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m \\\n", "0 Stefanie 1 162 161.5 female 42 1.62 \n", "\n", " weight bmi date \n", "0 57.25 21.81 2023-03-21 " ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc[[0]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selecting on a multi-axis by label:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameheight
0Stefanie162
1Peter163
2Stefanie163
3Manuela164
4Simon164
5Sophia164
6Ellen164
7Emilia165
8Lina165
9Marie165
10Lena165
11Mila165
12Fin165
13Eric166
14Pia166
15Marc166
16Ralph166
17Tom167
18Steven167
19Emanuel168
\n", "
" ], "text/plain": [ " name height\n", "0 Stefanie 162\n", "1 Peter 163\n", "2 Stefanie 163\n", "3 Manuela 164\n", "4 Simon 164\n", "5 Sophia 164\n", "6 Ellen 164\n", "7 Emilia 165\n", "8 Lina 165\n", "9 Marie 165\n", "10 Lena 165\n", "11 Mila 165\n", "12 Fin 165\n", "13 Eric 166\n", "14 Pia 166\n", "15 Marc 166\n", "16 Ralph 166\n", "17 Tom 167\n", "18 Steven 167\n", "19 Emanuel 168" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc[ : , [\"name\", \"height\"]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Showing label slicing, both endpoints are included:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameheight
0Stefanie162
1Peter163
\n", "
" ], "text/plain": [ " name height\n", "0 Stefanie 162\n", "1 Peter 163" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc[0:1, [\"name\", \"height\"]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Reduction in the dimensions of the returned object:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "name Stefanie\n", "height 162\n", "Name: 0, dtype: object" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc[0, [\"name\", \"height\"]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For getting a scalar value:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 162\n", "Name: height, dtype: int64" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc[[0], \"height\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### By position .iloc\n", "\n", "pandas provides a suite of methods in order to get purely integer based indexing. Here, the .iloc attribute is the primary access method. " ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "name Stefanie\n", "id 1\n", "height 162\n", "average_height_parents 161.5\n", "gender female\n", "number 42\n", "height_m 1.62\n", "weight 57.25\n", "bmi 21.81\n", "date 2023-03-21\n", "Name: 0, dtype: object" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By integer slices:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameid
0Stefanie1
1Peter2
\n", "
" ], "text/plain": [ " name id\n", "0 Stefanie 1\n", "1 Peter 2" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[0:2, 0:2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By lists of integer position locations:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameheight
0Stefanie162
2Stefanie163
\n", "
" ], "text/plain": [ " name height\n", "0 Stefanie 162\n", "2 Stefanie 163" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[[0, 2], [0, 2]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For slicing rows explicitly:" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
1Peter2163163.5male421.6368.8025.892023-03-21
2Stefanie3163163.2female421.6373.0127.482023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m \\\n", "1 Peter 2 163 163.5 male 42 1.63 \n", "2 Stefanie 3 163 163.2 female 42 1.63 \n", "\n", " weight bmi date \n", "1 68.80 25.89 2023-03-21 \n", "2 73.01 27.48 2023-03-21 " ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[1:3, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For slicing columns explicitly:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idheight
01162
12163
23163
34164
45164
56164
67164
78165
89165
910165
1011165
1112165
1213165
1314166
1415166
1516166
1617166
1718167
1819167
1920168
\n", "
" ], "text/plain": [ " id height\n", "0 1 162\n", "1 2 163\n", "2 3 163\n", "3 4 164\n", "4 5 164\n", "5 6 164\n", "6 7 164\n", "7 8 165\n", "8 9 165\n", "9 10 165\n", "10 11 165\n", "11 12 165\n", "12 13 165\n", "13 14 166\n", "14 15 166\n", "15 16 166\n", "16 17 166\n", "17 18 167\n", "18 19 167\n", "19 20 168" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[:, 1:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For getting a value explicitly:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Stefanie'" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.iloc[0, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Filter (boolean indexing)\n", "\n", "Using a single column’s values to select data." ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
\n", "
" ], "text/plain": [ "Empty DataFrame\n", "Columns: [name, id, height, average_height_parents, gender, number, height_m, weight, bmi, date]\n", "Index: []" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[df[\"height\"] > 180]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the [isin()](https://pandas.pydata.org/docs/reference/api/pandas.Series.isin.html#pandas.Series.isin) method for filtering:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameidheightaverage_height_parentsgendernumberheight_mweightbmidate
17Tom18167166.2male421.6769.7325.02023-03-21
\n", "
" ], "text/plain": [ " name id height average_height_parents gender number height_m weight \\\n", "17 Tom 18 167 166.2 male 42 1.67 69.73 \n", "\n", " bmi date \n", "17 25.0 2023-03-21 " ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[df[\"name\"].isin([\"Tom\", \"Lisa\"])]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Grouping\n", "\n", "By “group by” we are referring to a process involving one or more of the following steps:\n", "\n", "- **Splitting** the data into groups based on some criteria\n", "\n", "- **Applying** a function to each group independently\n", "\n", "- **Combining** the results into a data structure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Grouping and then applying the mean() function to the resulting groups." ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/xv/mfzfdtz93_n7615m5ks0tm2m0000gn/T/ipykernel_16204/2544976795.py:1: FutureWarning: The default value of numeric_only in DataFrameGroupBy.mean is deprecated. In a future version, numeric_only will default to False. Either specify numeric_only or select only columns which should be valid for the function.\n", " df.groupby(\"gender\").mean().T\n" ] }, { "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", "
genderfemalemale
height164.363636165.777778
average_height_parents164.863636165.944444
number42.00000042.000000
height_m1.6436361.657778
weight72.73909174.407778
bmi26.90090927.071111
\n", "
" ], "text/plain": [ "gender female male\n", "height 164.363636 165.777778\n", "average_height_parents 164.863636 165.944444\n", "number 42.000000 42.000000\n", "height_m 1.643636 1.657778\n", "weight 72.739091 74.407778\n", "bmi 26.900909 27.071111" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.groupby(\"gender\").mean().T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Segment data into bins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the function [cut](https://pandas.pydata.org/docs/reference/api/pandas.cut.html) when you need to segment and sort data values into bins. This function is also useful for going from a continuous variable to a categorical variable. \n", "\n", "In our example, we create a body mass index category. The standard weight status categories associated with BMI ranges for adults are shown in the following table:\n", "\n", "BMI\t| Weight Status\n", "---| ---\n", "Below 18.5 |\tUnderweight\n", "18.5 - 24.9 |\tNormal or Healthy Weight\n", "25.0 - 29.9 |\tOverweight\n", "30.0 and Above |\tObese\n", "\n", "Source: [U.S. Department of Health & Human Services](https://www.cdc.gov/healthyweight/assessing/bmi/adult_bmi/index.html)\n", "\n", "In our function, we discretize the variable `bmi` into four bins according to the table above:\n", "\n", "- The bins [0, 18.5, 25, 30, float('inf')] indicate (0,18.5], (18.5,25], (25,30], (30, float('inf))\n", "- `float('inf')` is used for setting variable with an infinitely large value" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [], "source": [ "df['bmi_category'] = pd.cut(df['bmi'], \n", " bins=[0, 18.5, 25, 30, float('inf')], \n", " labels=['underweight', 'normal', 'overweight', \"obese\"])" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 normal\n", "1 overweight\n", "2 overweight\n", "3 overweight\n", "4 overweight\n", "5 normal\n", "6 overweight\n", "7 overweight\n", "8 overweight\n", "9 normal\n", "10 obese\n", "11 overweight\n", "12 normal\n", "13 overweight\n", "14 overweight\n", "15 obese\n", "16 normal\n", "17 normal\n", "18 overweight\n", "19 overweight\n", "Name: bmi_category, dtype: category\n", "Categories (4, object): ['underweight' < 'normal' < 'overweight' < 'obese']" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['bmi_category']" ] } ], "metadata": { "interpreter": { "hash": "463226f144cc21b006ce6927bfc93dd00694e52c8bc6857abb6e555b983749e9" }, "kernelspec": { "display_name": "Python 3.8.2 64-bit ('base': conda)", "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.9.16" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }