{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas2)=\n", "# Table reshaping and joins" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "import myst_nb" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Last updated: 2024-02-06 00:05:42\n" ] } ], "source": [ "!echo Last updated: `date +'%Y-%m-%d %H:%M:%S'`" ] }, { "cell_type": "code", "execution_count": 3, "id": "9be78d54", "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "import options" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "*****" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In the previous chapter (see {ref}`pandas1`), we introduced the `pandas` package, and covered the basic operations with tables using `pandas`, such as importing and exporting, subsetting, renaming columns, sorting, and calculating new columns. In practice, we often need to do more than that. For example, we may need to aggregate, or to reshape, tables into a different form, or to combine numerous tables into one. In this chapter, we cover some of the common table operations which involve modifying table structure or combining multiple tables." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "When working with data, it is often necessary to *combine* data from multiple sources, and/or *reshape* data into the right form that a particular function accepts: \n", "\n", "* Combining may simply involve \"pasting\", or concatenating, two tables one on top of the other, or side-by-side (see {ref}`pandas-concatenation`). \n", "* In more complex cases, combining involves a table *join*, where the information from two tables is combined according to one or more \"key\" columns which are common to both tables (see {ref}`pandas-joining-tables`). \n", "* Moreover, we may need to summarize the values of a table according to a particular grouping, which is known as *aggregation* (see {ref}`pandas-aggregation`). \n", "* A special type of aggregation is *applying* a function across each row, or each column, of a table ({ref}`pandas-row-col-wise-operations`)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In this chapter, we learn about all of those common methods for combining and reshaping tables. By the end of the chapter, you will have the ability to not just import and transform tables in Python (see {ref}`pandas1`), but also to reshape and combine tables to the right form, which facilitates further analysis and insight from the data in those tables." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Sample data" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "First, let's recreate the small table named `stations` which we used in the previous chapter (see {ref}`creating-dataframe`):" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlat
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284
2DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288\n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284\n", "2 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "name = pd.Series(['Beer-Sheva Center', 'Beer-Sheva University', 'Dimona'])\n", "city = pd.Series(['Beer-Sheva', 'Beer-Sheva', 'Dimona'])\n", "lines = pd.Series([4, 5, 1])\n", "piano = pd.Series([False, True, False])\n", "lon = pd.Series([34.798443, 34.812831, 35.011635])\n", "lat = pd.Series([31.243288, 31.260284, 31.068616])\n", "d = {'name': name, 'city': city, 'lines': lines, 'piano': piano, 'lon': lon, 'lat': lat}\n", "stations = pd.DataFrame(d)\n", "stations" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We will also load the sample climatic data which we are also familiar with from the previous chapter ({ref}`pandas-reading-from-file`), into a `DataFrame` named `dat`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearGlobNHemSHem24N-90N...EQU-24N24S-EQU44S-24S64S-44S90S-64S
01880-0.17-0.28-0.05-0.38...-0.14-0.11-0.040.050.67
11881-0.09-0.180.00-0.36...0.110.10-0.06-0.070.60
21882-0.11-0.21-0.01-0.31...-0.04-0.050.010.040.63
31883-0.17-0.28-0.07-0.34...-0.17-0.16-0.040.070.50
41884-0.28-0.42-0.15-0.61...-0.12-0.17-0.19-0.020.65
....................................
13920190.981.200.751.42...0.900.900.750.390.83
14020201.011.350.681.67...0.880.840.580.390.89
14120210.851.140.561.42...0.720.600.720.320.30
14220220.891.160.621.52...0.620.510.790.381.09
14320231.171.490.851.78...1.071.040.910.440.63
\n", "

144 rows × 15 columns

\n", "
" ], "text/plain": [ " Year Glob NHem SHem 24N-90N ... EQU-24N 24S-EQU 44S-24S 64S-44S \\\n", "0 1880 -0.17 -0.28 -0.05 -0.38 ... -0.14 -0.11 -0.04 0.05 \n", "1 1881 -0.09 -0.18 0.00 -0.36 ... 0.11 0.10 -0.06 -0.07 \n", "2 1882 -0.11 -0.21 -0.01 -0.31 ... -0.04 -0.05 0.01 0.04 \n", "3 1883 -0.17 -0.28 -0.07 -0.34 ... -0.17 -0.16 -0.04 0.07 \n", "4 1884 -0.28 -0.42 -0.15 -0.61 ... -0.12 -0.17 -0.19 -0.02 \n", ".. ... ... ... ... ... ... ... ... ... ... \n", "139 2019 0.98 1.20 0.75 1.42 ... 0.90 0.90 0.75 0.39 \n", "140 2020 1.01 1.35 0.68 1.67 ... 0.88 0.84 0.58 0.39 \n", "141 2021 0.85 1.14 0.56 1.42 ... 0.72 0.60 0.72 0.32 \n", "142 2022 0.89 1.16 0.62 1.52 ... 0.62 0.51 0.79 0.38 \n", "143 2023 1.17 1.49 0.85 1.78 ... 1.07 1.04 0.91 0.44 \n", "\n", " 90S-64S \n", "0 0.67 \n", "1 0.60 \n", "2 0.63 \n", "3 0.50 \n", "4 0.65 \n", ".. ... \n", "139 0.83 \n", "140 0.89 \n", "141 0.30 \n", "142 1.09 \n", "143 0.63 \n", "\n", "[144 rows x 15 columns]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dat = pd.read_csv('data/ZonAnn.Ts+dSST.csv')\n", "dat" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-concatenation)=\n", "## Concatenation" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Overview" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The most basic method for combining several tables into one is *concatenation*, which essentially means binding tables one on top of another, or side-by-side:\n", "\n", "* Concatenation *by row* is usually desired when the two (or more) tables share exactly the same columns. For example, combining several tables reflecting the same data (e.g., measured on different dates, or for different subjects) involves concatenation by row. \n", "* Concatenation *by column* is useful when we need to attach new variables for the same observations we already have. For example, we may want to combine several different type of observations which are split across separate files." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In `pandas`, concatenation can be done using [`pd.concat`](https://pandas.pydata.org/docs/reference/api/pandas.concat.html). The `pd.concat` function accepts a `list` of tables, which are combined:\n", "\n", "* *By row* when using `axis=0` (the default)\n", "* *By column* when using `axis=1`" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(concatenation-by-row)=\n", "### Concatenation by row" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To demonstrate concatenation *by row*, let's create two subsets `x` and `y` of `stations`, with the 1st row and the 2nd-3rd rows, respectively:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlat
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = stations.iloc[[0], :] ## 1st row\n", "x" ] }, { "cell_type": "code", "execution_count": 7, "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", "
namecitylinespianolonlat
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284
2DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284\n", "2 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = stations.iloc[[1, 2], :] ## 2nd and 3rd rows\n", "y" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The expression `pd.concat([x,y])` then can be used to concatenates `x` and `y`, by row, re-creating the complete table `stations`:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlat
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284
2DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288\n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284\n", "2 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.concat([x, y])" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that `pd.concat` accepts a `list` of `DataFrame`s to concatenate, such as `[x,y]`. In this example the `list` is of length 2, but in general it can be of any length. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(concatenation-by-column)=\n", "### Concatenation by column" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To demonstrate concatenation by column, let's now split `stations` to subsets `x` and `y` *by column*. For example, the `x` table is going to contain one column `'name'`:" ] }, { "cell_type": "code", "execution_count": 9, "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", "
name
0Beer-Sheva Center
1Beer-Sheva University
2Dimona
\n", "
" ], "text/plain": [ " name\n", "0 Beer-Sheva Center\n", "1 Beer-Sheva University\n", "2 Dimona" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = stations[['name']]\n", "x" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "and the `y` table is going to contain two columns `'lon'` and `'lat'`:" ] }, { "cell_type": "code", "execution_count": 10, "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", "
lonlat
034.79844331.243288
134.81283131.260284
235.01163531.068616
\n", "
" ], "text/plain": [ " lon lat\n", "0 34.798443 31.243288\n", "1 34.812831 31.260284\n", "2 35.011635 31.068616" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = stations[['lon', 'lat']]\n", "y" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To concatenate by column, we use `pd.concat` with the `axis=1` argument. This concatenates the tables `x` and `y` side-by-side:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namelonlat
0Beer-Sheva Center34.79844331.243288
1Beer-Sheva University34.81283131.260284
2Dimona35.01163531.068616
\n", "
" ], "text/plain": [ " name lon lat\n", "0 Beer-Sheva Center 34.798443 31.243288\n", "1 Beer-Sheva University 34.812831 31.260284\n", "2 Dimona 35.011635 31.068616" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.concat([x, y], axis=1)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Alignment by index" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that concatenation—like many other operations in `pandas`—operates based on the *index*, rather than position. This is not a problem when concatenating by row, where columns typically need to be aligned by their index, i.e., column name (see {ref}`concatenation-by-row`). When concatenating by column, however, we need to pay attention to the index: is it meaningful, and we want to use it when aligning rows? Or is it arbitarary, and we want to reset it before concatenating?" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For example, here is what happens in concatenation by column, when the index is not aligned (see {ref}`setting-series-index`):" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namelonlat
0Beer-Sheva CenterNaNNaN
1Beer-Sheva University34.79844331.243288
2Dimona34.81283131.260284
3NaN35.01163531.068616
\n", "
" ], "text/plain": [ " name lon lat\n", "0 Beer-Sheva Center NaN NaN\n", "1 Beer-Sheva University 34.798443 31.243288\n", "2 Dimona 34.812831 31.260284\n", "3 NaN 35.011635 31.068616" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y.index = [1,2,3]\n", "pd.concat([x, y], axis=1)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To make sure we concatenate based on *position*, we may reset the index (using `.reset_index(drop=True)`) on both tables before concatenation:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namelonlat
0Beer-Sheva Center34.79844331.243288
1Beer-Sheva University34.81283131.260284
2Dimona35.01163531.068616
\n", "
" ], "text/plain": [ " name lon lat\n", "0 Beer-Sheva Center 34.798443 31.243288\n", "1 Beer-Sheva University 34.812831 31.260284\n", "2 Dimona 35.011635 31.068616" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = y.reset_index(drop=True)\n", "pd.concat([x, y], axis=1)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-row-col-wise-operations)=\n", "## Row/col-wise operations" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-row-colwise-built-in)=\n", "### Built-in methods" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "`pandas` defines summary methods which can be used to calculate row-wise and column-wise summaries of `DataFrame`s. The `pandas` methods are generally similar to the `numpy` 2D summary functions and methods (see {ref}`numpy-summaries-per-dimension-2d`) which we learned about earlier, but there are several important differences to keep in mind:\n", "\n", "* `pandas` **only has methods**, not functions, i.e., there is a `.mean` method but there is *no* `pd.mean` function—unlike `numpy`, which in many cases has both, e.g., both `.mean` and `np.mean` (see {numref}`numpy-summary-functions`)\n", "* The **default `axis`** is different: in `pandas` the default is column-wise summary (`axis=0`), while in `numpy` the default is \"global\" summary (`axis=None`) (see {ref}`numpy-global-summaries`)\n", "* `pandas` methods **exclude \"No Data\"** by default (see {ref}`pandas-operations-with-missing-data`), unless we explicitly specify `skipna=False`—unlike `numpy` which by default includes \"No Data\", unless using the specific \"No Data\"-safe functions such as `np.nanmean` (see {ref}`numpy-operations-with-nodata`)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Commonly used `pandas` summary methods are listed in {numref}`pandas-aggregation-methods`." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{table} Pandas aggregation methods\n", ":name: pandas-aggregation-methods\n", "\n", "| Operation | Method |\n", "|:---:|:---:|\n", "| `.sum` | Sum |\n", "| `.min` | Minimum | \n", "| `.max` | Maximum | \n", "| `.mean` | Mean | \n", "| `.median` | Median |\n", "| `.count` | Count (of non-missing values) |\n", "| `.nunique` | Number of unique values |\n", "| `.idxmin` | Index of (first) minimum |\n", "| `.idxmax` | Index of (first) maximum |\n", "| `.any` | Is at least one element `True`? |\n", "| `.all` | Are all elements `True`? |\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For the next few examples, let's take the *regional* temperature anomaly time series into a separate `DataFrame` named `regions`:" ] }, { "cell_type": "code", "execution_count": 14, "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", "
90S-64S64S-44S44S-24S24S-EQUEQU-24N24N-44N44N-64N64N-90N
00.670.05-0.04-0.11-0.14-0.26-0.52-0.80
10.60-0.07-0.060.100.11-0.19-0.50-0.93
20.630.040.01-0.05-0.04-0.13-0.31-1.41
30.500.07-0.04-0.16-0.17-0.24-0.58-0.18
40.65-0.02-0.19-0.17-0.12-0.45-0.66-1.30
...........................
1390.830.390.750.900.900.991.432.71
1400.890.390.580.840.881.191.812.88
1410.300.320.720.600.721.261.352.05
1421.090.380.790.510.621.271.502.34
1430.630.440.911.041.071.471.872.58
\n", "

144 rows × 8 columns

\n", "
" ], "text/plain": [ " 90S-64S 64S-44S 44S-24S 24S-EQU EQU-24N 24N-44N 44N-64N 64N-90N\n", "0 0.67 0.05 -0.04 -0.11 -0.14 -0.26 -0.52 -0.80\n", "1 0.60 -0.07 -0.06 0.10 0.11 -0.19 -0.50 -0.93\n", "2 0.63 0.04 0.01 -0.05 -0.04 -0.13 -0.31 -1.41\n", "3 0.50 0.07 -0.04 -0.16 -0.17 -0.24 -0.58 -0.18\n", "4 0.65 -0.02 -0.19 -0.17 -0.12 -0.45 -0.66 -1.30\n", ".. ... ... ... ... ... ... ... ...\n", "139 0.83 0.39 0.75 0.90 0.90 0.99 1.43 2.71\n", "140 0.89 0.39 0.58 0.84 0.88 1.19 1.81 2.88\n", "141 0.30 0.32 0.72 0.60 0.72 1.26 1.35 2.05\n", "142 1.09 0.38 0.79 0.51 0.62 1.27 1.50 2.34\n", "143 0.63 0.44 0.91 1.04 1.07 1.47 1.87 2.58\n", "\n", "[144 rows x 8 columns]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = [\n", " '90S-64S', \n", " '64S-44S', \n", " '44S-24S', \n", " '24S-EQU', \n", " 'EQU-24N', \n", " '24N-44N', \n", " '44N-64N', \n", " '64N-90N'\n", "]\n", "regions = dat[cols]\n", "regions" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Using the `.mean` method combined with `axis=0` (i.e., the function is applied on each column), we can calculate the mean temperature anomaly in each region:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "90S-64S -0.074028\n", "64S-44S -0.053681\n", "44S-24S 0.047917\n", "24S-EQU 0.083056\n", "EQU-24N 0.066181\n", "24N-44N 0.052500\n", "44N-64N 0.142500\n", "64N-90N 0.273333\n", "dtype: float64" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "regions.mean(axis=0)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that `axis=0` is the default, so we can also get the same result without specifying it (unlike `numpy` where the default is global summary, i.e., `axis=None`; see {ref}`numpy-global-summaries`):" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "90S-64S -0.074028\n", "64S-44S -0.053681\n", "44S-24S 0.047917\n", "24S-EQU 0.083056\n", "EQU-24N 0.066181\n", "24N-44N 0.052500\n", "44N-64N 0.142500\n", "64N-90N 0.273333\n", "dtype: float64" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "regions.mean()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-a\n", ":class: important\n", "* Calculate a `list` of (the first) years when the maximum temperature was observed per region (answer: {glue:}`year-of-max-per-region`)\n", "```" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [ { "data": { "text/plain": [ "[1996, 1985, 2023, 2016, 2023, 2023, 2023, 2016]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "year-of-max-per-region" } }, "output_type": "display_data" } ], "source": [ "myst_nb.glue('year-of-max-per-region', dat['Year'].loc[regions.idxmax()].tolist())" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Conversely, using `axis=1`, we can calculate *row* means, i.e., the average temperature anomaly for each year across all regions:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 -0.14375\n", "1 -0.11750\n", "2 -0.15750\n", "3 -0.10000\n", "4 -0.28250\n", " ... \n", "139 1.11250\n", "140 1.18250\n", "141 0.91500\n", "142 1.06250\n", "143 1.25125\n", "Length: 144, dtype: float64" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "regions.mean(axis=1)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "If necessary, the result can be assigned into a new column (see {ref}`pandas-creating-new-columns`), hereby named `mean`, as follows:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearGlobNHemSHem24N-90N...24S-EQU44S-24S64S-44S90S-64Smean
01880-0.17-0.28-0.05-0.38...-0.11-0.040.050.67-0.14375
11881-0.09-0.180.00-0.36...0.10-0.06-0.070.60-0.11750
21882-0.11-0.21-0.01-0.31...-0.050.010.040.63-0.15750
31883-0.17-0.28-0.07-0.34...-0.16-0.040.070.50-0.10000
41884-0.28-0.42-0.15-0.61...-0.17-0.19-0.020.65-0.28250
....................................
13920190.981.200.751.42...0.900.750.390.831.11250
14020201.011.350.681.67...0.840.580.390.891.18250
14120210.851.140.561.42...0.600.720.320.300.91500
14220220.891.160.621.52...0.510.790.381.091.06250
14320231.171.490.851.78...1.040.910.440.631.25125
\n", "

144 rows × 16 columns

\n", "
" ], "text/plain": [ " Year Glob NHem SHem 24N-90N ... 24S-EQU 44S-24S 64S-44S 90S-64S \\\n", "0 1880 -0.17 -0.28 -0.05 -0.38 ... -0.11 -0.04 0.05 0.67 \n", "1 1881 -0.09 -0.18 0.00 -0.36 ... 0.10 -0.06 -0.07 0.60 \n", "2 1882 -0.11 -0.21 -0.01 -0.31 ... -0.05 0.01 0.04 0.63 \n", "3 1883 -0.17 -0.28 -0.07 -0.34 ... -0.16 -0.04 0.07 0.50 \n", "4 1884 -0.28 -0.42 -0.15 -0.61 ... -0.17 -0.19 -0.02 0.65 \n", ".. ... ... ... ... ... ... ... ... ... ... \n", "139 2019 0.98 1.20 0.75 1.42 ... 0.90 0.75 0.39 0.83 \n", "140 2020 1.01 1.35 0.68 1.67 ... 0.84 0.58 0.39 0.89 \n", "141 2021 0.85 1.14 0.56 1.42 ... 0.60 0.72 0.32 0.30 \n", "142 2022 0.89 1.16 0.62 1.52 ... 0.51 0.79 0.38 1.09 \n", "143 2023 1.17 1.49 0.85 1.78 ... 1.04 0.91 0.44 0.63 \n", "\n", " mean \n", "0 -0.14375 \n", "1 -0.11750 \n", "2 -0.15750 \n", "3 -0.10000 \n", "4 -0.28250 \n", ".. ... \n", "139 1.11250 \n", "140 1.18250 \n", "141 0.91500 \n", "142 1.06250 \n", "143 1.25125 \n", "\n", "[144 rows x 16 columns]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dat['mean'] = regions.mean(axis=1)\n", "dat" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Here is a visualization (see {ref}`pandas-line-plots`) of the mean time series we just calculated:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhgAAAINCAYAAAB8nwY4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAACSa0lEQVR4nO3deXxcdb0//tfsk0ky2Vea7qX7jvQWQeBS22K//EC4CIhWelkUqYpVkHoRuHAVUTbFKoqyXReWyyIqFkppQaC00AXa0pbue5JmncwkmfX8/jjzOXPOzJktmclMktfz8ciDNnNyck5bct7zfr8/749BkiQJRERERBlkzPUFEBER0dDDAIOIiIgyjgEGERERZRwDDCIiIso4BhhERESUcQwwiIiIKOMYYBAREVHGMcAgIiKijDPn+gJyIRQK4cSJEyguLobBYMj15RAREQ0akiShq6sL9fX1MBrj5ymGZYBx4sQJNDQ05PoyiIiIBq2jR49ixIgRcV8flgFGcXExAPkPx+l05vhqiIiIBg+Xy4WGhgblWRrPsAwwRFnE6XQywCAiIuqDZC0GbPIkIiKijGOAQURERBnHAIOIiIgyjgEGERERZRwDDCIiIso4BhhERESUcQwwiIiIKOMYYBAREVHGMcAgIiKijGOAQURERBnHAIOIiIgyjgEGERERZRwDDCIiIso4BhhERESUcVkNMN5++21cdNFFqK+vh8FgwMsvv5zw+BdffBGf//znUVVVBafTifnz5+O1117THHPXXXfBYDBoPiZNmpTFuyAiIqJ0ZTXA8Hg8mDlzJlatWpXS8W+//TY+//nP49VXX8XmzZtx/vnn46KLLsLWrVs1x02dOhUnT55UPt55551sXD4RERH1kTmbJ7/wwgtx4YUXpnz8ww8/rPn9T37yE/z1r3/F3/72N8yePVv5vNlsRm1tbaYuk4iIaMhx9fqxbnczKots+Oz4ygH//nndgxEKhdDV1YXy8nLN5/fu3Yv6+nqMHTsWV199NY4cOZLwPF6vFy6XS/NBREQ0lB1p7cZ3ntmGFc9ty8n3z+sA4/7774fb7caXvvQl5XPz5s3Dk08+idWrV+M3v/kNDh48iHPOOQddXV1xz3PvvfeipKRE+WhoaBiIyyciIsqZzh4/AKCkwJKT75+3Acaf//xn/Pd//zeee+45VFdXK5+/8MILcfnll2PGjBlYtGgRXn31VXR0dOC5556Le66VK1eis7NT+Th69OhA3AIREVHOdHTLAUZpgTUn3z+rPRh99cwzz+C6667D888/jwULFiQ8trS0FKeffjr27dsX9xibzQabzZbpyyQiIspbIoPhZAZD9pe//AXLli3DX/7yFyxZsiTp8W63G/v370ddXd0AXB0REdHgkOsSSVYzGG63W5NZOHjwILZt24by8nKMHDkSK1euxPHjx/H0008DkMsiX/va1/CLX/wC8+bNQ2NjIwCgoKAAJSUlAIDvf//7uOiiizBq1CicOHECd955J0wmE6666qps3goREdGg0tHjAzBEezA+/PBDzJ49W1liumLFCsyePRt33HEHAODkyZOaFSC/+93vEAgEcNNNN6Gurk75+M53vqMcc+zYMVx11VWYOHEivvSlL6GiogLvv/8+qqqqsnkrREREg4ornMEodQzBDMZ5550HSZLivv7kk09qfr9+/fqk53zmmWf6eVVERERDX65LJHnXg0FERET9xwCDiIiIMk4sUy3JUYmEAQYREdEQxAwGERERZRwDDCIiIsqoYEhCV28AAAMMIiIiyhCxRBVggEFEREQZIsojhVYTLKbcPOoZYBAREQ1Cuxtd2Nfs1n2tI8f9FwADDCIiokHH1evHF1e9h8sffQ+hUOxAS6XB05GbnVQBBhhERESDzicnXOjxB9He7UePPxjzemQFSe42TWeAQURENMjsPulSfu3xBWJez/USVYABBhER0aCz62SX8muPVyeD0Z3bnVQBBhhERESDzu5GVQbDGz+DUcoeDCIiIkpFMCRhT1Mkg9HtS9SDwQwGERERpeBgiwe9/pDye70eDLHRmZMBBhEREaVCXR4BgG69HgxmMIiIiCgdu05qA4yEPRgMMIiIiCgVu1UrSAD9EomLGQwiIiICAEmSdKdyRhMZjLFVhQD0mzw5KpyIiIgAADc/uw3n/Gwdunr9cY/p7PbjRGcvAGDOyDIAsSUSfzCkBB2lDgYYREREw9r6PadwvKMHO4674h6zK9zgOaKsALVOO4DYDEanaqv2YjsDDCIiomFLkiQlE3GioyfucWJE+KRaJxw2E4DYDIZYolpsN8NkNGTjclPCAIOIiCjHfMEQAuH+i0QBhhgRPqWuGIVWeSOz6CbPfFiiCgC522aNiIiIAGj3EznRmSCDES6RTK5z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tm2b8gEADz30EJ544gkAQ+deR48ejfr6+phlgZ9++ilGjRoFYPD9/wrEv9/B8vNJkiQsX74cL730Et58802MGTNG83qmfvbMnz9fcw5xjDjHQMjEvQLAzp07cf755+NrX/safvzjH8d8n5zda1ZbSAeZrq4uaevWrdLWrVslANKDDz4obd26VTp8+LAkSZJ07rnnSlOnTpXWrVsnHThwQHriiScku90u/frXv5YkSZJ8Pp80fvx46ZxzzpE2btwo7du3T7r//vslg8Eg/eMf/1C+z+LFi6XZs2dLGzdulN555x1pwoQJ0lVXXZVX9/rcc89J69atk/bv3y+9/PLL0qhRo6RLL71Uc45vfOMb0siRI6U333xT+vDDD6X58+dL8+fPV14PBALStGnTpIULF0rbtm2TVq9eLVVVVUkrV64cVPfa2dkpzZs3T5o+fbq0b98+6eTJk8pHIBAYUveqB1ErFobSvT700EOS0+mUnn/+eWnv3r3S7bffLtntdmnfvn3KMfnw/6sk9f9+B8vPpxtvvFEqKSmR1q9fr/l/rbu7WzkmEz97Dhw4IDkcDumWW26Rdu3aJa1atUoymUzS6tWrB9W9bt++XaqqqpK+8pWvaM7R3Nyc83tlgKGybt06CUDMx9e+9jVJkiTp5MmT0jXXXCPV19dLdrtdmjhxovTAAw9IoVBIOcenn34qXXrppVJ1dbXkcDikGTNmxCwLa21tla666iqpqKhIcjqd0rJly6Surq6BvNWk9/qLX/xCGjFihGSxWKSRI0dKt99+e8wSxJ6eHumb3/ymVFZWJjkcDumLX/yidPLkSc0xhw4dki688EKpoKBAqqyslL73ve8pSzsHSn/vNd7XA5AOHjw4pO5VT3SAIUlD617vvfdeacSIEZLD4ZDmz58v/etf/9K8ng//v0pSZu53MPx8ivf/2hNPPKEck6mfPevWrZNmzZolWa1WaezYsZrvMRAyca933nmn7jlGjRql+V65uFdu105EREQZxx4MIiIiyjgGGERERJRxDDCIiIgo4xhgEBERUcYxwCAiIqKMY4BBREREGccAg4iIiDKOAQYRERFlHAMMIsoaSZKwYMECLFq0KOa1X//61ygtLcWxY8dycGVElG0MMIgoawwGA5544gls3LgRv/3tb5XPHzx4ELfeeiseeeQRze6RmeD3+zN6PiLqGwYYRJRVDQ0N+MUvfoHvf//7OHjwICRJwrXXXouFCxdi9uzZuPDCC1FUVISamhp89atfRUtLi/K1q1evxtlnn43S0lJUVFTg//2//4f9+/crrx86dAgGgwHPPvsszj33XNjtdvzpT3/KxW0SURTuRUJEA+KSSy5BZ2cnLr30Utxzzz3YuXMnpk6diuuuuw5Lly5FT08PfvCDHyAQCODNN98EALzwwgswGAyYMWMG3G437rjjDhw6dAjbtm2D0WjEoUOHMGbMGIwePRoPPPAAZs+eDbvdjrq6uhzfLRExwCCiAdHc3IypU6eira0NL7zwAnbs2IF//etfeO2115Rjjh07hoaGBuzZswenn356zDlaWlpQVVWF7du3Y9q0aUqA8fDDD+M73/nOQN4OESXBEgkRDYjq6mp8/etfx+TJk3HJJZfgo48+wrp161BUVKR8TJo0CQCUMsjevXtx1VVXYezYsXA6nRg9ejQA4MiRI5pzn3HGGQN6L0SUnDnXF0BEw4fZbIbZLP/YcbvduOiii3DffffFHCdKHBdddBFGjRqFxx57DPX19QiFQpg2bRp8Pp/m+MLCwuxfPBGlhQEGEeXEnDlz8MILL2D06NFK0KHW2tqKPXv24LHHHsM555wDAHjnnXcG+jKJqI9YIiGinLjpppvQ1taGq666Ch988AH279+P1157DcuWLUMwGERZWRkqKirwu9/9Dvv27cObb76JFStW5PqyiShFDDCIKCfq6+vx7rvvIhgMYuHChZg+fTpuvvlmlJaWwmg0wmg04plnnsHmzZsxbdo0fPe738XPf/7zXF82EaWIq0iIiIgo45jBICIiooxjgEFEREQZxwCDiIiIMo4BBhEREWUcAwwiIiLKOAYYRERElHEMMIiIiCjjGGAQERFRxjHAICIiooxjgEFEREQZxwCDiIiIMo4BBhEREWXc/w/CKJ3rDBtuqwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "dat.set_index('Year')['mean'].plot();" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(apply-and-custom-functions)=\n", "### `apply` and custom functions" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In case we need to apply a custom function on each row, or column, we can use the [`.apply`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.apply.html) method combined with a lambda function (see {ref}`lambda-functions`). For example, here is an alternative way to calculate row-wise means, using the `.apply` method and a lambda function. The result is the same as `regions.mean()` (see {ref}`pandas-row-colwise-built-in`):" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "90S-64S -0.074028\n", "64S-44S -0.053681\n", "44S-24S 0.047917\n", "24S-EQU 0.083056\n", "EQU-24N 0.066181\n", "24N-44N 0.052500\n", "44N-64N 0.142500\n", "64N-90N 0.273333\n", "dtype: float64" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "regions.apply(lambda x: x.mean())" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The advantage is that we can use any custom function definition. For example, the following expression calculates whether any region had temperature anomaly above 1 degree, in at least one of the 140 years:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "90S-64S True\n", "64S-44S False\n", "44S-24S False\n", "24S-EQU True\n", "EQU-24N True\n", "24N-44N True\n", "44N-64N True\n", "64N-90N True\n", "dtype: bool" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "regions.apply(lambda x: (x > 1).any(), axis=0)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-b\n", ":class: important\n", "* Function `np.polyfit` can be used to calculate the slope of linear regression between two columns. For example, using the code section shown below, you can find out that the linear trend of temperature in the `'44S-24S'` region was an increasing one, at `0.0066` degrees per year. \n", "* Adapt the code into to the form of a function named `slope` which, given two `Series` objects `x` and `y`, calculates the linear slope. For example, `f(dat['Year'],regions['44S-24S'])` should return `0.0066`.\n", "* Use the `slope` function you defined within the `.apply` method, to calculate the slope in all columns of `regions` at once. \n", "* Hint: you need to keep the `x` argument of `slope` fixed at `dat['Year']`, while the various columns of `regions` are passed to `y`. To do that, write another function (or use a lambda function) that \"wraps\" `slope` and runs it with just the `y` parameter (keeping `x` fixed). \n", "\n", "```py\n", "x = dat['Year']\n", "y = regions['44S-24S']\n", "np.polyfit(x, y, 1)[0]\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-joining-tables)=\n", "## Joining tables" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Overview" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "One of the most common operations when working with data is a *table join*. In a table join, two tables are combined into one, based on one or more common column(s). For example, when compiling a dataset about different cities, we may collect data on different aspects of each city (population size, socio-economic status, built area, etc.) from different sources. To work with these data together, the various tables need to be joined into one. The common column, in this case, would be the city name, or city ID. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "When working with `pandas`, tables can be joined, based on one or more common column, using the [`pd.merge`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.merge.html) function. `pd.merge` has the following important parameters:\n", "\n", "* `left`—The first (\"left\") table\n", "* `right`—The second (\"right\") table\n", "* `how`—The type of join, one of: `'left'`, `'right'`, `'outer'`, `'inner'` (the default), `'cross'`\n", "* `on`—The name(s) of the common column(s) where identical values are considered a \"match\"" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The *type* of join (the `how` parameter) basically determines what should be done with non-matching records. The options are `'left'`, `'right'`, `'outer'`, `'inner'` (the default), and `'cross'`. The meaning of the join types is the same as in SQL [^sql-join-types], and will be demonstrated through examples below. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "[^sql-join-types]: For a visual explanation of join types, see ." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Stations example" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For a first small example, let's get back to the `stations` table:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlat
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284
2DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288\n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284\n", "2 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we have another small table named `status` which describes the status (`'Closed'` or `'Open'`) of select stations:" ] }, { "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", "
namestatus
0Beer-Sheva CenterClosed
1Beer-Sheva UniversityOpen
2Tel-Aviv UniversityOpen
\n", "
" ], "text/plain": [ " name status\n", "0 Beer-Sheva Center Closed\n", "1 Beer-Sheva University Open\n", "2 Tel-Aviv University Open" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "name = pd.Series(['Beer-Sheva Center', 'Beer-Sheva University', 'Tel-Aviv University'])\n", "status = pd.Series(['Closed', 'Open', 'Open'])\n", "status = pd.DataFrame({'name': name, 'status': status})\n", "status" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `stations` and `status` can be joined as follows:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlatstatus
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288Closed
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284Open
\n", "
" ], "text/plain": [ " name city lines piano lon lat \\\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288 \n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284 \n", "\n", " status \n", "0 Closed \n", "1 Open " ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.merge(stations, status)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "This implies the default, `on` being equal to the column(s) sharing the same name in both tables (`on='name'`, in this case), and an `'inner'` join (i.e., `how='inner'`). As you can see, an inner join returns just the matching rows. It is better to be explicit, for clarity:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlatstatus
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288Closed
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284Open
\n", "
" ], "text/plain": [ " name city lines piano lon lat \\\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288 \n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284 \n", "\n", " status \n", "0 Closed \n", "1 Open " ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.merge(stations, status, on='name', how='inner')" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Unlike an `'inner'` join, a `'left'` join returns all records from the first (\"left\") table, even those that have no match in the second (\"right\") table. For example, `'Dimona'` station does not appear in the `status` table, but it is still returned in the result (with `status` set to `np.nan`):" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlatstatus
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288Closed
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284Open
2DimonaDimona1False35.01163531.068616NaN
\n", "
" ], "text/plain": [ " name city lines piano lon lat \\\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288 \n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284 \n", "2 Dimona Dimona 1 False 35.011635 31.068616 \n", "\n", " status \n", "0 Closed \n", "1 Open \n", "2 NaN " ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.merge(stations, status, on='name', how='left')" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "A `'right'` join is the opposite of a `'left'` join, i.e., it returns all records from the \"right\" table, even those that have no match in the \"left\" table. This time, values absent in the \"left\" table are set to `np.nan`:" ] }, { "cell_type": "code", "execution_count": 28, "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", "
namecitylinespianolonlatstatus
0Beer-Sheva CenterBeer-Sheva4.0False34.79844331.243288Closed
1Beer-Sheva UniversityBeer-Sheva5.0True34.81283131.260284Open
2Tel-Aviv UniversityNaNNaNNaNNaNNaNOpen
\n", "
" ], "text/plain": [ " name city lines piano lon lat \\\n", "0 Beer-Sheva Center Beer-Sheva 4.0 False 34.798443 31.243288 \n", "1 Beer-Sheva University Beer-Sheva 5.0 True 34.812831 31.260284 \n", "2 Tel-Aviv University NaN NaN NaN NaN NaN \n", "\n", " status \n", "0 Closed \n", "1 Open \n", "2 Open " ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.merge(stations, status, on='name', how='right')" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Finally, an `'outer'` (also known as \"full\") join returns all record from both tables, regardless of whether they have a matching record in the other table. Values that have no match in both the \"left\" and \"right\" tables are set to `np.nan`:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecitylinespianolonlatstatus
0Beer-Sheva CenterBeer-Sheva4.0False34.79844331.243288Closed
1Beer-Sheva UniversityBeer-Sheva5.0True34.81283131.260284Open
2DimonaDimona1.0False35.01163531.068616NaN
3Tel-Aviv UniversityNaNNaNNaNNaNNaNOpen
\n", "
" ], "text/plain": [ " name city lines piano lon lat \\\n", "0 Beer-Sheva Center Beer-Sheva 4.0 False 34.798443 31.243288 \n", "1 Beer-Sheva University Beer-Sheva 5.0 True 34.812831 31.260284 \n", "2 Dimona Dimona 1.0 False 35.011635 31.068616 \n", "3 Tel-Aviv University NaN NaN NaN NaN NaN \n", "\n", " status \n", "0 Closed \n", "1 Open \n", "2 NaN \n", "3 Open " ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.merge(stations, status, on='name', how='outer')" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "When working with data, we often have one main, or \"template\", table we are working with (\"left\") and we are interested to join data coming from another external (\"right\") table to it. In this scenario we usually prefer not to lose any records from the \"left\" table. Even if some of the records have no match and get \"No Data\" values (namely, `np.nan`), we usually prefer to keep those records and deal with the missing values as necessary, rather than lose the records altogether. Therefore, a `'left'` join is often most useful in data analysis. For example, in the above situation a `'left'` join makes sense if our focus is on the station properties given in `stations`, so even though the `status` of `'Dimona'` is unknown---we prefer to keep the `'Dimona'` station record. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(what-is-gtfs)=\n", "### What is GTFS?" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In the next examples, we demonstrate table join with a more realistic large dataset, namely a [GTFS](https://en.wikipedia.org/wiki/GTFS) public transport dataset. Before we go into the example, we need to be familiar with the GTFS format and structure. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The General Transit Feed Specification (GTFS) is a standard format for describing public transport routes and timetables. GTFS is typically published by government transport agencies, periodically. For example, the GTFS dataset provided as part of the book's sample data was downloaded from Israel ministry of transport [GTFS website](https://www.gov.il/he/departments/general/gtfs_general_transit_feed_specifications) on `2023-09-30`. GTFS data are used by both commercial companies, such as for routing in Google Maps, and in open-source tools. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Technically, a GTFS dataset is a collection of several CSV files (even though their file extension is `.txt`), of specific designation and structure, linked via common columns, or *keys*. In the examples, we are going to use only the six most important files of the GTFS dataset ({numref}`gtfs-files`). Recall that we already met one of the GTFS files, namely `'stops.txt'`, earlier, in an example of text file processing through `for` loops (see {ref}`file-object-and-reading-lines`)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{table} GTFS files used in the examples\n", ":name: gtfs-files\n", "\n", "| Name | Contents | Keys | \n", "|:---:|:---:|:---:|\n", "| `agency.txt` | Agencies | `agency_id` | \n", "| `routes.txt` | Routes | `route_id`, `agency_id` |\n", "| `trips.txt` | Trips | `route_id`, `trip_id`, `shape_id` |\n", "| `stop_times.txt` | Stop times | `trip_id`, `stop_id` | \n", "| `stops.txt` | Stops | `stop_id` | \n", "| `shapes.txt` | Shapes | `shape_id` |\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Let's see what the GTFS tables look like, what is their purpose, and how are they related with one another. To make things easier, we immediately subset the most important columns, which are also the ones we use in subsequent examples." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We start with `'agency.txt'`. This file lists the public transport *agencies*. Each row represents one agency, identified by `'agency_id'` (note that we are using `usecols` to read just the necessary columns from the CSV file):" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
agency_idagency_name
02רכבת ישראל
13אגד
24אלקטרה אפיקים תחבורה
35דן
46ש.א.מ
.........
3151ירושלים-צור באהר איחוד
3291מוניות מטרו קו
3393מוניות מאיה יצחק שדה
3497אודליה מוניות בעמ
3598מוניות רב קווית 4-5
\n", "

36 rows × 2 columns

\n", "
" ], "text/plain": [ " agency_id agency_name\n", "0 2 רכבת ישראל\n", "1 3 אגד\n", "2 4 אלקטרה אפיקים תחבורה\n", "3 5 דן\n", "4 6 ש.א.מ\n", ".. ... ...\n", "31 51 ירושלים-צור באהר איחוד\n", "32 91 מוניות מטרו קו\n", "33 93 מוניות מאיה יצחק שדה\n", "34 97 אודליה מוניות בעמ\n", "35 98 מוניות רב קווית 4-5\n", "\n", "[36 rows x 2 columns]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['agency_id', 'agency_name']\n", "pd.read_csv('data/gtfs/agency.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{note}\n", "`pd.read_csv` uses the `'utf-8'` encoding by default. All sample CSV files in this book are in the UTF-8 encoding, so there is no need to specify the encoding when reading them with `pd.read_csv`. Otherwise, the right encoding can be specified with the `encoding` parameter of `pd.read_csv`.\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The next file we look into is `'routes.txt'`. This file describes the public transport routes, identified by `'route_id'` and also specifying the name of the route: \n", "* `'route_short_name'`—typically a number, such as bus line number \n", "* `'route_long_name'`—the route textual description" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "It also contains `'agency_id'` to identify the agency which operates each route:" ] }, { "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", "
route_idagency_idroute_short_nameroute_long_name
01251ת. רכבת יבנה מערב-יבנה<->ת. רכב...
12251ת. רכבת יבנה מזרח-יבנה<->ת. רכב...
23252ת. רכבת יבנה מערב-יבנה<->ת. רכב...
3425ת. רכבת יבנה מערב-יבנה<->ת. רכב...
45252ת. רכבת יבנה מזרח-יבנה<->ת. רכב...
...............
8183373152NaNתא אוניברסיטה-תל אביב יפו<->באר...
8184373162NaNתא אוניברסיטה-תל אביב יפו<->הרצ...
818537342646גן טכנולוגי-נצרת<->מסרארה חט''ב...
818637343646גן טכנולוגי-נצרת<->מסרארה חט''ב...
8187373502NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה
\n", "

8188 rows × 4 columns

\n", "
" ], "text/plain": [ " route_id agency_id route_short_name route_long_name\n", "0 1 25 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "1 2 25 1 ת. רכבת יבנה מזרח-יבנה<->ת. רכב...\n", "2 3 25 2 ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "3 4 25 2א ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "4 5 25 2 ת. רכבת יבנה מזרח-יבנה<->ת. רכב...\n", "... ... ... ... ...\n", "8183 37315 2 NaN תא אוניברסיטה-תל אביב יפו<->באר...\n", "8184 37316 2 NaN תא אוניברסיטה-תל אביב יפו<->הרצ...\n", "8185 37342 6 46 גן טכנולוגי-נצרת<->מסרארה חט''ב...\n", "8186 37343 6 46 גן טכנולוגי-נצרת<->מסרארה חט''ב...\n", "8187 37350 2 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה\n", "\n", "[8188 rows x 4 columns]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['route_id', 'agency_id', 'route_short_name', 'route_long_name']\n", "pd.read_csv('data/gtfs/routes.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `'routes.txt'` table is linked to the `'trips.txt'` table, which characterizes trips taking place at specific *times of day* for a given route. Trips are uniquely identified by `'trip_id'` and linked with the routes table via the `'route_id'` column. As you can see from the small subset below, each route may be associated with multiple trips. The trips table also has a `'shape_id'` column which associates a trip with the geographical line geometry (see `'shapes.txt'` below). You can see that trips of the same route at different times of day typically follow exactly the same geographical shape, thus having identical `'shape_id'` values, but this is not guaranteed:" ] }, { "cell_type": "code", "execution_count": 32, "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", "
route_idtrip_idshape_id
0603764_081023126055.0
1683143332_011023128020.0
2683143338_011023128020.0
3683244955_011023128020.0
4683244956_011023128020.0
............
398086432827_081023127560.0
3980874317254928_011023127560.0
398088432796_011023127560.0
398089432806_011023127560.0
398090432807_011023127560.0
\n", "

398091 rows × 3 columns

\n", "
" ], "text/plain": [ " route_id trip_id shape_id\n", "0 60 3764_081023 126055.0\n", "1 68 3143332_011023 128020.0\n", "2 68 3143338_011023 128020.0\n", "3 68 3244955_011023 128020.0\n", "4 68 3244956_011023 128020.0\n", "... ... ... ...\n", "398086 43 2827_081023 127560.0\n", "398087 43 17254928_011023 127560.0\n", "398088 43 2796_011023 127560.0\n", "398089 43 2806_011023 127560.0\n", "398090 43 2807_011023 127560.0\n", "\n", "[398091 rows x 3 columns]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['route_id', 'trip_id', 'shape_id']\n", "pd.read_csv('data/gtfs/trips.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `'stop_times.txt'` table lists the stops associated with each trip (via the `'trip_id'` column), including the (scheduled) time of arrival at each stop. The stop times table also includes the `'stop_id'` column to associate it with the stop characteristics (see `'stops.txt'` below). In addition, the `'shape_dist_traveled'` column contains cumulative distance traveled (in $m$) at each stop. You can see the increasing distance traveled from one from stop to another (in the same trip) in the printout below. The `'stop_times.txt'` table is the largest one, in terms of file size, among the GTFS files; keep in mind that it lists all stops, at all times of day, of all public transport routes:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
trip_idarrival_timedeparture_timestop_idshape_dist_traveled
01_01102305:10:0005:10:00387250.0
11_01102305:12:2305:12:2315582714.0
21_01102305:13:2005:13:20155831215.0
31_01102305:14:3105:14:31160861791.0
41_01102305:15:0905:15:09160852152.0
..................
151695249999194_15102320:19:4520:19:45927212666.0
151695259999194_15102320:20:5920:20:591149512970.0
151695269999194_15102320:21:5920:21:59955013237.0
151695279999194_15102320:22:4020:22:401048313395.0
151695289999194_15102320:23:0820:23:081180913597.0
\n", "

15169529 rows × 5 columns

\n", "
" ], "text/plain": [ " trip_id arrival_time departure_time stop_id \\\n", "0 1_011023 05:10:00 05:10:00 38725 \n", "1 1_011023 05:12:23 05:12:23 15582 \n", "2 1_011023 05:13:20 05:13:20 15583 \n", "3 1_011023 05:14:31 05:14:31 16086 \n", "4 1_011023 05:15:09 05:15:09 16085 \n", "... ... ... ... ... \n", "15169524 9999194_151023 20:19:45 20:19:45 9272 \n", "15169525 9999194_151023 20:20:59 20:20:59 11495 \n", "15169526 9999194_151023 20:21:59 20:21:59 9550 \n", "15169527 9999194_151023 20:22:40 20:22:40 10483 \n", "15169528 9999194_151023 20:23:08 20:23:08 11809 \n", "\n", " shape_dist_traveled \n", "0 0.0 \n", "1 714.0 \n", "2 1215.0 \n", "3 1791.0 \n", "4 2152.0 \n", "... ... \n", "15169524 12666.0 \n", "15169525 12970.0 \n", "15169526 13237.0 \n", "15169527 13395.0 \n", "15169528 13597.0 \n", "\n", "[15169529 rows x 5 columns]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['trip_id', 'arrival_time', 'departure_time', 'stop_id', 'shape_dist_traveled']\n", "pd.read_csv('data/gtfs/stop_times.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `'stops.txt'` table, which we already worked with earlier (see {ref}`reading-csv-files`), describes the fixed, i.e., unrelated to time of day, properties of the stops. It is linked with the `'stops_time.txt'` table via the `'stop_id'` column. Stop properties include the stop name (`'stop_name'`), and its coordinates (`'stop_lon'` and `'stop_lat'`):" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
stop_idstop_namestop_latstop_lon
01בי''ס בר לב/בן יהודה32.18398534.917554
12הרצל/צומת בילו31.87003434.819541
23הנחשול/הדייגים31.98455334.782828
34משה פריד/יצחק משקה31.88832534.790700
46ת. מרכזית לוד/הורדה31.95639234.898098
...............
3400250182מסוף שכונת החותרים/הורדה32.74856434.966691
3400350183מסוף שכונת החותרים/איסוף32.74877634.966844
3400450184מדבריום31.26085734.744373
3400550185כביש 25/מדבריום31.26347834.747607
3400650186כביש 25/מדבריום31.26426234.746768
\n", "

34007 rows × 4 columns

\n", "
" ], "text/plain": [ " stop_id stop_name stop_lat stop_lon\n", "0 1 בי''ס בר לב/בן יהודה 32.183985 34.917554\n", "1 2 הרצל/צומת בילו 31.870034 34.819541\n", "2 3 הנחשול/הדייגים 31.984553 34.782828\n", "3 4 משה פריד/יצחק משקה 31.888325 34.790700\n", "4 6 ת. מרכזית לוד/הורדה 31.956392 34.898098\n", "... ... ... ... ...\n", "34002 50182 מסוף שכונת החותרים/הורדה 32.748564 34.966691\n", "34003 50183 מסוף שכונת החותרים/איסוף 32.748776 34.966844\n", "34004 50184 מדבריום 31.260857 34.744373\n", "34005 50185 כביש 25/מדבריום 31.263478 34.747607\n", "34006 50186 כביש 25/מדבריום 31.264262 34.746768\n", "\n", "[34007 rows x 4 columns]" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['stop_id', 'stop_name', 'stop_lat', 'stop_lon']\n", "pd.read_csv('data/gtfs/stops.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Finally, the `'shapes.txt'` table contains the trip geometries. It is linked with the `'trips.txt'` table via the common `'shape_id'` column. " ] }, { "cell_type": "code", "execution_count": 35, "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", "
shape_idshape_pt_latshape_pt_lonshape_pt_sequence
06989532.16472334.8488131
16989532.16473834.8489722
26989532.16477134.8491773
36989532.16484134.8494294
46989532.16488934.8496265
...............
754650914626032.08483134.796385953
754651014626032.08488434.796040954
754651114626032.08490834.795895955
754651214626032.08403934.795698956
754651314626032.08373734.795645957
\n", "

7546514 rows × 4 columns

\n", "
" ], "text/plain": [ " shape_id shape_pt_lat shape_pt_lon shape_pt_sequence\n", "0 69895 32.164723 34.848813 1\n", "1 69895 32.164738 34.848972 2\n", "2 69895 32.164771 34.849177 3\n", "3 69895 32.164841 34.849429 4\n", "4 69895 32.164889 34.849626 5\n", "... ... ... ... ...\n", "7546509 146260 32.084831 34.796385 953\n", "7546510 146260 32.084884 34.796040 954\n", "7546511 146260 32.084908 34.795895 955\n", "7546512 146260 32.084039 34.795698 956\n", "7546513 146260 32.083737 34.795645 957\n", "\n", "[7546514 rows x 4 columns]" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['shape_id', 'shape_pt_lat', 'shape_pt_lon', 'shape_pt_sequence']\n", "pd.read_csv('data/gtfs/shapes.txt', usecols=cols)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The relations between the six above-mentioned files in the GTFS dataset are summarized in {numref}`gtfs-files-drawing`." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{figure} images/gtfs_files_drawing.svg\n", "---\n", "name: gtfs-files-drawing\n", "---\n", "Relation between the six GTFS files listed in {numref}`gtfs-files`\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas2-gtfs-example)=\n", "### GTFS example" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have an idea about the structure and purpose of the GTFS dataset, let's demonstrate join operations between its tables. This is a classical example where joining tables is essential: you cannot go very far with GTFS data analysis, or processing, without joining the various tables together (see {numref}`gtfs-files-drawing`)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To make things simple, in this example, consider just two of the tables in the GTFS dataset:\n", "\n", "* `'agency.txt'`, where rows represent public transport *operators*\n", "* `'routes.txt'`, where rows represent public transport *routes*" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "As shown above (see {ref}`what-is-gtfs`), the two tables share a common column `'agency_id'`, which we can use to join the two, to find out which public routes belong to each operator." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "First, let's import the `'agency.txt'` table and subset the columns of interest, `'agency_id'` and `'agency_name'`:" ] }, { "cell_type": "code", "execution_count": 36, "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", "
agency_idagency_name
02רכבת ישראל
13אגד
24אלקטרה אפיקים תחבורה
35דן
46ש.א.מ
.........
3151ירושלים-צור באהר איחוד
3291מוניות מטרו קו
3393מוניות מאיה יצחק שדה
3497אודליה מוניות בעמ
3598מוניות רב קווית 4-5
\n", "

36 rows × 2 columns

\n", "
" ], "text/plain": [ " agency_id agency_name\n", "0 2 רכבת ישראל\n", "1 3 אגד\n", "2 4 אלקטרה אפיקים תחבורה\n", "3 5 דן\n", "4 6 ש.א.מ\n", ".. ... ...\n", "31 51 ירושלים-צור באהר איחוד\n", "32 91 מוניות מטרו קו\n", "33 93 מוניות מאיה יצחק שדה\n", "34 97 אודליה מוניות בעמ\n", "35 98 מוניות רב קווית 4-5\n", "\n", "[36 rows x 2 columns]" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['agency_id', 'agency_name']\n", "agency = pd.read_csv('data/gtfs/agency.txt', usecols=cols)\n", "agency" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Second, we import the `'routes.txt'` table, this time selecting the `'route_id'`, `'agency_id'`, `'route_short_name'`, and `'route_long_name'` columns. Note the common `'agency_id'` column, which we are going to use when joining the two tables:" ] }, { "cell_type": "code", "execution_count": 37, "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", "
route_idagency_idroute_short_nameroute_long_name
01251ת. רכבת יבנה מערב-יבנה<->ת. רכב...
12251ת. רכבת יבנה מזרח-יבנה<->ת. רכב...
23252ת. רכבת יבנה מערב-יבנה<->ת. רכב...
3425ת. רכבת יבנה מערב-יבנה<->ת. רכב...
45252ת. רכבת יבנה מזרח-יבנה<->ת. רכב...
...............
8183373152NaNתא אוניברסיטה-תל אביב יפו<->באר...
8184373162NaNתא אוניברסיטה-תל אביב יפו<->הרצ...
818537342646גן טכנולוגי-נצרת<->מסרארה חט''ב...
818637343646גן טכנולוגי-נצרת<->מסרארה חט''ב...
8187373502NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה
\n", "

8188 rows × 4 columns

\n", "
" ], "text/plain": [ " route_id agency_id route_short_name route_long_name\n", "0 1 25 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "1 2 25 1 ת. רכבת יבנה מזרח-יבנה<->ת. רכב...\n", "2 3 25 2 ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "3 4 25 2א ת. רכבת יבנה מערב-יבנה<->ת. רכב...\n", "4 5 25 2 ת. רכבת יבנה מזרח-יבנה<->ת. רכב...\n", "... ... ... ... ...\n", "8183 37315 2 NaN תא אוניברסיטה-תל אביב יפו<->באר...\n", "8184 37316 2 NaN תא אוניברסיטה-תל אביב יפו<->הרצ...\n", "8185 37342 6 46 גן טכנולוגי-נצרת<->מסרארה חט''ב...\n", "8186 37343 6 46 גן טכנולוגי-נצרת<->מסרארה חט''ב...\n", "8187 37350 2 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה\n", "\n", "[8188 rows x 4 columns]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cols = ['route_id', 'agency_id', 'route_short_name', 'route_long_name']\n", "routes = pd.read_csv('data/gtfs/routes.txt', usecols=cols)\n", "routes" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now, we can join the `routes` and `agency` tables based on the common `'agency_id'` column:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
route_idagency_idroute_short_nameroute_long_nameagency_name
01251ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
12251ת. רכבת יבנה מזרח-יבנה<->ת. רכב...אלקטרה אפיקים
23252ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
3425ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
45252ת. רכבת יבנה מזרח-יבנה<->ת. רכב...אלקטרה אפיקים
..................
8183373152NaNתא אוניברסיטה-תל אביב יפו<->באר...רכבת ישראל
8184373162NaNתא אוניברסיטה-תל אביב יפו<->הרצ...רכבת ישראל
818537342646גן טכנולוגי-נצרת<->מסרארה חט''ב...ש.א.מ
818637343646גן טכנולוגי-נצרת<->מסרארה חט''ב...ש.א.מ
8187373502NaNבאר שבע מרכז-באר שבע<->נהריה-נהריהרכבת ישראל
\n", "

8188 rows × 5 columns

\n", "
" ], "text/plain": [ " route_id agency_id route_short_name \\\n", "0 1 25 1 \n", "1 2 25 1 \n", "2 3 25 2 \n", "3 4 25 2א \n", "4 5 25 2 \n", "... ... ... ... \n", "8183 37315 2 NaN \n", "8184 37316 2 NaN \n", "8185 37342 6 46 \n", "8186 37343 6 46 \n", "8187 37350 2 NaN \n", "\n", " route_long_name agency_name \n", "0 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "1 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... אלקטרה אפיקים \n", "2 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "3 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "4 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... אלקטרה אפיקים \n", "... ... ... \n", "8183 תא אוניברסיטה-תל אביב יפו<->באר... רכבת ישראל \n", "8184 תא אוניברסיטה-תל אביב יפו<->הרצ... רכבת ישראל \n", "8185 גן טכנולוגי-נצרת<->מסרארה חט''ב... ש.א.מ \n", "8186 גן טכנולוגי-נצרת<->מסרארה חט''ב... ש.א.מ \n", "8187 באר שבע מרכז-באר שבע<->נהריה-נהריה רכבת ישראל \n", "\n", "[8188 rows x 5 columns]" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes = pd.merge(routes, agency, on='agency_id', how='left')\n", "routes" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now we have the additional `'agency_name'` column in the `routes` table, which tells us the name of the operator for each route." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{note}\n", "For more information and examples of `pd.merge`, check out the following official tutorials from the `pandas` documentation: \n", "* [Join tables using a common identifier](https://pandas.pydata.org/pandas-docs/stable/getting_started/intro_tutorials/08_combine_dataframes.html#join-tables-using-a-common-identifier)\n", "* [Database-style `DataFrame` or named `Series` joining/merging](https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html#database-style-dataframe-or-named-series-joining-merging)\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-aggregation)=\n", "## Aggregation" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Overview" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Aggregation is a commonly used to summarize tabular data. In an aggregation procedure, a function is applied on *subsets* of table rows, whereas subsets are specified through one or more grouping variables, to obtain a new (smaller) table with summaries per group. Aggregation is one of the techniques following the [split-apply-combine](https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html) concept." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In `pandas`, there are several different ways of specifying the function(s) to be applied on the table column(s). We will go over three commonly used scenarios:\n", "\n", "* {ref}`aggregation-same-function-on-all-columns`\n", "* {ref}`aggregation-different-functions` on each column\n", "* {ref}`aggregate-custom-functions`" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Afterwards, we are going to introduce a useful shortcut for a particularly common type of aggregation: counting the occurence of each unique value in a column (see {ref}`pandas-value-counts`)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(aggregation-same-function-on-all-columns)=\n", "### Same function on all columns" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For a minimal example of aggregation, let's go back to the small `stations` table:" ] }, { "cell_type": "code", "execution_count": 39, "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", "
namecitylinespianolonlat
0Beer-Sheva CenterBeer-Sheva4False34.79844331.243288
1Beer-Sheva UniversityBeer-Sheva5True34.81283131.260284
2DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " name city lines piano lon lat\n", "0 Beer-Sheva Center Beer-Sheva 4 False 34.798443 31.243288\n", "1 Beer-Sheva University Beer-Sheva 5 True 34.812831 31.260284\n", "2 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Suppose that we are interested in the number of lines (the `lines` column) and the number of stations with a piano (the `piano` column), which involves summing the values in those two columns. We already know how the *totals*, i.e., sums of each column, can be calculated (see {ref}`pandas-row-col-wise-operations`):" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "lines 10\n", "piano 1\n", "dtype: int64" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations[['lines', 'piano']].sum()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "However, what if we wanted to calculate the number of lines and stations with a piano per town, *separately*? To do that, we basically need to *split* the table according to the `'city'` column, then apply the `.sum` method on each subset. Here is how this can be done. Instead of simply using `.sum`, we split (or \"group\") the table by `'city'`, and only then apply the `.sum` method. Splitting is done using the [`.groupby`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) method, which accepts the column name (or `list` of column names) that specifies the grouping:" ] }, { "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", "
linespiano
city
Beer-Sheva91
Dimona10
\n", "
" ], "text/plain": [ " lines piano\n", "city \n", "Beer-Sheva 9 1\n", "Dimona 1 0" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations.groupby('city')[['lines', 'piano']].sum()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that the grouping variable(s) become the *index* of the resulting `DataFrame`. For our purposes, we are usually going to prefer to work with the grouping variable in its own column. In such case, we end the expression with `.reset_index()` (see {ref}`resetting-the-index`):" ] }, { "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", " \n", " \n", " \n", " \n", "
citylinespiano
0Beer-Sheva91
1Dimona10
\n", "
" ], "text/plain": [ " city lines piano\n", "0 Beer-Sheva 9 1\n", "1 Dimona 1 0" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations.groupby('city')[['lines', 'piano']].sum().reset_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{note}\n", "Tables can also be grouped by two or more columns, in which case the column names are passed in a `list`, as in `dat.groupby(['a','b'])`, where `'a'` and `'b'` are column names in `dat`.\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `.sum` method is just one example, there are many other useful functions we can use, such as the ones listed in {numref}`pandas-aggregation-methods`. Additional methods specific to `.groupby` are `.first` and `.last`, to select the first and last row per group. For example, to get the maximum per group we can combine `.groupby` with `.max`:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
citynamelinespianolonlat
0Beer-ShevaBeer-Sheva University5True34.81283131.260284
1DimonaDimona1False35.01163531.068616
\n", "
" ], "text/plain": [ " city name lines piano lon lat\n", "0 Beer-Sheva Beer-Sheva University 5 True 34.812831 31.260284\n", "1 Dimona Dimona 1 False 35.011635 31.068616" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stations.groupby('city').max().reset_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For a more realistic example, consider the `routes` table:" ] }, { "cell_type": "code", "execution_count": 45, "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", "
route_idagency_idroute_short_nameroute_long_nameagency_name
01251ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
12251ת. רכבת יבנה מזרח-יבנה<->ת. רכב...אלקטרה אפיקים
23252ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
3425ת. רכבת יבנה מערב-יבנה<->ת. רכב...אלקטרה אפיקים
45252ת. רכבת יבנה מזרח-יבנה<->ת. רכב...אלקטרה אפיקים
..................
8183373152NaNתא אוניברסיטה-תל אביב יפו<->באר...רכבת ישראל
8184373162NaNתא אוניברסיטה-תל אביב יפו<->הרצ...רכבת ישראל
818537342646גן טכנולוגי-נצרת<->מסרארה חט''ב...ש.א.מ
818637343646גן טכנולוגי-נצרת<->מסרארה חט''ב...ש.א.מ
8187373502NaNבאר שבע מרכז-באר שבע<->נהריה-נהריהרכבת ישראל
\n", "

8188 rows × 5 columns

\n", "
" ], "text/plain": [ " route_id agency_id route_short_name \\\n", "0 1 25 1 \n", "1 2 25 1 \n", "2 3 25 2 \n", "3 4 25 2א \n", "4 5 25 2 \n", "... ... ... ... \n", "8183 37315 2 NaN \n", "8184 37316 2 NaN \n", "8185 37342 6 46 \n", "8186 37343 6 46 \n", "8187 37350 2 NaN \n", "\n", " route_long_name agency_name \n", "0 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "1 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... אלקטרה אפיקים \n", "2 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "3 ת. רכבת יבנה מערב-יבנה<->ת. רכב... אלקטרה אפיקים \n", "4 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... אלקטרה אפיקים \n", "... ... ... \n", "8183 תא אוניברסיטה-תל אביב יפו<->באר... רכבת ישראל \n", "8184 תא אוניברסיטה-תל אביב יפו<->הרצ... רכבת ישראל \n", "8185 גן טכנולוגי-נצרת<->מסרארה חט''ב... ש.א.מ \n", "8186 גן טכנולוגי-נצרת<->מסרארה חט''ב... ש.א.מ \n", "8187 באר שבע מרכז-באר שבע<->נהריה-נהריה רכבת ישראל \n", "\n", "[8188 rows x 5 columns]" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We can use aggregation with the `.nunique` function ({numref}`pandas-aggregation-methods`) to calculate the number of unique route IDs that each public transport agency operates, as follows:" ] }, { "cell_type": "code", "execution_count": 45, "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", "
agency_nameroute_id
0אגד1621
1אודליה מוניות בעמ2
2אלקטרה אפיקים413
3אלקטרה אפיקים תחבורה297
4אקסטרה65
.........
31קווים1161
32רכבת ישראל1008
33ש.א.מ158
34תבל5
35תנופה287
\n", "

36 rows × 2 columns

\n", "
" ], "text/plain": [ " agency_name route_id\n", "0 אגד 1621\n", "1 אודליה מוניות בעמ 2\n", "2 אלקטרה אפיקים 413\n", "3 אלקטרה אפיקים תחבורה 297\n", "4 אקסטרה 65\n", ".. ... ...\n", "31 קווים 1161\n", "32 רכבת ישראל 1008\n", "33 ש.א.מ 158\n", "34 תבל 5\n", "35 תנופה 287\n", "\n", "[36 rows x 2 columns]" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp = routes.groupby('agency_name')['route_id'].nunique().reset_index()\n", "tmp" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To find out which agencies have the most routes, the resulting table can be sorted using `.sort_values` combined with `ascending=False` (see {ref}`pandas-sorting`):" ] }, { "cell_type": "code", "execution_count": 46, "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", "
agency_nameroute_id
0אגד1621
31קווים1161
32רכבת ישראל1008
27מטרופולין691
29נתיב אקספרס577
.........
20כפיר3
21כרמלית2
19כבל אקספרס2
1אודליה מוניות בעמ2
22מוניות מאיה יצחק שדה1
\n", "

36 rows × 2 columns

\n", "
" ], "text/plain": [ " agency_name route_id\n", "0 אגד 1621\n", "31 קווים 1161\n", "32 רכבת ישראל 1008\n", "27 מטרופולין 691\n", "29 נתיב אקספרס 577\n", ".. ... ...\n", "20 כפיר 3\n", "21 כרמלית 2\n", "19 כבל אקספרס 2\n", "1 אודליה מוניות בעמ 2\n", "22 מוניות מאיה יצחק שדה 1\n", "\n", "[36 rows x 2 columns]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp.sort_values('route_id', ascending=False)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-c\n", ":class: important\n", "* Calculate a series of global temperature means for each *decade*, based on the information in `ZonAnn.Ts+dSST.csv`. \n", "* First, you need to create a new variable named `decade` based on the `'Year'`, using an expression such as the one shown below.\n", "* Second, use `.groupby` to calculate the mean global temperature in each decade.\n", "\n", "```py\n", "dat['Year'] // 10 * 10\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-d\n", ":class: important\n", "* The `'routes.txt'` table describes public transport routes (uniquely identified by `route_id`). The `'trips.txt'` table, however, descibes specific journeys of a along those routes, at a specific time of day (uniquely identified by `trip_id`). The two tables are associated with one another via the common `route_id` column (see {ref}`what-is-gtfs`). For example, a route that operates five times a day will be represented in one row in the `'routes.txt'` table, and five rows in the `'trips.txt'` table.\n", "* Join `'routes.txt'` to `'trips.txt'`, using the common `route_id` column.\n", "* Calculate a table with the number of unique `trip_id`'s per `route_id`.\n", "* Sort the table according to number of unique trips, and print a summary with the numbers and names (`route_short_name` and `route_long_name` columns from `routes.txt`, respectively) of the most and least frequent routes ({numref}`exercise-06-c`).\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-c\n", "---\n", "name: exercise-06-c\n", "---\n", "Solution of exercise-06-c\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(aggregation-different-functions)=\n", "### Different functions (`agg`)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes we need to aggregate a `DataFrame` while applying a different function on each column, rather than the same function on all columns. For the next example, consider the `'world_cities.csv'` file, which has information about major cities in the world:" ] }, { "cell_type": "code", "execution_count": 48, "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", "
citycountrypoplatloncapital
0'Abasan al-JadidahPalestine562931.3134.340
1'Abasan al-KabirahPalestine1899931.3234.350
2'Abdul HakimPakistan4778830.5572.110
3'Abdullah-as-SalamKuwait2181729.3647.980
4'AbudPalestine245632.0335.070
.....................
43640az-ZubayrIraq12461130.3947.710
43641az-ZulfiSaudi Arabia5407026.3044.800
43642az-ZuwaytinahLibya2198430.9520.120
43643s-GravenhageNetherlands47952552.074.300
43644s-HertogenboschNetherlands13552951.685.300
\n", "

43645 rows × 6 columns

\n", "
" ], "text/plain": [ " city country pop lat lon capital\n", "0 'Abasan al-Jadidah Palestine 5629 31.31 34.34 0\n", "1 'Abasan al-Kabirah Palestine 18999 31.32 34.35 0\n", "2 'Abdul Hakim Pakistan 47788 30.55 72.11 0\n", "3 'Abdullah-as-Salam Kuwait 21817 29.36 47.98 0\n", "4 'Abud Palestine 2456 32.03 35.07 0\n", "... ... ... ... ... ... ...\n", "43640 az-Zubayr Iraq 124611 30.39 47.71 0\n", "43641 az-Zulfi Saudi Arabia 54070 26.30 44.80 0\n", "43642 az-Zuwaytinah Libya 21984 30.95 20.12 0\n", "43643 s-Gravenhage Netherlands 479525 52.07 4.30 0\n", "43644 s-Hertogenbosch Netherlands 135529 51.68 5.30 0\n", "\n", "[43645 rows x 6 columns]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cities = pd.read_csv('data/world_cities.csv')\n", "cities" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we want to summarize the information per country (`'country'` column). However, we want each column to be treated differently:\n", "\n", "* The city names (`'city'` column) will be *counted* \n", "* Population (`'pop'` column) will be *summed*\n", "* Longitude and latitude (`'lon'` and `'lat'` columns, respectively) will be *averaged*" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "This can be done using the [`.agg`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.agg.html) method applied on a *grouped* `DataFrame` instead of a specific method (such as `.nunique`). The `.agg` method accepts a dictionary, with `key:value` pairs of the form `'column':function`, where: \n", "\n", "* `'column'`—Name of the column to be aggregated\n", "* `function`—The function to apply on each group in that column. This can be:\n", " * a *string* referring to a `pandas` method (such as `'nunique'`, see {numref}`pandas-aggregation-methods`)\n", " * a standalone *function* that can be applied on a `Series`, such as `np.mean` or `np.sum`" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In our case, the aggregation expression is as follows. As a result, we get a new table where each row represents a country, with the count of unique city names, sum of the population across all cities, and average longitute and latitude across all cities:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_55311/2985202954.py:1: FutureWarning: The provided callable is currently using SeriesGroupBy.sum. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string \"sum\" instead.\n", " cities.groupby('country').agg({\n", "/tmp/ipykernel_55311/2985202954.py:1: FutureWarning: The provided callable is currently using SeriesGroupBy.mean. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string \"mean\" instead.\n", " cities.groupby('country').agg({\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countrycitypoplonlat
0Afghanistan115754385666.92034234.807692
1Albania67153623219.97552241.087463
2Algeria315205086423.53544335.467025
3American Samoa3558021-170.663714-14.299143
4Andorra7690311.53857142.534286
..................
234Wallis and Futuna2311380-176.585652-13.512609
235Western Sahara4338786-13.82000025.935000
236Yemen30549207745.08866714.481000
237Zambia73403217028.179315-13.404247
238Zimbabwe76423185930.442500-18.629211
\n", "

239 rows × 5 columns

\n", "
" ], "text/plain": [ " country city pop lon lat\n", "0 Afghanistan 115 7543856 66.920342 34.807692\n", "1 Albania 67 1536232 19.975522 41.087463\n", "2 Algeria 315 20508642 3.535443 35.467025\n", "3 American Samoa 35 58021 -170.663714 -14.299143\n", "4 Andorra 7 69031 1.538571 42.534286\n", ".. ... ... ... ... ...\n", "234 Wallis and Futuna 23 11380 -176.585652 -13.512609\n", "235 Western Sahara 4 338786 -13.820000 25.935000\n", "236 Yemen 30 5492077 45.088667 14.481000\n", "237 Zambia 73 4032170 28.179315 -13.404247\n", "238 Zimbabwe 76 4231859 30.442500 -18.629211\n", "\n", "[239 rows x 5 columns]" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cities.groupby('country').agg({\n", " 'city': 'nunique', \n", " 'pop': np.sum, \n", " 'lon': np.mean, \n", " 'lat': np.mean\n", "}).reset_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(aggregate-custom-functions)=\n", "### Custom functions (`agg`)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Finally, sometimes we need to apply a custom function when aggregating a table. For example, suppose that we need to calculate the population difference between the most populated, and least populated, cities, in each country. To do that, we can define our own function, named `diff_max_min`, which: \n", "\n", "* accepts a `Series` named `x`, and \n", "* returns the difference between the maximum and minimum, `x.max()-x.min()`." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Here is the function definition:" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "def diff_max_min(x):\n", " return x.max() - x.min()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "It is worthwhile to test the function, to make sure it works as expected:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diff_max_min(pd.Series([15, 20, 4, 12, 6]))" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now, we can use the function inside the `.agg` expression, just like any other predefined function:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countrycitypop
0Afghanistan1153117579
1Albania67379803
2Algeria3152024344
3American Samoa3511341
4Andorra717740
............
234Wallis and Futuna231142
235Western Sahara4146906
236Yemen301918607
237Zambia731305210
238Zimbabwe761574930
\n", "

239 rows × 3 columns

\n", "
" ], "text/plain": [ " country city pop\n", "0 Afghanistan 115 3117579\n", "1 Albania 67 379803\n", "2 Algeria 315 2024344\n", "3 American Samoa 35 11341\n", "4 Andorra 7 17740\n", ".. ... ... ...\n", "234 Wallis and Futuna 23 1142\n", "235 Western Sahara 4 146906\n", "236 Yemen 30 1918607\n", "237 Zambia 73 1305210\n", "238 Zimbabwe 76 1574930\n", "\n", "[239 rows x 3 columns]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cities.groupby('country').agg({\n", " 'city': 'nunique', \n", " 'pop': diff_max_min\n", "}).reset_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For example, here is how the \"new\" pop value is obtained for the first country (`'Afghanistan'`):" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3117579" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diff_max_min(cities[cities['country'] == 'Afghanistan']['pop'])" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we can use a lambda function (see {ref}`lambda-functions`), to do the same, using more concise syntax:" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countrycitypop
0Afghanistan1153117579
1Albania67379803
2Algeria3152024344
3American Samoa3511341
4Andorra717740
............
234Wallis and Futuna231142
235Western Sahara4146906
236Yemen301918607
237Zambia731305210
238Zimbabwe761574930
\n", "

239 rows × 3 columns

\n", "
" ], "text/plain": [ " country city pop\n", "0 Afghanistan 115 3117579\n", "1 Albania 67 379803\n", "2 Algeria 315 2024344\n", "3 American Samoa 35 11341\n", "4 Andorra 7 17740\n", ".. ... ... ...\n", "234 Wallis and Futuna 23 1142\n", "235 Western Sahara 4 146906\n", "236 Yemen 30 1918607\n", "237 Zambia 73 1305210\n", "238 Zimbabwe 76 1574930\n", "\n", "[239 rows x 3 columns]" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cities.groupby('country').agg({\n", " 'city': 'nunique', \n", " 'pop': lambda x: x.max() - x.min()\n", "}).reset_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{note}\n", "For more information and examples on aggregation, and other types of split-apply-combine operations which we have not mentioned, see .\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(pandas-value-counts)=\n", "## Value counts" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "A very common type of aggregation is to calculate how many times each unique value is \"repeated\" in a `Series`. For example, recall the way that we calculated the number of unique routes per agency:" ] }, { "cell_type": "code", "execution_count": 47, "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", "
agency_nameroute_id
0אגד1621
31קווים1161
32רכבת ישראל1008
27מטרופולין691
29נתיב אקספרס577
.........
20כפיר3
21כרמלית2
19כבל אקספרס2
1אודליה מוניות בעמ2
22מוניות מאיה יצחק שדה1
\n", "

36 rows × 2 columns

\n", "
" ], "text/plain": [ " agency_name route_id\n", "0 אגד 1621\n", "31 קווים 1161\n", "32 רכבת ישראל 1008\n", "27 מטרופולין 691\n", "29 נתיב אקספרס 577\n", ".. ... ...\n", "20 כפיר 3\n", "21 כרמלית 2\n", "19 כבל אקספרס 2\n", "1 אודליה מוניות בעמ 2\n", "22 מוניות מאיה יצחק שדה 1\n", "\n", "[36 rows x 2 columns]" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes \\\n", " .groupby('agency_name')['route_id'] \\\n", " .nunique() \\\n", " .reset_index() \\\n", " .sort_values('route_id', ascending=False)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The [`.value_counts`](https://pandas.pydata.org/docs/reference/api/pandas.Series.value_counts.html) method which can be thought of as a shortcut (assuming that all `route_id` values are unique, which is true in this case):" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "agency_name \n", "אגד 1621\n", "קווים 1161\n", "רכבת ישראל 1008\n", "מטרופולין 691\n", "נתיב אקספרס 577\n", " ... \n", "כפיר 3\n", "כרמלית 2\n", "כבל אקספרס 2\n", "אודליה מוניות בעמ 2\n", "מוניות מאיה יצחק שדה 1\n", "Name: count, Length: 36, dtype: int64" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes[['agency_name']].value_counts()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The result is a `Series` where the index is the agency name, and the values are the counts. It tells us how many rows are there in the `routes` table, for each agency. For example, `'אגד'` is repeated over `1621` rows." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, the resuling `Series` is sorted by count, from highest to lowest. In case we need to sort by index, i.e., by agency name, we can use the [`.sort_index`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html) method:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "agency_name \n", "אגד 1621\n", "אודליה מוניות בעמ 2\n", "אלקטרה אפיקים 413\n", "אלקטרה אפיקים תחבורה 297\n", "אקסטרה 65\n", " ... \n", "קווים 1161\n", "רכבת ישראל 1008\n", "ש.א.מ 158\n", "תבל 5\n", "תנופה 287\n", "Name: count, Length: 36, dtype: int64" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes[['agency_name']].value_counts().sort_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-e\n", ":class: important\n", "* How often is there more than one shape (`shape_id`) for the same route (`route_id`)? \n", "* Use the `'trips.txt'` table to calculate the number of unique values of `shape_id` for each `route_id`.\n", "* Summarize the resulting column to calculate how many `route_id`s has `0`, `1`, `2`, etc. of `shape_id`.\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(exercise-pandas2)=\n", "## More exercises" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-f\n", ":class: important\n", "* Read the `'agency.txt'`, `'routes.txt'`, `'trips.txt'`, and `'shapes.txt'` tables (located in the `gtfs` directory).\n", "* Subset just the `'דן באר שבע'` operator routes from the `routes` table (first find out its `agency_id` in the `agency` table)\n", "* Subset only those `routes` where `'route_short_name'` is `'24'` (i.e., routes of bus `'24'`)\n", "* Join the routes table with `trips` and filter to retain just one trip (the first `trip_id`)\n", "* Join the trip table with `shapes`\n", "* Print the resulting table with the shape coordinates of one of the trips of bus `'24'` ({numref}`exercise-06-f1`)\n", "* Create a scatterplot of the trip coordinates, with `'shape_pt_lon'` values on the x-axis and `'shape_pt_lat'` values on the y-axis ({numref}`exercise-06-f2`)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-f1\n", "---\n", "name: exercise-06-f1\n", "---\n", "Solution of exercise-06-f: Coordinates of the 1st trip of bus `'24'` by ``'דן באר שבע'``\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-f2\n", "---\n", "name: exercise-06-f2\n", "---\n", "Solution of exercise-06-f: Coordinates of the 1st trip of bus `'24'` by ``'דן באר שבע'``\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Exercise 06-g\n", ":class: important\n", "* In this exercise, you are going to find the names of the five longest bus routes (in terms of distance traveled) in Israel. To do that, go through the following steps.\n", "* Read the `stop_times.txt` table and select just the `'trip_id'` and `'shape_dist_traveled'` columns. \n", "* Calculate the maximum (i.e., total) distance traveled (`'shape_dist_traveled'`) for each public transit trip (`'trip_id'`) ({numref}`exercise-06-g1`).\n", "* Read the `trips.txt` table and select just the `'trip_id'`, and `'route_id'`.\n", "* Join the resulting `trips` table with the `stop_times` table from the previous step (using the common `\"trip_id\"` column), to get the `'route_id'` value of each trip.\n", "* Retain just one (the first) trip per `'route_id'` ({numref}`exercise-06-g2`).\n", "* Read the `routes.txt` table and subset the `'route_id'`, `'route_short_name'`, and `'route_long_name'` columns.\n", "* Join the resulting table with the trips table (using the common `'route_id'` column), to get the `'route_short_name'` and `'route_long_name'` values of each route ({numref}`exercise-06-g3`).\n", "* Sort the table according to `'shape_dist_traveled'` (from largest to smallest), and print the first five rows ({numref}`exercise-06-g4`). Those are the longest-distance public transport routes in the GTFS dataset.\n", "* Convert the `'route_long_name'` values of the first five rows from the previous step, collect them into a `list`, and print the `list`, to see the full names of the routes. You can see that all five routes are from Haifa to Eilat or the other way around.\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-g1\n", "---\n", "name: exercise-06-g1\n", "---\n", "Solution of exercise-06-g: Total distance traveled in each trip, based on `stop_times.txt`\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-g2\n", "---\n", "name: exercise-06-g2\n", "---\n", "Solution of exercise-06-g: Joined with `trips.txt`, selecting just the 1st trips per `route_id`\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-g3\n", "---\n", "name: exercise-06-g3\n", "---\n", "Solution of exercise-06-g: Joined with `routes.txt`\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```{glue:figure} exercise-06-g4\n", "---\n", "name: exercise-06-g4\n", "---\n", "Solution of exercise-06-g: Sorted by `shape_dist_traveled`, from largest to smallest\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise solutions" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "from myst_nb import glue" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 06-b" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/plain": [ "0.006830158347399733" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "# Read data\n", "dat = pd.read_csv('data/ZonAnn.Ts+dSST.csv')\n", "cols = ['90S-64S', '64S-44S', '44S-24S', '24S-EQU', 'EQU-24N', '24N-44N', '44N-64N', '64N-90N']\n", "regions = dat[cols]\n", "# Function to calculate linear slope\n", "def f(x, y): \n", " return np.polyfit(x, y, 1)[0]\n", "f(dat['Year'], regions['44S-24S'])" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/plain": [ "90S-64S 0.006262\n", "64S-44S 0.005188\n", "44S-24S 0.006830\n", "24S-EQU 0.006690\n", "EQU-24N 0.006562\n", "24N-44N 0.008564\n", "44N-64N 0.012204\n", "64N-90N 0.018884\n", "dtype: float64" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Calculate slopes per region\n", "regions.apply(lambda i: f(dat['Year'], i), axis=0)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 06-d" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "tags": [ "remove-output" ] }, "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", "
route_idroute_short_nameroute_long_nametrip_id
2837116851ת. מרכזית חוף הכרמל/רציפים עירו...1344
2839116891מרכזית הקריות-קרית מוצקין<->ת. ...1300
64642960210מרכזית המפרץ-חיפה<->אוניברסיטת ...1201
64652960310אוניברסיטת חיפה-חיפה<->מרכזית ה...1201
31921240515תחנה תפעולית/ביטוח לאומי-ירושלי...978
...............
27201141189פרי מגדים/חוט השני-מעלה אדומים<...1
27191141089דרך צמח השדה/העירית-מעלה אדומים...1
27171140888דרך צמח השדה/העירית-מעלה אדומים...1
565123676303הרב שלום שבזי/שילה-ראש העין<->י...1
35901505391מעונות הסטודנטים/הנשיא-צפת<->הא...1
\n", "

7180 rows × 4 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name trip_id\n", "2837 11685 1 ת. מרכזית חוף הכרמל/רציפים עירו... 1344\n", "2839 11689 1 מרכזית הקריות-קרית מוצקין<->ת. ... 1300\n", "6464 29602 10 מרכזית המפרץ-חיפה<->אוניברסיטת ... 1201\n", "6465 29603 10 אוניברסיטת חיפה-חיפה<->מרכזית ה... 1201\n", "3192 12405 15 תחנה תפעולית/ביטוח לאומי-ירושלי... 978\n", "... ... ... ... ...\n", "2720 11411 89 פרי מגדים/חוט השני-מעלה אדומים<... 1\n", "2719 11410 89 דרך צמח השדה/העירית-מעלה אדומים... 1\n", "2717 11408 88 דרך צמח השדה/העירית-מעלה אדומים... 1\n", "5651 23676 303 הרב שלום שבזי/שילה-ראש העין<->י... 1\n", "3590 15053 91 מעונות הסטודנטים/הנשיא-צפת<->הא... 1\n", "\n", "[7180 rows x 4 columns]" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "# Read\n", "routes = pd.read_csv('data/gtfs/routes.txt')\n", "trips = pd.read_csv('data/gtfs/trips.txt')\n", "# Join\n", "dat = pd.merge(trips, routes, on='route_id', how='left')\n", "# Calculate number of unique trips per route\n", "dat = dat.groupby(['route_id', 'route_short_name', 'route_long_name']).nunique()['trip_id'].reset_index()\n", "# Sort\n", "dat = dat.sort_values('trip_id', ascending=False)\n", "dat" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "tags": [ "remove-cell" ] }, "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", "
route_idroute_short_nameroute_long_nametrip_id
2837116851ת. מרכזית חוף הכרמל/רציפים עירו...1344
2839116891מרכזית הקריות-קרית מוצקין<->ת. ...1300
64642960210מרכזית המפרץ-חיפה<->אוניברסיטת ...1201
64652960310אוניברסיטת חיפה-חיפה<->מרכזית ה...1201
31921240515תחנה תפעולית/ביטוח לאומי-ירושלי...978
...............
27201141189פרי מגדים/חוט השני-מעלה אדומים<...1
27191141089דרך צמח השדה/העירית-מעלה אדומים...1
27171140888דרך צמח השדה/העירית-מעלה אדומים...1
565123676303הרב שלום שבזי/שילה-ראש העין<->י...1
35901505391מעונות הסטודנטים/הנשיא-צפת<->הא...1
\n", "

7180 rows × 4 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name trip_id\n", "2837 11685 1 ת. מרכזית חוף הכרמל/רציפים עירו... 1344\n", "2839 11689 1 מרכזית הקריות-קרית מוצקין<->ת. ... 1300\n", "6464 29602 10 מרכזית המפרץ-חיפה<->אוניברסיטת ... 1201\n", "6465 29603 10 אוניברסיטת חיפה-חיפה<->מרכזית ה... 1201\n", "3192 12405 15 תחנה תפעולית/ביטוח לאומי-ירושלי... 978\n", "... ... ... ... ...\n", "2720 11411 89 פרי מגדים/חוט השני-מעלה אדומים<... 1\n", "2719 11410 89 דרך צמח השדה/העירית-מעלה אדומים... 1\n", "2717 11408 88 דרך צמח השדה/העירית-מעלה אדומים... 1\n", "5651 23676 303 הרב שלום שבזי/שילה-ראש העין<->י... 1\n", "3590 15053 91 מעונות הסטודנטים/הנשיא-צפת<->הא... 1\n", "\n", "[7180 rows x 4 columns]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-c" } }, "output_type": "display_data" } ], "source": [ "glue('exercise-06-c', dat)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 06-e" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "tags": [ "remove-output" ] }, "outputs": [ { "data": { "text/plain": [ "shape_id\n", "0 1008\n", "1 7016\n", "2 164\n", "Name: count, dtype: int64" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "trips = pd.read_csv('data/gtfs/trips.txt')\n", "trips.groupby('route_id')['shape_id'].nunique().value_counts().sort_index()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "(exercise-06-f)=\n", "### Exercise 06-f" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
route_idroute_short_nameroute_long_nametrip_idshape_idshape_pt_sequenceshape_pt_lonshape_pt_lat
01753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0134.79797931.242009
11753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0234.79798831.242103
21753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0334.79798231.242829
31753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0434.79798631.242980
41753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0534.79800031.243121
...........................
8561753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.085734.82216631.280183
8571753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.085834.82211631.280225
8581753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.085934.82203831.280246
8591753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.086034.82194931.280250
8601753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.086134.82186031.280233
\n", "

861 rows × 8 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "0 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "1 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "2 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "3 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "4 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", ".. ... ... ... \n", "856 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "857 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "858 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "859 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "860 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "\n", " trip_id shape_id shape_pt_sequence shape_pt_lon shape_pt_lat \n", "0 26385618_011023 136236.0 1 34.797979 31.242009 \n", "1 26385618_011023 136236.0 2 34.797988 31.242103 \n", "2 26385618_011023 136236.0 3 34.797982 31.242829 \n", "3 26385618_011023 136236.0 4 34.797986 31.242980 \n", "4 26385618_011023 136236.0 5 34.798000 31.243121 \n", ".. ... ... ... ... ... \n", "856 26385618_011023 136236.0 857 34.822166 31.280183 \n", "857 26385618_011023 136236.0 858 34.822116 31.280225 \n", "858 26385618_011023 136236.0 859 34.822038 31.280246 \n", "859 26385618_011023 136236.0 860 34.821949 31.280250 \n", "860 26385618_011023 136236.0 861 34.821860 31.280233 \n", "\n", "[861 rows x 8 columns]" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "# Read\n", "agency = pd.read_csv('data/gtfs/agency.txt')\n", "routes = pd.read_csv('data/gtfs/routes.txt')\n", "trips = pd.read_csv('data/gtfs/trips.txt')\n", "shapes = pd.read_csv('data/gtfs/shapes.txt')\n", "# Subset\n", "agency = agency[['agency_id', 'agency_name']]\n", "routes = routes[['route_id', 'agency_id', 'route_short_name', 'route_long_name']]\n", "trips = trips[['trip_id', 'route_id', 'shape_id']]\n", "shapes = shapes[['shape_id', 'shape_pt_sequence', 'shape_pt_lon', 'shape_pt_lat']]\n", "# Filter agency\n", "agency = agency[agency['agency_name'] == 'דן באר שבע']\n", "routes = routes[routes['agency_id'] == agency['agency_id'].iloc[0]]\n", "routes = routes.drop('agency_id', axis=1)\n", "# Filter route\n", "routes = routes[routes['route_short_name'] == '24']\n", "# Filter trip\n", "routes = pd.merge(routes, trips, on='route_id', how='left')\n", "trip = routes[routes['trip_id'] == routes['trip_id'].iloc[0]]\n", "# Join with 'shapes'\n", "trip = pd.merge(trip, shapes, on='shape_id', how='left')\n", "trip = trip.sort_values(by='shape_pt_sequence')\n", "trip" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "tags": [ "remove-cell" ] }, "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", "
route_idroute_short_nameroute_long_nametrip_idshape_id
01753724ת.מרכזית/עירוניים לצפון-באר שבע...26385618_011023136236.0
11753724ת.מרכזית/עירוניים לצפון-באר שבע...26385620_011023136236.0
21753724ת.מרכזית/עירוניים לצפון-באר שבע...25887153_011023136236.0
31753724ת.מרכזית/עירוניים לצפון-באר שבע...29025527_011023136236.0
41753724ת.מרכזית/עירוניים לצפון-באר שבע...25887168_011023136236.0
..................
1421753824מסוף רמות-באר שבע<->ת.מרכזית/עי...22834961_011023127348.0
1431753824מסוף רמות-באר שבע<->ת.מרכזית/עי...22834957_011023127348.0
1441753824מסוף רמות-באר שבע<->ת.מרכזית/עי...26385928_011023127348.0
1451753824מסוף רמות-באר שבע<->ת.מרכזית/עי...26385947_011023127348.0
1461753824מסוף רמות-באר שבע<->ת.מרכזית/עי...26385948_011023127348.0
\n", "

147 rows × 5 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "0 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "1 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "2 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "3 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", "4 17537 24 ת.מרכזית/עירוניים לצפון-באר שבע... \n", ".. ... ... ... \n", "142 17538 24 מסוף רמות-באר שבע<->ת.מרכזית/עי... \n", "143 17538 24 מסוף רמות-באר שבע<->ת.מרכזית/עי... \n", "144 17538 24 מסוף רמות-באר שבע<->ת.מרכזית/עי... \n", "145 17538 24 מסוף רמות-באר שבע<->ת.מרכזית/עי... \n", "146 17538 24 מסוף רמות-באר שבע<->ת.מרכזית/עי... \n", "\n", " trip_id shape_id \n", "0 26385618_011023 136236.0 \n", "1 26385620_011023 136236.0 \n", "2 25887153_011023 136236.0 \n", "3 29025527_011023 136236.0 \n", "4 25887168_011023 136236.0 \n", ".. ... ... \n", "142 22834961_011023 127348.0 \n", "143 22834957_011023 127348.0 \n", "144 26385928_011023 127348.0 \n", "145 26385947_011023 127348.0 \n", "146 26385948_011023 127348.0 \n", "\n", "[147 rows x 5 columns]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-f1" } }, "output_type": "display_data" } ], "source": [ "glue('exercise-06-f1', routes)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "image/png": "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j86dO2P37t1qrdOA/XxGGMXWSclRLF68WMjIyBCKi4uFc+fOCYsXLxYkEonw/fffa7weGvob+/bt2+4vmOrqasHDw0NYs2aNxnJWrVolnD59WsjLyxM++OADoWvXrmp97MqpZuPHjxdycnKEffv2CYGBgRabamav92H37t3Cf/7zH+H8+fNCfn6+8OGHHwoeHh7Cq6++at4b1sIS9+GBBx4Q+vfvL6SlpQlFRUXChg0bhC5duqiNI3j22WeFkJAQ4dChQ0JWVpYQHx8vxMfHq85b+/dBEOz3XnSU34kbN24I2dnZwn/+8x8BgHD48GEhOztbqKioUF0zceJEITY2Vjh58qRw5MgRISoqymLTk+31Phw7dkx49913hZycHKGwsFD47LPPhMDAQCE5OVn8myDY5j5UV1cLw4YNEwYOHCgUFBSoTcO+e/euIAi2+YwwF4OKgf70pz8JoaGhQufOnYXAwEBh7NixWn/hBEHzLx3+t6ZDax999JHQtWtXoaqqSmM5f/zjHwU/Pz+hc+fOQkxMjLB58+Z215SUlAiTJk0SunbtKgQEBAgLFy5UTUUTm73eh7179wr33Xef4OXlJXh6egqDBg0S1q5dqzalWUyWuA83btwQnnzySaFHjx5Cly5dhL59+worV64UmpubVdfcvn1beP755wVfX1/Bw8NDmD59unDjxg21cq35+yAI9nsvOsrvxGuvvSYAaPfTupyKigphxowZgpeXlyCVSoVZs2YJt27dEuutq7HX+3D69Glh2LBhgkwmE7p06SL069dPeOuttyzWDWiL+6Ds9tL0U1xcrCrH2p8R5pIIghXm6hERERGZgGNUiIiIyG4xqBAREZHdYlAhIiIiu8WgQkRERHaLQYWIiIjsFoMKERER2S0GFSIiIrJbDCpEZLYnn3wS06ZNs3U1bOL111/HfffdZ+tqEDktBhUiolYkEgm+/vprW1eDiP6HQYWIiIjsFoMKERlsx44dGDhwILp27Qp/f388+OCDqKurU51fsWIFunfvDn9/f8yZMweNjY2qc59++imGDBkCb29v3HPPPXj88cfVdnBNT0+HRCLBt99+i5iYGHTp0gXDhw9Hbm6uWh2OHDmCUaNGoWvXrggODsb8+fPV6qBLWFgY/v73v2PGjBnw9PREz549sXr1arXzADB9+nRIJBLVY2M0NzfjzTffRK9eveDu7o777rsP+/btU50vKSmBRCLBV199hdGjR8PDwwODBg3C8ePHjX4too6AQYWIDHLjxg3MmDEDf/rTn3Dp0iWkp6fjkUcegXK7sLS0NBQWFiItLQ2bNm3Cxo0bsXHjRtXzGxsb8fe//x1nz57F119/jZKSEjz55JPtXufll1/GypUrkZmZicDAQEyZMkUVeAoLCzFx4kQ8+uijOHfuHL744gscOXIEc+fONfh9vPPOOxg0aBCys7OxePFivPDCCzhw4AAAIDMzEwCwYcMG3LhxQ/XYGO+99x5WrlyJFStW4Ny5c5gwYQIefvhh5Ofnq13317/+FYsWLUJOTg769OmDGTNm4O7du0a/HpHTs/GmiETkIE6fPi0AEEpKStqdmzlzphAaGqraSl4QBOGxxx4Tfv/732stLzMzUwCg2sVXufPrtm3bVNdUVFQIXbt2Fb744gtBEAQhJSVFePrpp9XK+eGHHwQXFxfh9u3bet9DaGioMHHiRLVjv//974VJkyapHkPDLra6vPbaa8KgQYNUj3v06CEsW7ZM7Zq4uDjh+eefFwRBEIqLiwUAwrp161TnL1y4IAAQLl26ZPDrEnUUbFEhIoMMGjQIY8eOxcCBA/HYY4/hP//5DyorK1Xn+/fvD1dXV9Xj7t27q3XtnD59GlOmTEFISAi8vb3xwAMPAACuXLmi9jrx8fGq//bz80Pfvn1x6dIlAMDZs2exceNGeHl5qX4mTJiA5uZmFBcXG/Q+WpevfKws31w1NTW4fv06EhIS1I4nJCS0e42YmBjVf3fv3h0A1O4XEbVgUCEig7i6uuLAgQPYu3cvoqOjsWrVKvTt21cVENzc3NSul0gkaG5uBgDU1dVhwoQJkEql+Pzzz5GZmYmdO3cCABoaGgyuQ21tLZ555hnk5OSofs6ePYv8/Hz07t1bpHdqHa3vl0QiAQDV/SKiX3WydQWIyHFIJBIkJCQgISEBr776KkJDQ1WBQ5cff/wRFRUVWL58OYKDgwEAWVlZGq89ceIEQkJCAACVlZX46aef0K9fPwDA/fffj4sXLyIyMtLk93DixIl2j5XlAy0BoqmpyaSypVIpevTogaNHj6pajADg6NGjGDp0qGkVJurgGFSIyCAnT57EwYMHMX78eAQFBeHkyZOQy+Xo168fzp07p/O5ISEh6Ny5M1atWoVnn30Wubm5+Pvf/67x2jfffBP+/v7o1q0b/vrXvyIgIEC1mNxf/vIXDB8+HHPnzsVTTz0FT09PXLx4EQcOHMAHH3xg0Ps4evQo3n77bUybNg0HDhzA9u3b8e2336rOh4WF4eDBg0hISIC7uzt8fX0Nu0H/8/LLL+O1115D7969cd9992HDhg3IycnB559/blQ5RNSCXT9EZBCpVIrDhw/joYceQp8+ffDKK69g5cqVmDRpkt7nBgYGYuPGjdi+fTuio6OxfPlyrFixQuO1y5cvxwsvvIDBgwejtLQU33zzDTp37gygZVxHRkYGfvrpJ4waNQqxsbF49dVX0aNHD4Pfx8KFC5GVlYXY2Fj84x//wL/+9S9MmDBBdX7lypU4cOAAgoODERsba3C5SvPnz8dLL72EhQsXYuDAgdi3bx92796NqKgoo8siIkAiCP+bW0hEZEPp6ekYPXo0Kisr4ePjY5HXCAsLw4IFC7BgwQKLlE9E4mOLChEREdktBhUicgo//PCD2rTltj+m6t+/v9YyOe6EyPLY9UNETuH27du4du2a1vOmzhS6fPmy2lYArXXr1g3e3t4mlUtEhmFQISIiIrvFrh8iIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdmt/w+Z4VZfonV5rwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "trip.plot.scatter(x='shape_pt_lon', y='shape_pt_lat');" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [ { "data": { "application/papermill.record/image/png": "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j86dO2P37t1qrdOA/XxGGMXWSclRLF68WMjIyBCKi4uFc+fOCYsXLxYkEonw/fffa7weGvob+/bt2+4vmOrqasHDw0NYs2aNxnJWrVolnD59WsjLyxM++OADoWvXrmp97MqpZuPHjxdycnKEffv2CYGBgRabamav92H37t3Cf/7zH+H8+fNCfn6+8OGHHwoeHh7Cq6++at4b1sIS9+GBBx4Q+vfvL6SlpQlFRUXChg0bhC5duqiNI3j22WeFkJAQ4dChQ0JWVpYQHx8vxMfHq85b+/dBEOz3XnSU34kbN24I2dnZwn/+8x8BgHD48GEhOztbqKioUF0zceJEITY2Vjh58qRw5MgRISoqymLTk+31Phw7dkx49913hZycHKGwsFD47LPPhMDAQCE5OVn8myDY5j5UV1cLw4YNEwYOHCgUFBSoTcO+e/euIAi2+YwwF4OKgf70pz8JoaGhQufOnYXAwEBh7NixWn/hBEHzLx3+t6ZDax999JHQtWtXoaqqSmM5f/zjHwU/Pz+hc+fOQkxMjLB58+Z215SUlAiTJk0SunbtKgQEBAgLFy5UTUUTm73eh7179wr33Xef4OXlJXh6egqDBg0S1q5dqzalWUyWuA83btwQnnzySaFHjx5Cly5dhL59+worV64UmpubVdfcvn1beP755wVfX1/Bw8NDmD59unDjxg21cq35+yAI9nsvOsrvxGuvvSYAaPfTupyKigphxowZgpeXlyCVSoVZs2YJt27dEuutq7HX+3D69Glh2LBhgkwmE7p06SL069dPeOuttyzWDWiL+6Ds9tL0U1xcrCrH2p8R5pIIghXm6hERERGZgGNUiIiIyG4xqBAREZHdYlAhIiIiu8WgQkRERHaLQYWIiIjsFoMKERER2S0GFSIiIrJbDCpEZLYnn3wS06ZNs3U1bOL111/HfffdZ+tqEDktBhUiolYkEgm+/vprW1eDiP6HQYWIiIjsFoMKERlsx44dGDhwILp27Qp/f388+OCDqKurU51fsWIFunfvDn9/f8yZMweNjY2qc59++imGDBkCb29v3HPPPXj88cfVdnBNT0+HRCLBt99+i5iYGHTp0gXDhw9Hbm6uWh2OHDmCUaNGoWvXrggODsb8+fPV6qBLWFgY/v73v2PGjBnw9PREz549sXr1arXzADB9+nRIJBLVY2M0NzfjzTffRK9eveDu7o777rsP+/btU50vKSmBRCLBV199hdGjR8PDwwODBg3C8ePHjX4too6AQYWIDHLjxg3MmDEDf/rTn3Dp0iWkp6fjkUcegXK7sLS0NBQWFiItLQ2bNm3Cxo0bsXHjRtXzGxsb8fe//x1nz57F119/jZKSEjz55JPtXufll1/GypUrkZmZicDAQEyZMkUVeAoLCzFx4kQ8+uijOHfuHL744gscOXIEc+fONfh9vPPOOxg0aBCys7OxePFivPDCCzhw4AAAIDMzEwCwYcMG3LhxQ/XYGO+99x5WrlyJFStW4Ny5c5gwYQIefvhh5Ofnq13317/+FYsWLUJOTg769OmDGTNm4O7du0a/HpHTs/GmiETkIE6fPi0AEEpKStqdmzlzphAaGqraSl4QBOGxxx4Tfv/732stLzMzUwCg2sVXufPrtm3bVNdUVFQIXbt2Fb744gtBEAQhJSVFePrpp9XK+eGHHwQXFxfh9u3bet9DaGioMHHiRLVjv//974VJkyapHkPDLra6vPbaa8KgQYNUj3v06CEsW7ZM7Zq4uDjh+eefFwRBEIqLiwUAwrp161TnL1y4IAAQLl26ZPDrEnUUbFEhIoMMGjQIY8eOxcCBA/HYY4/hP//5DyorK1Xn+/fvD1dXV9Xj7t27q3XtnD59GlOmTEFISAi8vb3xwAMPAACuXLmi9jrx8fGq//bz80Pfvn1x6dIlAMDZs2exceNGeHl5qX4mTJiA5uZmFBcXG/Q+WpevfKws31w1NTW4fv06EhIS1I4nJCS0e42YmBjVf3fv3h0A1O4XEbVgUCEig7i6uuLAgQPYu3cvoqOjsWrVKvTt21cVENzc3NSul0gkaG5uBgDU1dVhwoQJkEql+Pzzz5GZmYmdO3cCABoaGgyuQ21tLZ555hnk5OSofs6ePYv8/Hz07t1bpHdqHa3vl0QiAQDV/SKiX3WydQWIyHFIJBIkJCQgISEBr776KkJDQ1WBQ5cff/wRFRUVWL58OYKDgwEAWVlZGq89ceIEQkJCAACVlZX46aef0K9fPwDA/fffj4sXLyIyMtLk93DixIl2j5XlAy0BoqmpyaSypVIpevTogaNHj6pajADg6NGjGDp0qGkVJurgGFSIyCAnT57EwYMHMX78eAQFBeHkyZOQy+Xo168fzp07p/O5ISEh6Ny5M1atWoVnn30Wubm5+Pvf/67x2jfffBP+/v7o1q0b/vrXvyIgIEC1mNxf/vIXDB8+HHPnzsVTTz0FT09PXLx4EQcOHMAHH3xg0Ps4evQo3n77bUybNg0HDhzA9u3b8e2336rOh4WF4eDBg0hISIC7uzt8fX0Nu0H/8/LLL+O1115D7969cd9992HDhg3IycnB559/blQ5RNSCXT9EZBCpVIrDhw/joYceQp8+ffDKK69g5cqVmDRpkt7nBgYGYuPGjdi+fTuio6OxfPlyrFixQuO1y5cvxwsvvIDBgwejtLQU33zzDTp37gygZVxHRkYGfvrpJ4waNQqxsbF49dVX0aNHD4Pfx8KFC5GVlYXY2Fj84x//wL/+9S9MmDBBdX7lypU4cOAAgoODERsba3C5SvPnz8dLL72EhQsXYuDAgdi3bx92796NqKgoo8siIkAiCP+bW0hEZEPp6ekYPXo0Kisr4ePjY5HXCAsLw4IFC7BgwQKLlE9E4mOLChEREdktBhUicgo//PCD2rTltj+m6t+/v9YyOe6EyPLY9UNETuH27du4du2a1vOmzhS6fPmy2lYArXXr1g3e3t4mlUtEhmFQISIiIrvFrh8iIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdmt/w+Z4VZfonV5rwAAAABJRU5ErkJggg==\n", "application/papermill.record/text/plain": "
" }, "metadata": { "scrapbook": { "mime_prefix": "application/papermill.record/", "name": "exercise-06-f2" } }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAINCAYAAAAQmVQ9AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABq7UlEQVR4nO3deVzUdeI/8NeAiHLMcJsHp6CJipGiIkqoeeWaWtvuz9rFXLLLI0vbVbft2jXc0m3LTGs1j0ot/WaapeYqYN6goKJGnGoqMSCHMAoIn98f7EwMzD2fOXk9Hw8ej+bz+cx73vMJZ168T4kgCAKIiIiI7JCLrStAREREpA2DChEREdktBhUiIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2q5OtK+Compubcf36dXh7e0Mikdi6OkRERA5DEATcunULPXr0gIuL7jYTBhUTXb9+HcHBwbauBhERkcO6evUqevXqpfMaBhUTeXt7A2i5yVKp1Ma1ISIichw1NTUIDg5WfZfqwqBiImV3j1QqZVAhIiIygSFDJziYloiIiOwWgwoRERHZLQYVIiIislsMKkRERGS3GFSIiIjIbjGoEBERkd1iUCEiIiK7xaBCREREdotBhYiIiOwWgwoRERHZLQYVIiIislsMKkRERGS3GFSIiIjIbjGoEBERkd3qZOsKEJHjKJLX4vJNBcpq7uDSjRoEeLkjppcPmgQBrhIJmgQBYf6eCA/wtHVVAbTU92TxTZTfqkegtzskEuDSjRq4SCTo080bPXy6WqXuHxzMx55z1+Hv5Y5nk3pjVFSg6K9B5KwYVIhIpyJ5LdLyyvDp8csoqVAY9Bx3VwkmDeiGf88YbOHaaZZzpRKLd57HjzduGf3cAT2keGv6QHh16YTLNxVGhxdlmAvz98SNKgUeX3fq15O/1OJoYQW83Tvhu/mjEOzvYXT9iDoaiSAIgq0r4Yhqamogk8lQXV0NqVRq6+oQia5K0YDnPjuD40UVZpXz/u/vw8OxPUWqlW5VigbM3pyFzJJKUcuNCvLEhOh70MvPAz18uuJa1W1IALX/7tddipXf/4TD+XKDypR26YRzr08QtZ5EjsKY71AGFRMxqJCze2ztMdG+8A8tfACp311CobwWg0P98FBMd9G7WXKuVOLxdSehaGgSrUxLG9hTis9ShkPm4WbrqhBZFYOKFTCokLOqUjTgqU1ZyLosbquEJolRgVg1I9asL2qxWn5sQQJgVFQgNqcMtXVViKzKmO9QzvohIjWzN2fhtBVCCgAcyZfjqU2ZZpUxf2uOQ4YUABAAHM6Xo7i8ztZVIbJbDCpEHZxysOzZq1X47ZqW7h5rNbM2A8i8XIkpq35AtaLR6OcXyWsNHhNiz+ZtPWPS+yfqCDjrh6iDUU7ZvXpTge/O3zB4Jo8lnb9Wg1FvH8IPfx5jVDfQ5Zu2r7sYLl6vwbyt2ewCItKAQYXIwbSe/hoe4Knz8amiCnyUUYirlS1f6F3cXHGr3vzBpr0DPDEs3A89fLtiULAPDl0qw4ZjJWaVWXPnLoan/hcnljxocFi53XBX7zXunSSYPTICvfw84OoiwYXr1XCVSBDVzRs9fbvibrOA+sYmfJBWgNxrNWa9h7aUY3A+P3kZq9MKUKdloG+z8GsXkL2sQUNkLziY1kQcTEtiycgrQ87PVbg/xFfnQmBVigbM35qj1tXh6+GGylZdBm0fiynUzwPPJfXGsAh/jV+mvZd8iyYRPk1cXYD0haMNWmNk0r8P41Kp9rVSPNxccNyI4FNcXoeSijqE+Xvi1p1G/OX/zuGSEWuxjOjtj8UT70WFoqHdrKZqRSOeWHcCude1h6HURwZixtAQg1+PyFFx1o8VMKhQW4YGDqXLFXWYtvpou6Cxe85IjV/SyetP4WhBOZps8E82LswX65LjdH7hX7xWjYdWHRHl9bzdXXH+jYk6rymS12LMygyd1+yem4CYXj5m1aW4vA4niipQUVuPAC939PTtip8rW9ZOaf3f2gKcsXUWYyYUkb0z5juUXT9EZjI2cCi1fQ4AVCoa8fDqI8h+dbzacVsNGnUBMDjUF9ufHaH32uieMpQsn4zl313E2sPFZr3urfom/JAv1xn4ThbrnukTFeRldkgBgPAA8dZ7iQj0QmJUoM7AebSgnONViFrhrB8iM+kKHNpk5JVp7aKpVDTihzahxFaDRkdGBWLdzDijnrP4oWiULJ+MP0/oi94BHrhH6o7eAR4YHx2ET1OG4uyr4yHtov9vpIOXftFzhUTnWXvtQlk1IxYJkQFazzcJAqcsE7XCFhUiM+gLHPvO38DEgd3bncv5uUpnuWeuVKq1JoT6WWdPGF8PN2yaNVTjGAtjPT86Es+PjtR47oc/j0HcsgNo0DGoJT1PjmpFo9YukB6yLjpfP6qbl+GVtSKZhxs2pwzFtlNXsPir81qvK6ngwFoigC0qRGbRFzhS917SePw+PV0S94f4qj1Wdhm4SnS3IpgjNtgH6YtGIybYB6P7Bln0S1Lm4aa3O+lyhQLztmZrPX+9+rbO51+r1H3e1oaG++k8H+bPkEIEMKgQmUVf4Lh887bGJvwH+gbBV0tLga+Hm8axGZq6DNqWoa3MtoK8OmNuUm8sGt8Hyx8ZiLRFSdg5J8GqAzgHBftgaJj2L2vlqq3ntIRB+a16neUv/uo8Vh/KN6OGlqUtfLpKJEiMCoQgCEjLK2MXEHV4nPVjIs76IaUBr+1DrY61STbMisPovkHtjl+tUODh1UeMHoTbegpteICnzsdZJTexNr0AV24qIJEAA3v6YMXv7rObLgVDpuwO6CnFnnmj2h3feuoKlujoOlEqWT7ZrDpaUrWiEfO2ZqsNlI6P8IdEAhwr/HWwMGcCkbPh9GQrYFAhpaP5cjyx/pTW870DPPHV89pbK37Il+PMlUqDpzU7m5wrlZj24TGd16QtSmoXrgyZ6gsAQ0J8sOP5BLPqaGmtw+Vruy60mxXkKpEgITKAM4HIaXBTQiIr6u7TVef5wvI6PLLmqNbzo6IC8cLYPh0ypFQpGpD8ifaQp1RS0b77IyLQC718dd97AMi+WmVK1awqPMATo/sGQfjfjJ+2U5eVM4HazgYj6ggYVIjMpG89DwAolNdxrIEGszdnoeaO/mXwtQ0sXTrpXr3P7eRAn3L6pqH/cf0pJK8/xQ0MqUNxoH/CRPbKsJk4cz8/beF6OJYffipDZkml3uuigry0jqm5t7v+btc/xocbXTdbMWQa+pF8OZ5Yd4LBlzoMBhUiMw3TM81UqUBea+GaOJZnPzMsuK18bJDWc4YshPfKb6INrpOtGTINvRlA7vUajF6RztYV6hAYVIjMFBHohQCvznqvC/J2t0JtHENGXhnqGpr1Xjeitz9ign20ntf3Afbig5oXnLNn+laubU253D6RM2NQIRLB/xsSrPeatx6JsUJNHENaXpnea+Ij/LHmicE6r9G36Fs3qf7BtvZGuXLt5j/pn+GjHGT78vazVqgZkW0wqBCJYLAB3T+9fK2zDL4j8PPU3QL1h2HB2Pr0cL3rhuhb9K28Vvd5e5bYJ9Dg1Yi3n/4ZYYu/Rczr+/CPPRetUDsi62FQIRKBIYMgNU2x7agG6VnRd8KA9vsjaRLorXu/H38vx+5uM6YbCABq7jRh3ZFihC3+Fgcv6tvUkcgxMKgQiSAi0AtxYb46r+HeLb/SNzrlbrNh61DqG8g8PMLfwBrZJ2U3UNqiJAzoKYWLEVs9pWzO4hL85BQYVIhEsi45TuNeOy5oWQLdXpattwf6WqAMDXURgV6I1xJG4iP8neaehwd44vOU4RgZadyigLM2ZKpmB529WsXgQg6JQYVIJDIPN6QvGo24UPWWlZH/26eFfiVmwFj7h8FIbLOqb1yYL9b+QfdAXEejbF2Rdulk9HMP58sxdfVRteDCac3kKBhUiEQk83DD9udGIG1REjbMikPaoiRsThnKzeQ00DZG1ICxo2pkHm54f8Z9agExs6QS87ZmO+WX8W/v72V2GZqmNRfJa9niQnaJQYXIAsIDPOECYNOxYqw6lM8P/zaK5LVquwO3dqywwuj79fTmLGReVl/l9nC+HLM3Z5lcR3v16sP9zS5DOa25uLyuZb+l9acwZmWGxhYXTQFGW6jRFXYYhMhUxrchEpFOlyvqMPWDo6i6/etf8yu//wlxob5YNzOOrSvQv6LshevVBnf/FMlrcUrLUvynSm6iuLzOacaqKK1PHoIUEUJYSUUdXttVgqMF5WrHjxaU49nPTsPN1QWHW22EGB/hD4kEaiEzMSoQ/5g2AK98nat2beL/ujwFCJi/NUfjOZmHG4rktbh8U4Ewf0+1/0/ajlPHIxEEwbDh9aTGmC2qqWOJffN7VGrpckiMCsTrD0d3+A/gInktxqzM0Ho+NliGnXNGGlTW+wd/wr8O5Gs9v2h8H8wdE2V0HR3BP/ZcxNfZP+N2QxMAoKt7J3Tp5Iob1Xfa7cCsyeY/DdW5e7WLBNA3ActVIoG0ayfU3L6r9pquEolqavXRgvJ254aG+7ULQvpCj65gQ47FmO9QtqgQiSgjr0xrSAFauiNaf0G3/gDuSCICvTAk1BdZlzW3hGRfrTa4JeRmXYPO84686Js+r/wmut1eRtWKRszbmq32Rd+WMkToCzOGzBJvEgSNv/PK7iVtzzleVNFuuvXRgnJMXX0ENbfvtjuuqYWno/776Wg4RoVIRDk/Vxl1/eF8OWZt1P4XrTN7aMA9Os+n/ah/mX0ACPDUvahbkJ5F4ZxN67VXNsyKw+65Ce1mRSVEBmDVjFiDFiq0pLZBSBl62gYoZbA5UqAefFoPCuYYGOfFFhUiEd2nZ8VVTc5cqXLKcRT6dHV31Xn+H99exLh+3RDsr/vLtAm6/+xvbNa/+aEzCg/4tWtkc8pQFJfXoaSiTq3LRObhhsSowHZdMy7QvyifLWgKNofz5Xhs7TFkthqnxJYW58IWFSIRPdA3SOOib/p8drxE/MrYsSpFA746c03nNc0CMHnVD3rLukdPi0kPmeNtTGgJ4QGeGN03qF0g1rRM/8ioQIzo7W/QPkOuEgl8PdzaXesqkSAxSvN+RWJ/8Zxu04WobGlhK4tzYIsKkch2zxmJyat+QM2du/ov/h99s2CcSZG8FvO3ZuPC9Rq919bcuYsf8uUYFaV9RVZPd90fYwHejr3fj6Upu4ratrhoGuuiadZPQmQAlk0bgL+2GQCr7F4C0K6ckVGBuNvcjJNFN9sNstU0MFdfC4+2lhaOB3MODCpEIgv294CrMZuyAJjQX/d4DWdQpWhoN03VEGeuVOoMKhuPleh8PvdYMkzrriJAe4ABoPGYtmu1ndMUhLSFHm3BxpguKmUry+aUoSbcHbIlTk82EacnkzYZeWWYuSHT4OtdJUBh6mQL1si2lNNJPzxUgDNXqgyaNtvapylDtQYVfdOc48J8sf3ZEUa9HlmXtnBjSLDRNXNMm/HRQbh4owbxEQF457FBor0PMg6nJxPZkDEzfzq5SLB7ToLlKmNDZ69W4q87c5FrQBePNr4eblpDyuWKOjz8wRGdz585Iszk1ybraNuSo+24thae5PWn2g0G1uX7iy2zybaf/hnbT/+MIO/OeHnCvXhsSLA4b4hEx8G0RCIzZOaPqwR4Y0o0Ct56CNE9ZZavlBUpl2SfuvqY2SFlt45F36atPora+iadZfTv4Vz3ltoPCtY0GNgYZbca8PKOcwhf/C0OXCgVq5okIraoEIlMOfNH28JvrhLgzN/GO+2gvqc2ZbWbhWGIAT2leGxwL1TdbsT9Ib46x6XoW1jPRQKMjAzscFO+OyJNLS2v7bpgVCsLAAgAZn96GkNCfTFrRBiie8r4+2MnOEbFRByjQrpcrVBg8qrDqLmj/he/Z2dX7HshUe/aII6oStGA2Zuz1Naz0MdFAkT3kGLVjPsN/lKoUjRg6gdHcPnmba3XhPp7YPeckU4bBkk3Q1bnNQRnClkOx6gQ2Viwvwc+f2o4pn5wVG1WQv3dZty6o70lwNFk5JXh65xr+KXmDgp+uYWyWuPe28hI478I5m/NwRUdIQUA/jFtAL9cOrC2rSzzPj+N2gbjl7DjTCH7wKBCZCHTPzzWburk3WYBD68+ioK3HrJJncRyuaIOU1YdMWqtGKBlUNzgMF88PzrSpE3liuS1ev9K1jUAlzoW5YDc3w0JwSd6prFrolyPpbi8DoIgcDNEG2FQIbKAL05dwV0tO7rdbRawPeuqQ88ymPTvdOgYIqLVSDOa0ovktfjm3HWd13i5u+ocgEsd06sP9zcpqCjN23oGudd+HRjetkuIOzpbFoMKkQUcL67Qef5oYbnDBpWMvDKjQ0pUN0+sfOw+xJiwF1LOlUq8sitX7YtCm2/mjXLK8T9kvvXJQ5CyOcuk515sM3tN2SX0/oz72i1i2DrEMMCIg0GFyALiw/3xdbb2v/4Teps+ndLW3j3wk8HXukiAwaGmLbpmzEq2rhIJEiID+GVAWo2N7oaS5ZPxjz0X8X+nr6K2/i5cJYDExQW3GzWPX1GufKttif7Zm7Nw5nKV2rmjBeV49rPTcHN10RpgyDic9WMizvohfSKXfqex+6eTi8Shx6jc98Z+VN02bGyKOR/O01cfRfbVKou/DlFxeR0uXK/GpmMlarPWBvSQmrwWkItEPeAowzQH5rbgrB8iO7B7TgIeXn20XVgZ2EOKakWjw36pGrKPkZe7K76ZN8qkFo4qRQOe2pRlUEh5cVwUHh7Uky0pZBbloNvfxPRQW49FEASdWzTooq0Vpri8zqDfV3Yb/YpBhchConvKMKJ3QLuui3PXahxyyqOyK6aiTvcAFQmAvfNNXytm/tYcgxeMY0ghsbVduj8xKrDd4nGuEgliQ3yM3mcIAEoqdAcVTV2eHb3FkEvoE1mItqm0rf+yciTPfXbGoPEiC8f3MTqkvLn7Aib+OwMvbz+Lw/ly6OuPlkhaPrwZUsjSNC3RnxAZgPUz45AYFQhXiXoLo74vVX27ec/fmoOjBeVqx5SDdzsqtqgQWcjlmwqd5y9eq3aYL9oieS2OF+meyaQ0OaaHweV+n3sDT392RvX4x9Jag543JNQXq2bEGvw6RKbSthki0BJi2q6AOzIqEHebm3Gy6Ga7Vhh9A74N+eNG32eGM3YZMagQWUion+5WhY3HSjB5kOFf6raUlldm0HVDw/yM+nBsHVIMdV+wj0mziIjMoWmXZ20hRtMS/gmRAXrDtb4/bnR1GxnaZbTwixycLKlAfEQA3nlskM7XsxcMKkQWEhHohbgwX61732RerjR4YJ2tbTt1Ve81yg9FQ725+4LR9TD2NYisoW2I0dUKo4u+P250dRvp6jLanDIUO09fxYvbz6nObT/9M7af/hnv//4+PBzbU2/dbIlBhciCZo4I07lJnyN0/+RcqUR+me4umU9Thhq9bP33l0qNrsvRfDlqbjvujCnqWDS1wugSEeildfCurm4jQ7qMWoeU1uZ/kYPYEN9248qK5LU4WVwBQILhEf42/ZziYFoiC4rurnt9gHe+z7NSTUz3yq5cnef73eNt0t46AZ7uRj+nCcCod9Kw7eRlo59L5Ai0Dd7V1ZKor8vor19pDilKY/+VrvrvKkUDpq8+ijErM7Dkq1ws+eo8Rq9Ix31vfo9Nx4r1vwELsGlQWbNmDWJiYiCVSiGVShEfH4+9e/eqzn/88cdISkqCVCqFRCJBVVWV3jJTU1MRFxcHb29vBAUFYdq0acjLU/8yKC0txR//+Efcc8898PT0xP3334//+7//E/vtEam6f7QpqVAgbPG3uHit2oq1MlzOlUq9S9f/89EYk8p+cVwfk54HAIt36g5PRI5K2W2UtigJG2bFIW1REjanDNXZiqivy+inX27pPN/QJODv31zAd+dvYOQ/D2lcw6hK0YjXdl9E7yXW/7yyaVDp1asXli9fjtOnTyMrKwtjxozB1KlTceFCS9+1QqHAxIkTsXTpUoPLzMjIwJw5c3DixAkcOHAAjY2NGD9+POrqfp0KmpycjLy8POzevRvnz5/HI488gt/97nfIzu6407/IcmaOCNN7zW8+OGL5iphAX2vKgB5SxAT7mFT2A32D4GlGD86zn5q2bwuRIwgP8MTovkEGdbkou4zaTpV2lUiQGBWIHrKuestYf7QEz39+BrX1TTqvaxKAKaut+3ll06AyZcoUPPTQQ4iKikKfPn2wbNkyeHl54cSJEwCABQsWYPHixRg+fLjBZe7btw9PPvkk+vfvj0GDBmHjxo24cuUKTp8+rbrm2LFjmDdvHoYOHYqIiAi88sor8PHxUbuGSCwlcv3rpTQLwPYs/QNWralIXqu3NeWt6QPNeo19C0bD18TxJkcMWNOFqKPQ1WV0+67mvYxM1dRs3c8ruxlM29TUhO3bt6Ourg7x8fGilVtd3dJE5efnpzo2YsQIfPHFF5g8eTJ8fHzw5Zdf4s6dO0hKShLtdYmUCsoNWxsk9duLdrWjsr5+by93V5NbU5SC/T2Q/ep4/JAvx9KvzuNq5W2Dn+vVxW4+vohsTttMo4y8Mr2D4U2x88w1q31e2fxf+vnz5xEfH487d+7Ay8sLO3fuRHR0tChlNzc3Y8GCBUhISMCAAQNUx7/88kv8/ve/h7+/Pzp16gQPDw/s3LkTkZGRWsuqr69HfX296nFNjWkbVVHH49e1s0HX3TRwoz9r0dfvXVvfhHM/VyGml49Zr1Mkr8XPlbeNCikAsHD8vWa9LpEzUs40qlI0IHn9KYNWkzaFl7urRcrVxOazfvr27YucnBycPHkSzz33HGbOnImLFy+KUvacOXOQm5uLbdu2qR3/29/+hqqqKvz3v/9FVlYWXnrpJfzud7/D+fPntZaVmpoKmUym+gkOtp+/fMm+yQwciGHFf/cGiQj0woAeumctLdyeY3L5yg/SltkF2v/taWNPrU9E9mb+1hyLdo/+0YCxd2KRCIKgb1sNq3rwwQfRu3dvfPTRR6pj6enpGD16NCorK+Hj42NQOXPnzsWuXbtw+PBhhIeHq44XFhYiMjISubm56N+/v9rrRkZGYu3atRrL09SiEhwcbNAW1dSxZeSVYeaGTL3XPTUyHK/8RpzWRLGcvVqFqauP6rxmYE8pPksZbvTaJsnrT7VbL8IQLhJgz9yRiO4pM+p5RB1FkbzW5F2fDeHt7oLzb0wyq4yamhrIZDKDvkNt3vXTVnNzs1ogMJYgCJg3bx527tyJ9PR0tZACtMwkAgAXF/XGJFdXVzQ3ax9w5O7uDnd349d9IHqgbxCkXTqh5o7urh17CykAMCjYBwN6SJF7XXtX5/lrNRj19iH88OcxesOKch8SV4nEqCZp904SBHl3wfyxUWxJIdKhSF6Lb85dt1j5Pl3d8M3ckRYrXxObBpUlS5Zg0qRJCAkJwa1bt7Blyxakp6dj//79AFrWOyktLUVBQQGAlvEs3t7eCAkJUQ2OHTt2LKZPn465c+cCaOnu2bJlC3bt2gVvb2+UlrasfimTydC1a1fce++9iIyMxDPPPIMVK1bA398fX3/9NQ4cOIA9e/bY4C5QR/DKb/rhzzu0d2+8MFb7+ChbWzZ9oN5WlZo7d1VhpaKuXrUpmiAIuHxTgdsNTfgwvUDvLCJN4iP8sfVpw2f+EXU0T2/KRHpeGRqMnNwzsIcUjw8PRUVtPQK83NHTtyvuNgvo5CLB3WYB5bfqceF6NWrv3IV3FzeM6Rdk0uKO5rJpUCkrK0NycjJu3LgBmUyGmJgY7N+/H+PGjQMArF27Fm+88Ybq+sTERADAhg0b8OSTTwJo6copL/91f4M1a9YAQLsZPMrnuLm54bvvvsPixYsxZcoU1NbWIjIyEps2bcJDDz1kwXdLHVnfbt46z0+L7WWlmhhvULAPEqMC8UO+HLo6aZRhRV/LkTG4tw+Rdp8dL8Yru0wb0xkV5IXPntLfZfsYbN+CaXdjVByFMf1rRLpG3ydGBWJzylAr18g41YpGpGzKRNZl7fsWicFVIsH9IT54fkykU21TTyS2N3adx4bjV0x+ftqiJJv++zLmO9Tms36InJ22DcOUFk0wfSl5a5F5uGHHcyMwsKdlQ3lCZADWzYwzeEVOoo7KnJASb+NNBo1ld4NpiZxNZslNnecr6hqsVBPzfZYyXPTunU9ThuJus8AWFCIDjX0nzeTnOmJ3KltUiCxs2beXdJ4P83ecL2eZhxt++PMYSEVYFdZF0vKhOSoqkC0oREYorNC9arQu+jY4tEcMKkQWlJFXprP1YWBPqcN9QSvDSttdoX093OAq0fIkDUZGOt5fdkT2wIh/Zk6BXT9EFpSWV6bz/MioAJ3n7ZXMww3bnx2htq+In0dnzNuarXd9lAE9pHhr+kCz9wki6qhGRPjhaJHuLmVNhoT4iF8ZK+CsHxNx1g/pUqVowPytOXq/tD9NGWqTdQksqXV4AYCSijrVugwch0IkjrDF3xr9nJLlky1QE9M49Mq0RM5g/tYcHC0o13mNr4eb04UU4NdN0Vo/JiJxvTq5H97UM/6ttZfH2//sQm04RoVIZMrpyLr2sPH1cMPuOdZdhpqInMefRkXgi9mGrdi8PnkI5oyJsnCNLIctKkQiu3xT94j8heP7YJ4Df2gQkX0Y1tsfJcsn48O0AvzncCGqbt+FBICLC+Dt3gmPDg62yz3EjMWgQiQyPz1T/34T08NKNSGijuD50ZF4frT97hdmLgYVIpGt/D5f67kRve1/RcgvTl3BtsyWVS8fHxbK3YqJyKYYVIhEpG+5/Ft3Gq1YG82K5LWq3Y1bh6bzP1dhygfquyRnXz2Hl3ecw3fzRiK6p8zaVSUiYlAhEpO+8Snnr9WguLzOYq0qrUOIIAhqgaRK0YCnNmWpbSyoXE77m7M/69yF9aFVRzBvdG8snHCvRepNRKQNgwqRiEL9PPRek/5jGcJHhpv8Gm1bRIrktbh4vQabjpUgU8vuxiN6++PC9WpU31ZfJfdIvtygRdoAYFVaIYMKEVkdgwqRiCICvRAV5IX8slqt12w5dRmzTAgqmhaR8/VwQ6VCf3fSscIKjcebAYNCitJv3juMPS8kGnw9EZG5uI4KkchWPBaj83x+WR2Ky+v0llMkr0VaXpnqWk2LyBkSUsR04cYtq74eERFbVIhENijYF/26e+OSji/1ld//iL73eAMAAry6oKdPFzQJLTsp+3q4tWs5iQvzRWaJ5m4dIiJnxqBCZAHLHxmIqauPaT2/51wp9pwr1XjO18MN1W1aSk5rGXsihrhQX61jW9oaGelvsXoQEWnCrh8iCxgU7Iu4MF+TnlupaERzm2PNFto61NfDDetmxmH59AEGXT+Zi9URkZUxqBBZyMwRYaKXaeo/2BG9/REfod4aEhfmi/RFoyHzcMP/GxaKkuWTEezbRWc55bX1JtaAiMg07PohspDo7rq3LjfF4DbdNG1n/cSF+WLmiDD079GyOFtJRZ3awm7F5XXtjrX22JBg/OuA9pV1iYisjUGFyEIiAr2QGBWIIwVys7tuXCUSJEQGYHPK0HZhQ1f40PRY12Jzgd66W1Q8O7ua/iaIiEzArh8iC1o1IxYjIwONeo6rpKWlpLWEyACsmhELoCVsjO4bpAocbR+bo4dMd1D56sw1s1+DiMgYbFEhsiCZhxs2pwzFuatV+Mv/ncOlUv3rkCREtixrf1PRoLObxhLaDuJt6/z1Gpy7WoWYYB9rVIeIiEGFyBpign2wd0EiisvrcLKoQm1Qqr+XO3r5dsXdZkEtlMg83Ky+07IhWwAs3Xkee+aPskJtiIgYVIisSt8YEVuLCPTSu7hcLltViMiKOEaFiNSsS46Dl7vuQbPzt52xUm2IqKNjUCEiNTIPN3z+1DCd15RU3EbM6/txtUJhpVoRUUfFoEJE7QwK9sWAnrrXgam5cxeT3j9s0AaLRESmYlAhIo2WTdO/rH5tfRNGr0hH8vpT7fYnIiISA4MKEWk0KNgXiVGGrQFzpECO3649hq2nrrCFhYhEJREEwULbnTm3mpoayGQyVFdXQyoVf6l0IntQrWjEE+tPIPdajVHPiw2WYeOsYZC1WbiOiAgw7juULSpEpJXMww175o2CtItxKxlkX63GqLcPYc+562xhISKzsEXFRGxRoY7kaoUCD68+orYBojEG9JTirekDEdPLR9yKEZFDMuY7lEHFRAwq1BH9kC/HKzvP48rN2zDlgyMxqmV7AHYJEXVsDCpWwKBCHVW1ohHztmbjcL7c6Oe6ABgc5ovnR0diT851ZOTL0ckFSI4Px/OjI8WvLBHZJQYVK2BQoY6uuLwO87acQe514wba6vLF7OEY1ttftPKIyD5xMC0RWVx4gCc+f2o4RogYLH7/nxM4ePEX0cojIsfHoEJEJpN5uGHL7OHYPScBUUFeopSZsjlLlHKIyDkwqBCR2WKCfXDgpQeQtigJq2fEIi7U16zy/rHnokg1IyJHZ9ziCEREOoQHeCI8wBOTB/XAuatVWLrzvEljWI4UGD9Ql4icE1tUiMgiYoJ98NlTw3BfsI/Rzx0ZadjS/UTk/BhUiMhi5m/NQc7VKqOf98pvosWvDBE5JAYVIrKIInmtSWutrE8eYoHaEJGjYlAhIou4fFNh9HOWTx+AsdHdLFAbInJUHExLRKIpktfi8k0Fwvw9Eernoff6AE833GlswsioQKz9I1tSiKg9BhUiMkuRvBYXbtRg87ESZJZUqo4nRgViRG9/HCus0Pi8xKhAbE4Zaq1qEpGDYlAhIpNUKRowf2uO1nEoRwvKMTTcD/ER/jhepB5WRvT2x6oZsdaoJhE5OAYVIjLJ/K05OFpQrvV8kyDgeFEF0hYlAQBOFFVAAmBYhD/CAzytU0kicngMKkRktIy8MoNn9JRU1GF03yCGEyIyCYMKERmsStGA2Zuz1Mai6BPmz4BCRKZjUCEig1QpGpD4dhpq7tw16HpXiQQJkQFsSSEis3AdFSLSy9iQAgAJkQEcMEtEZmOLChHpNWtDpkEhJS7UF0+OCEN0TxlbUohIFAwqRKRTkbwW2Qbs1/NpylCMiuJmgkQkLnb9EJFO6Xlleq+JC/NlSCEii2BQISKdPjtxRed5j86uWJccZ6XaEFFHw6BCRFoVyWtRVF6n85ptTw+HzMPNSjUioo6GQYWItDpZrHmfHqWIAE/E9PKxTmWIqENiUCEiHSQ6z/72/p5WqgcRdVQMKkSk1bBwP53nD1zSP9CWiMgcDCpEpFVEoBdig2Vaz2dfrUKxnjEsRETmYFAhIp2mDOqh8/y3565bqSZE1BExqBCRTl07614XcsX3PyF5/SlUKxqtVCMi6kgYVIhIJ33jVADgaEE55m3NtkJtiKijYVAhIp0iAr0QH+Gv85omQcDhfDnHqxCR6BhUiEivtX8YjEQDlsjfffYawwoRiUoiCIJg60o4opqaGshkMlRXV0Mqldq6OkRWcfinMiR/kqn3usSoQKyaEcsVa4lII2O+Q9miQkQGS+wThMSoQLhKdC8ExzErRCQWBhUiMsqqGbFIiAzQeQ3HrBCRWBhUiMgoMg83bE4ZirRFSXhxXJTOazlmhYjMxaBCRCYJD/DElBjdi8G9eyAfo1ekc50VIjIZgwoRmSwi0ItjVojIohhUiMgsHLNCRJbEoEJEZjFmzEpJBYMKERmHQYWIRGHImJXS6jtsVSEio9g0qKxZswYxMTGQSqWQSqWIj4/H3r17Vec//vhjJCUlQSqVQiKRoKqqSm+ZqampiIuLg7e3N4KCgjBt2jTk5eWpzpeUlEAikWj82b59uyXeJlGHoW/MypKvznNwLREZxaZBpVevXli+fDlOnz6NrKwsjBkzBlOnTsWFCxcAAAqFAhMnTsTSpUsNLjMjIwNz5szBiRMncODAATQ2NmL8+PGoq2v5Ky44OBg3btxQ+3njjTfg5eWFSZMmWeR9EnUkhoxZ4eBaIjKU3S2h7+fnh3feeQcpKSmqY+np6Rg9ejQqKyvh4+NjVHlyuRxBQUHIyMhAYmKixmtiY2Nx//33Y/369QaXyyX0iXQrLq/DiaJyLPkqV+s1aYuSEB7gacVaEZE9cMgl9JuamrBt2zbU1dUhPj5etHKrq6sBtAQgTU6fPo2cnBy1YKRJfX09ampq1H6ISLvwAE/cI+uq8xouCEdE+tg8qJw/fx5eXl5wd3fHs88+i507dyI6OlqUspubm7FgwQIkJCRgwIABGq9Zv349+vXrhxEjRugsKzU1FTKZTPUTHBwsSh2JnFmon4fO88oF4R5be4xjVohII5sHlb59+yInJwcnT57Ec889h5kzZ+LixYuilD1nzhzk5uZi27ZtGs/fvn0bW7Zs0duaAgBLlixBdXW16ufq1aui1JHImRm6IFxmSSWSVqQxrBBROzYPKp07d0ZkZCQGDx6M1NRUDBo0CO+9957Z5c6dOxd79uxBWloaevXqpfGaHTt2QKFQIDk5WW957u7uqtlJyh8i0s+QwbUAUKloxP/7z3Er1IiIHInNg0pbzc3NqK+vN/n5giBg7ty52LlzJw4dOoTw8HCt165fvx4PP/wwAgMDTX49ItLNmAXhLt24hcfWsBuIiH5l06CyZMkSHD58GCUlJTh//jyWLFmC9PR0PPHEEwCA0tJS5OTkoKCgAEDLeJacnBzcvHlTVcbYsWPxwQcfqB7PmTMHn332GbZs2QJvb2+UlpaitLQUt2/fVnvtgoICHD58GE899ZQV3ikRGbIgHABkXq7EU5szrVAjInIENg0qZWVlSE5ORt++fTF27FhkZmZi//79GDduHABg7dq1iI2NxezZswEAiYmJiI2Nxe7du1VlFBYWory8XPV4zZo1qK6uRlJSErp37676+eKLL9Re+5NPPkGvXr0wfvx4K7xTIgJaxqxEBXnpvS6zpJItK0QEwA7XUXEUXEeFyDRnr1Zi6upjeq9zATAyKhCbU4ZavlJEZFUOuY4KEXUMg4J9ER/hr/e6ZgCH8+XYeuoK11oh6sDYomIitqgQma5a0Yh5W7NxOF9u8HMG9JTirekDEdPLx3IVIyKrMOY7lEHFRAwqROY7d7UKC7efRX5ZrcHPYWAhcnwMKlbAoEIknsfWHMPpy5VoNuI5cWG+mDkiDP17yLhfEJGDYVCxAgYVIvGY0hXUWmJUIFbNiIXMww1F8lpcvqlAmL8nBEHAyeIKABIMj/BnoCGyEwwqVsCgQiQ+Q3Zc1sRVIsGwCD90cnHRGXbiI/yx9g+DUVFXrwozDC9E1segYgUMKkSWk7z+FI4UyNFs5KeTC6C3+8jXww2VrdZnad0aQ0TWwenJROTQVs2IxchI47e2MGSMS2WbReSOFpRj3tZstWNF8lqk5ZVxWjSRHehk6woQEbWl3B/o3NUqLN15HrnXayz2Wk2CgMP5chSX18HXww3zt+aodR9pG//CLiMi62DXj4nY9UNkPfoCi4sERncTtbVhVhw2HCnB0YJyNLX6WNQ2/oWzjohMZ8x3KFtUiMjuxQT7YM/8USgur8PFa9XYeKwEmZcrVedHRgaisakZp4pvqoUMY7hKoHEgbpMg4FhhRbt+8sySSmSWtNQhLswXcWG+UDQ0YWy/bhgVFYiMvDL8+78/oby2HhP6d8crv4k2qV5EHR1bVEzEFhUi2your0NJRZ2qG8aQKc6yrp1w6/ZdtbEsrhIJEiIDMGtkGGZtsOyuzeuTh2BsdDeLvgaRI+CsHytgUCGyT60DDACcLKqAAGB4hD/8PDq3CzPKMSgVdfUYszLD4vV7eXwfzBkTZfHXIbJnDCpWwKBC5LjatsYoJa8/1W6MihjjX9oqWT5Z3AKJHAynJxMR6RAe4InRfYPaDYJdNSMWCZEBasdGRgYiPsIfrhKJaK//2w+PilYWkbPjYFoiov9RTos2ZfyLMbKvVolSDlFHYFKLSkREBCoqKtodr6qqQkREhNmVIiKypbYtLsoAk7YoCatnxCIu1Nes8juxLZvIYCa1qJSUlKCpqand8fr6ely7ds3sShER2aPwgJYWlsmDeqimSn90uAjnrlUbVc4f48MtVEMi52NUUNm9e7fqv/fv3w+ZTKZ63NTUhIMHDyIsLEy0yhER2au2oeWDg/n4v2zD/lDjmipEhjMqqEybNg0AIJFIMHPmTLVzbm5uCAsLw8qVK0WrHBGRIwgP8ERIgIdB165PHmLh2hA5F6OCSnNzyzJJ4eHhyMzMREBAgJ5nEBE5vyJ5LSTQPSvowXsDsO7JYVaqEZHzMGmMSnFxsdj1ICJyOFWKhnabGGri6+HGkEJkIpOnJ9fV1SEjIwNXrlxBQ0OD2rn58+ebXTEiIns3f2sOjhaU67zG18MNu+eMtFKNiJyPSUElOzsbDz30EBQKBerq6uDn54fy8nJ4eHggKCiIQYWInF6RvFZnS8qsEWEY0y8Io6ICrVgrIudj0mz+F198EVOmTEFlZSW6du2KEydO4PLlyxg8eDBWrFghdh2JiOzO5ZsKnecT+wYypBCJwKSgkpOTg4ULF8LFxQWurq6or69HcHAw3n77bSxdulTsOhIR2ZUieS1Kq+/ovEa5KSIRmcekrh83Nze4uLRknKCgIFy5cgX9+vWDTCbD1atXRa0gEZG9MGTwrKtEgoTIgHb7CBGRaUwKKrGxscjMzERUVBQeeOABvPrqqygvL8enn36KAQMGiF1HIiK7YMjg2YTIAKyaEWulGhE5P5OCyltvvYVbt24BAJYtW4bk5GQ899xziIqKwieffCJqBYmI7IG+wbPLHxmIYRH+bEkhEplJQWXIkF9XVgwKCsK+fftEqxARkT3SN3i2m6wLQwqRBXAPTyIiA4T66V4in4NniSzD4BaV2NhYSCS6l4hWOnPmjMkVIiKyRxGBXkiMCsTRgnI0CYLqOAfPElmWwUFFuSEhEVFHtWpGLOZtzVYbq8LBs0SWJRGEVn8aiGzr1q14+OGH4enpfH9p1NTUQCaTobq6GlKp1NbVISIrKi6vQ0lFHcL8PdmSQmQCY75DLTpG5ZlnnsEvv/xiyZcgIhJVkbwWaXllKC6v03pNeIAnRvcNYkghsgKTNyU0hAUba4iIRKVpMbfEqECsmhELmYebDWtG1LFx1g8REYDZm7NwpEB9nZSjBeWYtzXbRjUiIoBBhYg6uCpFA3675hgySyrR3KYRuEkQcDhfrrMbiIgsi0GFiDq0h947jKzLlTqvKalgUCGyFYuOUSEisleXK+ow8d/puN2o/1ou5kZkOxZtUQkNDYWbGwehEZH9mbb6qEEhJS7Ml7N7iGzIpKASERGBioqKdserqqoQERGhepybm4vg4GDTa0dEZAEZeWWoVBiQUgDMHBFm2coQkU4mBZWSkhI0NTW1O15fX49r166ZXSkiIkupUjRgyVfnDb6+fw+ZBWtDRPoYNUZl9+7dqv/ev38/ZLJf/wE3NTXh4MGDCAsLE61yRERiqlI0YPSKdINbUwI8O7Pbh8jGjAoqyv1+JBIJZs6cqXbOzc0NYWFhWLlypWiVIyIS01ObsgwOKQBwcGGS5SpDRAYxKqg0NzcDAMLDw5GZmYmAgACLVIqISGwZeWV6pyG3tnz6AK5IS2QHTJqeXFxcLHY9iIgsQtPS+Np06SRBUt8grP3jECvUjIgMYfI6KgcPHsS7776LS5cuAQD69euHBQsW4MEHHxStckRE5pq9OQunDWhJiQvzxfZnR1ihRkRkDJNm/Xz44YeYOHEivL298cILL+CFF16AVCrFQw89hNWrV4tdRyIio+laGr8tXw83rEuOs07FiMgoEsGELY579eqFxYsXY+7cuWrHV69ejbfeeqtDTFGuqamBTCZDdXU1pFKpratDRG0krz+FI/lyNOu5Li7UF+tmxnE8CpEVGfMdalKLSlVVFSZOnNju+Pjx41FdXW1KkUREosnIK8NhA0LKpylDsf25EQwpRHbMpKDy8MMPY+fOne2O79q1C7/5zW/MrhQRkSmqFA1IXn8KMzdk6rzORQIkRgViVFSglWpGRKYyaTBtdHQ0li1bhvT0dMTHxwMATpw4gaNHj2LhwoV4//33VdfOnz9fnJoSEenx/OdncKyw/fYebQ0O9cWqGbFWqBERmcukMSrh4eGGFS6RoKioyOhKOQKOUSGyL0XyWoxZmaHzGhe0hJTtz3F2D5EtGfMdynVUiMgppOeV6b1mZFQgW1KIHIxJY1QMJZVKnbZFhYjsR5WiASv25+m8ZuH4PticMpQDZ4kcjEWDigm9SkRERpu1IROKRt1zfH4T08NKtSEiMVk0qBARWVqRvBbZV6t0XtOvuzd3QSZyUAwqROTQThbrn+Xzz0djrFATIrIEBhUicmjyW/U6z4f5eyCml491KkNEorNoUJFIJJYsnogIgd5ddJ5Pjg+zTkWIyCI4mJaIHNqwcD+d50ffG2SlmhCRJZgVVBoaGpCXl4e7d+9qPL9371707NnTnJcgItIpItALQ8N8NZ4bGubLQbREDs6koKJQKJCSkgIPDw/0798fV65cAQDMmzcPy5cvV103cuRIuLu7i1NTIiItXF00f5RpO05EjsOkf8VLlizB2bNnkZ6eji5dfu0ffvDBB/HFF1+IVjkiIn2K5LU4XqR55s/xogoUl9dZuUZEJCaTltD/+uuv8cUXX2D48OFqA2b79++PwsJC0SpHRKTP5ZsKnedLKurY/UPkwExqUZHL5QgKaj9Ara6ujjN9iMiqQv08dJ4P82dIIXJkJgWVIUOG4Ntvv1U9VoaTdevWIT4+XpyaETmQInkttp66gm2nrrTraiiS1yItr8wiXRCWLNtRRAR6wVfL/j2+Hm5sTSFycCZ1/bz11luYNGkSLl68iLt37+K9997DxYsXcezYMWRk6N5mnciZ5FypxEtfnkVRm6Aworc/lj8Sg1e+zsXhfLnqeOL/du81d2O8KkUD5m/NMbnsInktLt9UIMzf02Jf5EXyWpwsvgkJgGER/qK+Tuv6C4KASkWjxusqFY0oLmfXD5EjkwgmLnZSWFiI5cuX4+zZs6itrcX999+Pv/zlLxg4cKDYdbRLNTU1kMlkqK6uhlQqtXV1yMqqFA2YteEUsq9Wa73G18MNNbfvoqnVPzFXiQQJkQHYnDLUrNdPXn8KRwvKjS7b3IBjiCpFA5777Ey7Aa4jevtjzRODzXodTfX3cndFbX2T1udsmBWH0X25lgqRPTHmO9TkoNLRMah0XFWKBiS+nYaaO5rXDzJE2qIkk//KL5LXYsxK7S2Xuso2NeAYI3n9KbUg0VpiVKBZr6Op/vqYc6+JyDKM+Q41qesHAJqamrBz505cunQJABAdHY2pU6eiUyeTiySye1WKBiQsP4S6Bu1/wRvCnJkops5yKZLXagwQTYKAw/lyUbpItL2Gkjmvo69sInJOJqWKCxcu4OGHH0ZpaSn69u0LAPjnP/+JwMBAfPPNNxgwYIColSSyB8qWFHNDCmDeTBRTZ7lYYxqvvtcw53UMKVuTk0UVbFEhcmAmzfp56qmn0L9/f/z88884c+YMzpw5g6tXryImJgZPP/202HUksgtPbcoyqrvH18MNrm2m67tKJEiMCjTrizMi0AuJUYFGl22Nabz6XsOc1zGkbE3Yt03k2EwKKjk5OUhNTYWv76/7a/j6+mLZsmXIzs4WrXJE9qJIXousy5UGXz+itz92zxmJhMgAteMJkQFYNSPW7PqsmhFrdNmmBhxjKF9DG3NeR1v99Rke4W/S6xGRfTApqPTp0we//PJLu+NlZWWIjIw0uJw1a9YgJiYGUqkUUqkU8fHx2Lt3r+r8xx9/jKSkJEilUkgkElRVVektMzU1FXFxcfD29kZQUBCmTZuGvLy8dtcdP34cY8aMgaenJ6RSKRITE3H79m2D604di6HdDhEBntg9JwFbZg9HsL8HNqcMRdqiJGyYFYe0RUnYnDJUlNk1Mg83k8o2JeAYa9WMWMRrCAcjevub/Tqa6q9tDRUAiBd5WjQRWZ9Js36+++47/PnPf8brr7+O4cOHAwBOnDiBN998E8uXL8fIkSNV1+oazfvNN9/A1dUVUVFREAQBmzZtwjvvvIPs7Gz0798f//73v3Hnzh0ALfsLVVZWwsfHR2fdJk6ciP/3//4f4uLicPfuXSxduhS5ubm4ePEiPD1bPrCOHz+OiRMnYsmSJZgyZQo6deqEs2fPYurUqQZvoshZPx2Lvpk27p1csP2ZeMQE+1ivUmYoLq9DSUWdRddRKS6vw4miCouso9K2/ud+rsLSneeRe61GdY3Y066JSDwWn57s0mpHUuWqtMpiWj+WSCRoajJu4KGfnx/eeecdpKSkqI6lp6dj9OjRBgWVtpTL/WdkZCAxMREAMHz4cIwbNw5///vfjSqrNQaVjid5/SkcyZejuc1xaZdO+OHPY/iFaAesEcCIyHwWn56clpZmUsV0aWpqwvbt21FXVyfqMvzV1S0Lcvn5+QFo6Z46efIknnjiCYwYMQKFhYW49957sWzZMrWWoLbq6+tRX1+velxTU6P1WnJOq2bEYt7WbLUpsnGhvlg3M44hxU6EBzCgEDkbk4LKAw88IFoFzp8/j/j4eNy5cwdeXl7YuXMnoqOjRSm7ubkZCxYsQEJCgmrKdFFREQDg9ddfx4oVK3Dfffdh8+bNGDt2LHJzcxEVFaWxrNTUVLzxxhui1Isck3JcCP9qJyKyHrNWZ1MoFLhy5QoaGhrUjsfExBhcRt++fZGTk4Pq6mrs2LEDM2fOREZGhihhZc6cOcjNzcWRI0dUx5qbWxrun3nmGcyaNQsAEBsbi4MHD+KTTz5BamqqxrKWLFmCl156SfW4pqYGwcHBZteRHA//aicish6TgopcLsesWbPUZui0Zsy4lM6dO6tmCg0ePBiZmZl477338NFHH5lSNZW5c+diz549OHz4MHr16qU63r17dwBoF4T69euHK1euaC3P3d3d4IG2REREJA6TpicvWLAAVVVVOHnyJLp27Yp9+/Zh06ZNiIqKwu7du82qUHNzs9pYEGMJgoC5c+di586dOHToEMLDw9XOh4WFoUePHu2mLP/0008IDQ01+XWJiIhIfCa1qBw6dAi7du3CkCFD4OLigtDQUIwbNw5SqRSpqamYPHmyQeUsWbIEkyZNQkhICG7duoUtW7YgPT0d+/fvBwCUlpaitLQUBQUFAFrGs3h7eyMkJEQ1OHbs2LGYPn065s6dC6Clu2fLli3YtWsXvL29UVpaCgCQyWTo2rUrJBIJXn75Zbz22msYNGgQ7rvvPmzatAk//vgjduzYYcrtICIiIgsxKajU1dUhKKhl23RfX1/I5XL06dMHAwcOxJkzZwwup6ysDMnJybhx4wZkMhliYmKwf/9+jBs3DgCwdu1atQGsyunFGzZswJNPPgkAKCwsRHl5ueqaNWvWAACSkpLUXqv1cxYsWIA7d+7gxRdfxM2bNzFo0CAcOHAAvXv3Nuo+EBERkWWZtI5KXFwc/vGPf2DChAl4+OGH4ePjg9TUVLz//vvYsWMHCgsLLVFXu8J1VIiIiExj8XVUXnjhBdy4cQMA8Nprr2HixIn4/PPP0blzZ2zcuNGUIomIiIjaMalFpS2FQoEff/wRISEhCAgI0P8EJ8AWFSIiItNYvEWlLQ8PD9x///1iFEXkMIrktbh8U8GF34iILMikoNLU1ISNGzfi4MGDKCsrUy2ipnTo0CFRKkdkj6oUDZi/NUdtKX1ugEdEZBkmj1HZuHEjJk+ejAEDBqg2IiTqCJ7//AyOFVaoHTucL8dzn5/GltnDbVQrIiLnZFJQ2bZtG7788ks89NBDYteHyK4VyWvbhRSlY4UVKC6vYzcQEZGITFqZtvWy90QdyclizSFFdb5I93kiIjKOSUFl4cKFeO+99yDChCEihyK/pXt7h/Ja07d/ICKi9gzu+nnkkUfUHh86dAh79+5F//794eamPoDwq6++Eqd2RHYm0LuLzvP+Xty4kohITAYHFZlMpvZ4+vTpoleGyN4NC/fTeX54hL+VakJE1DEYHFQ2bNig+u/bt2+jubkZnp4tgwZLSkrw9ddfo1+/fpgwYYL4tSSyExGBXpB26YSaO3fbnZN26cSBtEREIjNpjMrUqVPx6aefAgCqqqowfPhwrFy5EtOmTVNtCkjkjIrktRpDCgDU3LmL4vI6K9eIiMi5mRRUzpw5g1GjRgEAduzYgW7duuHy5cvYvHkz3n//fVErSGRP9M36Sf+xzEo1ISLqGEwKKgqFAt7e3gCA77//Ho888ghcXFwwfPhwXL58WdQKEtkX3YsbbjnF338iIjGZFFQiIyPx9ddf4+rVq9i/fz/Gjx8PACgrK+MGfeTU9A2mzS+rY/cPEZGITAoqr776KhYtWoSwsDAMGzYM8fHxAFpaV2JjY0WtIJE9iQj0Qr/u3jqvKalgUCEiEotJQeW3v/0trly5gqysLOzbt091fOzYsXj33XdFqxyRPVr+yECd58P8OfOHiEgsJu31AwD33HMP7rnnHrVjQ4cONbtCRPZuULAvEqMCcSRfjuY253w93ODn0dkm9SIickYmtagQdXSrZsRC5uHW7ni1ohHztmbboEZERM6JQYXIBBV19ahUNLY73gzgcL6cA2qJiETCoEJkgss3FTrPc0AtEZE4GFSITBDq56HzPAfUEhGJg0GFyAQRgV5IjAqEq0R9AThXiQSJUYHc84eISCQMKkQmWjUjFgmRAWrH+vXwxqIJfWxUIyIi5yMRBEGwdSUcUU1NDWQyGaqrq7kabwd39mol/rozF7nXa1THEqMCtc4MIiLq6Iz5DmWLCpGZVn6fj0s3bqkdO1Ig5zRlIiIRMKgQmaFIXovD+XI0tWmYbBZapimfu1plm4oRETkJBhUiM+ibprx053kr1YSIyDkxqBCZQd805dzrNVz8jYjIDAwqRGaICPTCgJ66B4Jx8TciItMxqBCZadm0ATrP+3OTQiIikzGoEJnJu4vuKch/33PRSjUhInI+DCpEZtI3oDbzciXHqRARmYhBhchM+gbUAhynQkRkKgYVIjNFBHohLsxX5zUcp0JEZBoGFSIRrEuOg6+O5fJXfP+TFWtDROQ8GFSIRCDzcMPGWXFazx/Ol3OcChGRCRhUiERyU9Go8zzHqRARGY9BhUgk+gbVhvl7WqkmRETOg0GFSCQRgV5IjAqEq0Si8fxruy6gWk+rCxERqWNQIRLRqhmxSIgM0HjuaEE55m3NtnKNiIgcG4MKkYhkHm54/eFojeeaBIGDaomIjMSgQiQyfSvVclAtEZHhGFSIRMZBtURE4mFQIRJZRKCX1sXffD3cEB7AoEJEZCgGFSKRFclrUalldk+lopFjVIiIjMCgQiQyjlEhIhIPgwqRyDhGhYhIPAwqRCLjGBUiIvEwqBCJjGNUiIjEw6BCJDKOUSEiEg+DCpHIOEaFiEg8DCpERERktxhUiETGrh8iIvEwqBCJzE/LjB8ldv0QERmOQYVIZP/cl6f1XGJUIKcnExEZgUGFSERF8locK6zQen7RhD5WrA0RkeNjUCES0cli7SEFAC5er7FSTYiInAODCpGoJDrPClaqBRGRs2BQIRLRsHA/neeHR/hbqSZERM6BQYVIRBGBXojXEkbiI/w5kJaIyEgMKkQiW/uHwUiMClQ7lhgViLV/GGyjGhEROa5Otq4AkbORebhhc8pQFJfXoaSiDmH+nmxJISIyEYMKkYWEBzCgEBGZi10/REREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i7N+iMxUJK/F5ZsKTkMmIrIABhUiE1UpGjB7cxYySypVxxKjArFqRixkHm42rBkRkfNg1w+RCaoUDRi9Il0tpADA0QI55m3NtlGtiIicD4MKkQme2pSFSkVju+NNAnA4X47i8job1IqIyPkwqBAZqUhei6zLlTqvKalgUCEiEgODCpGRLt9U6L0mzJ+DaomIxMCgQmQkPz0DZePCfDn7h4hIJDYNKmvWrEFMTAykUimkUini4+Oxd+9e1fmPP/4YSUlJkEqlkEgkqKqq0ltmamoq4uLi4O3tjaCgIEybNg15eXlq1yQlJUEikaj9PPvss2K/PXJSK7/P13rO18MN65LjrFgbIiLnZtOg0qtXLyxfvhynT59GVlYWxowZg6lTp+LChQsAAIVCgYkTJ2Lp0qUGl5mRkYE5c+bgxIkTOHDgABobGzF+/HjU1amPGZg9ezZu3Lih+nn77bdFfW/knIrktTicL9d6ftOfhnJqMhGRiGy6jsqUKVPUHi9btgxr1qzBiRMn0L9/fyxYsAAAkJ6ebnCZ+/btU3u8ceNGBAUF4fTp00hMTFQd9/DwwD333GNy3alj0jc+paKuwUo1ISLqGOxmjEpTUxO2bduGuro6xMfHi1ZudXU1AMDPz0/t+Oeff46AgAAMGDAAS5YsgUKh+wuovr4eNTU1aj/U8YT6eeg8z0G0RETisvnKtOfPn0d8fDzu3LkDLy8v7Ny5E9HR0aKU3dzcjAULFiAhIQEDBgxQHX/88ccRGhqKHj164Ny5c/jLX/6CvLw8fPXVV1rLSk1NxRtvvCFKvchxRQR6ITEqEEcLytEkCKrjrhIJEiIDOIiWiEhkEkFo9WlrAw0NDbhy5Qqqq6uxY8cOrFu3DhkZGWphJT09HaNHj0ZlZSV8fHwMLvu5557D3r17ceTIEfTq1UvrdYcOHcLYsWNRUFCA3r17a7ymvr4e9fX1qsc1NTUIDg5GdXU1pFKpwXUix1etaMS8rdlqY1W4dD4RkeFqamogk8kM+g61eYtK586dERkZCQAYPHgwMjMz8d577+Gjjz4yq9y5c+diz549OHz4sM6QAgDDhg0DAJ1Bxd3dHe7u7mbViZyDzMMNm1OGori8DiUVddyMkIjIgmweVNpqbm5Wa7kwliAImDdvHnbu3In09HSEh4frfU5OTg4AoHv37ia/LnUcrXdLHt03yNbVISJyajYNKkuWLMGkSZMQEhKCW7duYcuWLUhPT8f+/fsBAKWlpSgtLUVBQQGAlvEs3t7eCAkJUQ2OHTt2LKZPn465c+cCAObMmYMtW7Zg165d8Pb2RmlpKQBAJpOha9euKCwsxJYtW/DQQw/B398f586dw4svvojExETExMTY4C6Qo6hSNGD+1hx2+RARWZFNZ/2UlZUhOTkZffv2xdixY5GZmYn9+/dj3LhxAIC1a9ciNjYWs2fPBgAkJiYiNjYWu3fvVpVRWFiI8vJy1eM1a9aguroaSUlJ6N69u+rniy++ANDS1fTf//4X48ePx7333ouFCxfi0UcfxTfffGPFd06OaP7WHBwpUF9D5WhBOXdLJiKyIJsPpnVUxgwEIsd39molpq4+pvV82qIkjlMhIjKQMd+hdrOOCpE9++vOXJ3nuVsyEZFlMKgQ6VEkr0Xudd0L/HGhNyIiy2BQIdJD37L5A3pK2e1DRGQhDCpEeuj7RzJ3dKRV6kFE1BExqBDpUSiv1Xm+StFopZoQEXU8DCpEemw9dUXneU6bIyKyHAYVIh2K5LXIL9M9o2d4hL+VakNE1PEwqBDpcFHPbJ9+3b05kJaIyIIYVIh02HisROf5fz7KbReIiCyJQYVIiyJ5LbIuV2o9Hxfmi5hePtarEBFRB8SgQqRBywaEuvfwmTkizDqVISLqwBhUiDSYvTkLF/SMT+nfQ2al2hARdVydbF0BIntSpWjAU5uydHb5uEiAkZGBHERLRGQFbFEhamX25iyc1hFSACC6hxSrZsRaqUZERB0bW1SI0NKS8sf1J3H+mu7uHgBYNeN+yDzcrFArIiJiUKEOr0rRgNEr0lGpZyl8dvkQEVkfu36ow/vj+pN6QwoADA71ZZcPEZGVsUWFOizlwFl93T0SAENCfbH92RHWqRgREakwqFCHNX9rDs7oGTgLAEPCfLEuOc4KNSIiorYYVKhDysgrw+F8ud7rBvaUsiWFiMiGGFSoQ2lZcTbHoJDi6+GGz1KGW6FWRESkDYMKdSiGrJMCtLSkfJYynNOQiYhsjEGFOgRDVpwFWqbBDQ71xfbn2N1DRGQPGFSoQzC0JWVkVCCnIBMR2REGFXJqhrakAMCnKUMxKirQCrUiIiJDMaiQUzNkCrJyxVmGFCIi+8OgQk7L0CnIXHGWiMh+MaiQ0zF0CjJXnCUisn8MKuRUiuS1mL8tGxev698FmSvOEhHZPwYVcgrGLOSmmoLMlhQiIrvHoEJOYf7WHBwtKDfoWk5BJiJyHAwq5LCK5LW4fFMBV4nEoJYUgFOQiYgcDYMKOZycK5V4ZVcucq/pH4ei5CqRICEygCGFiMjBMKiQwzAloCglRAawu4eIyAExqJDdKpLX4mTxTdxuuIu9uaXILNG/umxrLgCie0ix6vH7ER7gaZlKEhGRRTGokN2pUjTguc/O4HhRhVnlKAfNcgdkIiLHxaBCdkE5MDbM3xOv7bpgckj5NGUo7jYLCPP3ZCsKEZETYFAhmzJm/RNduF8PEZFzYlAhm1C2oLz/33xkX60yu7yRkVwbhYjIGTGokMW17tbx9XATpQVFaUAPKd6aPhAxwT6ilEdERPaFQYVEp2u2jq+HG2puN5r9GgwoREQdA4MKicaQ2TqVCtNDSmywD54aGY7onjIOlCUi6iAYVEgUyl2LTVmMTZtPU4bi58rbkAAYFuHPcEJE1AExqJBZqhQNmL05y+jF2PSJj/DnDB4iImJQIdNVKRqQ+HYaau7cFbXcRO5uTERE/8OgQiYxNaS4AJB5uKmNVUmMCsSi8X1QoWjgQm1ERKSGQYWMViSvxTOfZpnUkqJc1v6mogElFXUOFUxaT7N2lDoTETk6BhUymKmryGqarSPzcHOYL/uzVyuxaPs55JfVqo4lch8hIiKrYFAhg83fmoOjBeUGXRvq54Hnkno79GydKkUDZm3I1Lhy7tECOeZtzcbmlKHWrxgRUQfCoEIGKZLXGtySIu3SCbvnjnTo1oYqRQNGr0jXuu5LkwAczpejuLzOYYMYEZEjcLF1BcgxXL6pMOg6aZdO+OHPYxw6pADArA2nDFqcrqSizgq1ISLquNiiQjopB5C6SiR6r40L9cW6mXEOH1KK5LXIvlpt0LVh/mxNISKyJAYV0kjTwFnlPj1Nwq/XuQCI7iHFqsfvd5oukJPFNw26LirIy2neMxGRvWJQITXKFpQP0wpw5nKV2rlqRWO7NVBGOuHsF/mtOwZdt3B8HwvXhIiIGFQIgGFTj5vRsqngpylDcbdZcNr1RAK93Q26rsqMDRaJiMgwDCqk2lDw4nXDNhS82yxgdN8gC9fKdoaF+xt0naD/EiIiMhODSgdm6gJuzj6ANCLQC3Fhvno3WhweYVigISIi0zGodGDGLOAGAK4SCRIiA5yyu6ctN1fdM/fjHXghOyIiR8Kg0kFl5JUZ3ZKSEBnQIXY1LpLX4lhhhdbz0i6d8PajMVasERFRx8Wg0sEY093jKpHg/hAfPD8m0mkHzmqib3G7mjt38ZevzmHL7OFWqhERUcfFoNLBGNPdo2xBcaapx4YI9fPQe82xwgoun09EZAUMKh2IIfv1OOMCbsY4/3MVpq0+atC1J4sqOuQ9IiKyJgYVJ6ZcvE3ZbWPIfj3OuICbMaZ8YFhIATg9mYjIGhhUnJCmcSiJUYF6V1L9NGUoRkUFWrp6duuLU1eMup7Tk4mILI9BxQlpGoeifJwYFYijBeVoEn5tD1BOO+6oIUXZ8vTGN7kGP4fTk4mIrINBxcloG4fSJAg4nC/H7rkJAKB2TUeadrzn3HXcrGvA2H7dIO3SCX/dmYtcA1fkVYoL9cXaPwy2UC2JiKg1BhUno28cSkVdAzanDEVxeR1KKuqcdtpx6/E5Nbcb8PL2c/iprFZ1fuOxyyaVGxvig+3PjRCrmkREpAeDioNrO2BW39Ra5fL34QHOGVBM3RbAED1l7tj45FDRyyUiIu0YVByUtgGzq2bE6hyH4izhpG1AUzJ2WwBjHF3yoEXKJSIi7RhUHJS2AbPztmZj1YxYzNua7ZTjUHQFtIq6eou0pADAf/7IMSlERLbAoOKA9A2Yvalw3HEo2lpKlHQFtFkjwyxSp6FhfhjX/x6LlE1ERLoxqDiI1l/g+gbMllTUqcagOEpAqVI04KlNWci6XKk6lthm8Tl9Ae2pUWGi10tZByIisg0GFTunqatjSKivzucoB8zaqyJ5LT44VIBLN6rh59kZIX6e2H32OuoamtSuO5Ivx7yt2dic0jKAVV9AaxI0rxNjiAE9pZg7OhLubq7o5CLB3WbBoVqiiIicFYOKndPU1ZF9pQq+Hm6ouX3XoQbMVikakPzJSZz7WX3dkqOFNzVe34yW9V6Um/8ZMqNJ0/gc9Ws8EN/bDw8N7IFevh4O1zVGRNTRMKjYMV1dHZWKRsSF+SKz5NeuEnsfMDv1gyO4fPO20c9TdmVFBHoZNKOp7fgcZRmaAgkDChGRfXOx5YuvWbMGMTExkEqlkEqliI+Px969e1XnP/74YyQlJUEqlUIikaCqqkpvmampqYiLi4O3tzeCgoIwbdo05OXlabxWEARMmjQJEokEX3/9tUjvSjz6ujqeHx2JtEVJ2DArDmmLkrA5ZajdbibYMsbG+JACqHdlrZoRi4TIALXzmgJaeIAnRvcNUo3TUf43ERE5Fpu2qPTq1QvLly9HVFQUBEHApk2bMHXqVGRnZ6N///5QKBSYOHEiJk6ciCVLlhhUZkZGBubMmYO4uDjcvXsXS5cuxfjx43Hx4kV4eqp/Uf373/+GRCKxxFsziSmLtznCgNkqRQOmrDpi0nPjQn3V3p/Mw81hZzQREZHxbBpUpkyZovZ42bJlWLNmDU6cOIH+/ftjwYIFAID09HSDy9y3b5/a440bNyIoKAinT59GYmKi6nhOTg5WrlyJrKwsdO/e3eT3IAZnXrytSF6L+Vuz2w2UNYSvhxvWzYzTeM4RAhoREZnPbsaoNDU1Yfv27airq0N8fLxo5VZXVwMA/Pz8VMcUCgUef/xxrF69GvfcY9j6GPX19aivr1c9rqkxbiM7XZxx8TZzl7KPC/PFuuQ4u+3KIiIi67B5UDl//jzi4+Nx584deHl5YefOnYiOjhal7ObmZixYsAAJCQkYMGCA6viLL76IESNGYOrUqQaXlZqaijfeeEOUerVm7OJtrpKWabg3FQ12/SVuylL23u6u+NuUaMSF+bO1hIiIANhBUOnbty9ycnJQXV2NHTt2YObMmcjIyBAlrMyZMwe5ubk4cuTX8RG7d+/GoUOHkJ2dbVRZS5YswUsvvaR6XFNTg+DgYLPraOjibb4ebnhtV4nG7iF7Cyzawpcun6YMxaioQAvViIiIHJVNZ/0AQOfOnREZGYnBgwcjNTUVgwYNwnvvvWd2uXPnzsWePXuQlpaGXr16qY4fOnQIhYWF8PHxQadOndCpU0tWe/TRR5GUlKS1PHd3d9XsJOWPGAzd7VhX95C90Re+WuvkIsF380YypBARkUY2b1Fpq7m5WW0siLEEQcC8efOwc+dOpKenIzw8XO384sWL8dRTT6kdGzhwIN599912g3utwZC1QfR1DykXRLMFTXvz6AtfABDk7Y45o3tj5ohwvdcSEVHHZdOgsmTJEkyaNAkhISG4desWtmzZgvT0dOzfvx8AUFpaitLSUhQUFABoGc/i7e2NkJAQ1eDYsWPHYvr06Zg7dy6Alu6eLVu2YNeuXfD29kZpaSkAQCaToWvXrrjnnns0DqANCQlpF2qsRd+AWUO7hwD9m/qJ5ezVSvx1Zy5yr/86qFjZFaUtfLlIgOgeUqyacT/HoBARkUFsGlTKysqQnJyMGzduQCaTISYmBvv378e4ceMAAGvXrlUbwKqcXrxhwwY8+eSTAIDCwkKUl//aJbJmzRoAaNeN0/o59kbf2iCGdA/pmuIs5hgWXbN5lF1Rm1OGagxfIyPtc0wNERHZL4kgGLl7GwFoGUwrk8lQXV0t2ngVXZLXn9LaPbQ5Zaje82LW40iBHM06fmvSFiWpghYXZiMioraM+Q61+WBaMoyupeOVY1ja7hjcegyLuYrktdh66jIO5+sOKUBLV5QSl68nIiJz2N1gWtJMV/fQmauVOp9rzhgWUxZua703DxERkTkYVByMpqXjLTmGxZiF21wAjIwKZOsJERGJhl0/TkA5y8a1zQaLrhIJEv8XHExZh0Vbl5I2I/8XfIiIiMTCoOIkLDGGxdCF2wb0lGL33ARsThnKGT1ERCQqdv04CUuMYdHXpZT6yEAMj+C+PEREZDkMKk5G7DEs8RH+OFV8U+O05xlDQ8StPBERURvs+ukAzBnDIpFAa5cSERGRpbFFpYPQtUy/rr2EjhVWIG1REgBw4TYiIrI6BpUOwtwxLFy0jYiIbIFBpYMxdQwLERGRLXCMChk0hoWIiMgWGFQIgO51WIiIiGyFXT8EQPcYFiIiIlthUCE1msawEBER2Qq7foiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdktBhUiIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdmtTraugKMSBAEAUFNTY+OaEBERORbld6fyu1QXBhUT3bp1CwAQHBxs45oQERE5plu3bkEmk+m8RiIYEmeonebmZly/fh3e3t6QSCQml1NTU4Pg4GBcvXoVUqlUxBo6Ft6HX/FetOB9aMH70IL3oYWz3AdBEHDr1i306NEDLi66R6GwRcVELi4u6NWrl2jlSaVSh/6lEwvvw694L1rwPrTgfWjB+9DCGe6DvpYUJQ6mJSIiIrvFoEJERER2i0HFxtzd3fHaa6/B3d3d1lWxKd6HX/FetOB9aMH70IL3oUVHvA8cTEtERER2iy0qREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoGKgNWvWICYmRrXITnx8PPbu3dvuOkEQMGnSJEgkEnz99dc6y5RIJBp/3nnnHdU1Z86cwbhx4+Dj4wN/f388/fTTqK2tVSvnypUrmDx5Mjw8PBAUFISXX34Zd+/eFeV9t2XP90FTGdu2bRPlfbdliftQW1uLuXPnolevXujatSuio6Oxdu1atWvu3LmDOXPmwN/fH15eXnj00Ufxyy+/qF1jzd8HwL7vRUf4nfj444+RlJQEqVQKiUSCqqqqduXcvHkTTzzxBKRSKXx8fJCSktLu349Y7Pk+hIWFtft9WL58uTlvVytb3IebN29i3rx56Nu3L7p27YqQkBDMnz8f1dXVauVY+zPCbAIZZPfu3cK3334r/PTTT0JeXp6wdOlSwc3NTcjNzVW77l//+pcwadIkAYCwc+dOnWXeuHFD7eeTTz4RJBKJUFhYKAiCIFy7dk3w9fUVnn32WeHHH38UTp06JYwYMUJ49NFHVWXcvXtXGDBggPDggw8K2dnZwnfffScEBAQIS5YsEf0eCIL93gdBEAQAwoYNG9TKun37tqjvX8kS92H27NlC7969hbS0NKG4uFj46KOPBFdXV2HXrl2qa5599lkhODhYOHjwoJCVlSUMHz5cGDFihOq8tX8fBMF+74UgdIzfiXfffVdITU0VUlNTBQBCZWVlu3ImTpwoDBo0SDhx4oTwww8/CJGRkcKMGTPEeNvt2PN9CA0NFd58802134fa2lox3nY7trgP58+fFx555BFh9+7dQkFBgXDw4EEhKirKpt8ZYmBQMYOvr6+wbt061ePs7GyhZ8+ewo0bNwz6pWtr6tSpwpgxY1SPP/roIyEoKEhoampSHTt37pwAQMjPzxcEQRC+++47wcXFRSgtLVVds2bNGkEqlQr19fUmvjPj2MN9EATBpNcSk7n3oX///sKbb76pduz+++8X/vrXvwqCIAhVVVWCm5ubsH37dtX5S5cuCQCE48ePC4JgH78PgmAf90IQnP93orW0tDSNX9AXL14UAAiZmZmqY3v37hUkEolw7do149+UCezhPghCS1B59913TXkLorDmfVD68ssvhc6dOwuNjY2CINjPZ4Qx2PVjgqamJmzbtg11dXWIj48HACgUCjz++ONYvXo17rnnHqPL/OWXX/Dtt98iJSVFday+vh6dO3dW27Cpa9euAIAjR44AAI4fP46BAweiW7duqmsmTJiAmpoaXLhwwaT3Zyh7ug9Kc+bMQUBAAIYOHYpPPvnEoC3EzSXWfRgxYgR2796Na9euQRAEpKWl4aeffsL48eMBAKdPn0ZjYyMefPBB1XPuvfdehISE4Pjx4wBs+/sA2Ne9UHLm3wlDHD9+HD4+PhgyZIjq2IMPPggXFxecPHnSuDdmJHu6D0rLly+Hv78/YmNj8c4771ily8OW96G6uhpSqRSdOrVs7WfrzwiT2DAkOZxz584Jnp6egqurqyCTyYRvv/1Wde7pp58WUlJSVI9h5F9y//znPwVfX1+1Zunc3FyhU6dOwttvvy3U19cLN2/eFB599FEBgPDWW28JgtDSFDh+/Hi1surq6gQAwnfffWfiO9XNHu+DIAjCm2++KRw5ckQ4c+aMsHz5csHd3V147733zHuzOoh9H+7cuSMkJycLAIROnToJnTt3FjZt2qQ6//nnnwudO3du97y4uDjhz3/+syAItvl9EAT7vBeC4Py/E61pa0lYtmyZ0KdPn3bXBwYGCh9++KHhb84I9ngfBEEQVq5cKaSlpQlnz54V1qxZI/j4+AgvvviiSe/RELa8D4IgCHK5XAgJCRGWLl2qOmarzwhzcPdkI/Tt2xc5OTmorq7Gjh07MHPmTGRkZKCgoACHDh1Cdna2yWV/8skneOKJJ9ClSxfVsf79+2PTpk146aWXsGTJEri6umL+/Pno1q2b3m2xLcle78Pf/vY31X/Hxsairq4O77zzDubPn29yfXQR+z6sWrUKJ06cwO7duxEaGorDhw9jzpw56NGjh1rLgT2y13vB3wnbsNf78NJLL6n+OyYmBp07d8YzzzyD1NRUiyxJb8v7UFNTg8mTJyM6Ohqvv/66iO/KBmydlBzZ2LFjhaefflp44YUXBIlEIri6uqp+AAguLi7CAw88oLecw4cPCwCEnJwcrdeUlpYKt27dEmprawUXFxfhyy+/FARBEP72t78JgwYNUru2qKhIACCcOXPGnLdnMHu4D5rs2bNHACDcuXPHlLdlNHPug0KhENzc3IQ9e/aoHU9JSREmTJggCIIgHDx4UONfiiEhIcK//vUvQRDs4/dBEOzjXmjibL8TrWlrSVi/fr3g4+OjdqyxsVFwdXUVvvrqK7Pen6Hs4T5okpubKwAQfvzxR1PeltGsdR9qamqE+Ph4YezYse0Gj9vLZ4QxOEbFDM3Nzaivr8fixYtx7tw55OTkqH4A4N1338WGDRv0lrN+/XoMHjwYgwYN0npNt27d4OXlhS+++AJdunTBuHHjAADx8fE4f/48ysrKVNceOHAAUqkU0dHR5r1BA9nDfdAkJycHvr6+Vtu8y5z70NjYiMbGxnYtZa6urmhubgYADB48GG5ubjh48KDqfF5eHq5cuaLq97aH3wfAPu6FJs72O2GI+Ph4VFVV4fTp06pjhw4dQnNzM4YNG2b8mzKBPdwHTXJycuDi4oKgoCCzyjGUNe5DTU0Nxo8fj86dO2P37t1qrdOA/XxGGMXWSclRLF68WMjIyBCKi4uFc+fOCYsXLxYkEonw/fffa7weGvob+/bt2+4vmOrqasHDw0NYs2aNxnJWrVolnD59WsjLyxM++OADoWvXrmp97MqpZuPHjxdycnKEffv2CYGBgRabamav92H37t3Cf/7zH+H8+fNCfn6+8OGHHwoeHh7Cq6++at4b1sIS9+GBBx4Q+vfvL6SlpQlFRUXChg0bhC5duqiNI3j22WeFkJAQ4dChQ0JWVpYQHx8vxMfHq85b+/dBEOz3XnSU34kbN24I2dnZwn/+8x8BgHD48GEhOztbqKioUF0zceJEITY2Vjh58qRw5MgRISoqymLTk+31Phw7dkx49913hZycHKGwsFD47LPPhMDAQCE5OVn8myDY5j5UV1cLw4YNEwYOHCgUFBSoTcO+e/euIAi2+YwwF4OKgf70pz8JoaGhQufOnYXAwEBh7NixWn/hBEHzLx3+t6ZDax999JHQtWtXoaqqSmM5f/zjHwU/Pz+hc+fOQkxMjLB58+Z215SUlAiTJk0SunbtKgQEBAgLFy5UTUUTm73eh7179wr33Xef4OXlJXh6egqDBg0S1q5dqzalWUyWuA83btwQnnzySaFHjx5Cly5dhL59+worV64UmpubVdfcvn1beP755wVfX1/Bw8NDmD59unDjxg21cq35+yAI9nsvOsrvxGuvvSYAaPfTupyKigphxowZgpeXlyCVSoVZs2YJt27dEuutq7HX+3D69Glh2LBhgkwmE7p06SL069dPeOuttyzWDWiL+6Ds9tL0U1xcrCrH2p8R5pIIghXm6hERERGZgGNUiIiIyG4xqBAREZHdYlAhIiIiu8WgQkRERHaLQYWIiIjsFoMKERER2S0GFSIiIrJbDCpEZLYnn3wS06ZNs3U1bOL111/HfffdZ+tqEDktBhUiolYkEgm+/vprW1eDiP6HQYWIiIjsFoMKERlsx44dGDhwILp27Qp/f388+OCDqKurU51fsWIFunfvDn9/f8yZMweNjY2qc59++imGDBkCb29v3HPPPXj88cfVdnBNT0+HRCLBt99+i5iYGHTp0gXDhw9Hbm6uWh2OHDmCUaNGoWvXrggODsb8+fPV6qBLWFgY/v73v2PGjBnw9PREz549sXr1arXzADB9+nRIJBLVY2M0NzfjzTffRK9eveDu7o777rsP+/btU50vKSmBRCLBV199hdGjR8PDwwODBg3C8ePHjX4too6AQYWIDHLjxg3MmDEDf/rTn3Dp0iWkp6fjkUcegXK7sLS0NBQWFiItLQ2bNm3Cxo0bsXHjRtXzGxsb8fe//x1nz57F119/jZKSEjz55JPtXufll1/GypUrkZmZicDAQEyZMkUVeAoLCzFx4kQ8+uijOHfuHL744gscOXIEc+fONfh9vPPOOxg0aBCys7OxePFivPDCCzhw4AAAIDMzEwCwYcMG3LhxQ/XYGO+99x5WrlyJFStW4Ny5c5gwYQIefvhh5Ofnq13317/+FYsWLUJOTg769OmDGTNm4O7du0a/HpHTs/GmiETkIE6fPi0AEEpKStqdmzlzphAaGqraSl4QBOGxxx4Tfv/732stLzMzUwCg2sVXufPrtm3bVNdUVFQIXbt2Fb744gtBEAQhJSVFePrpp9XK+eGHHwQXFxfh9u3bet9DaGioMHHiRLVjv//974VJkyapHkPDLra6vPbaa8KgQYNUj3v06CEsW7ZM7Zq4uDjh+eefFwRBEIqLiwUAwrp161TnL1y4IAAQLl26ZPDrEnUUbFEhIoMMGjQIY8eOxcCBA/HYY4/hP//5DyorK1Xn+/fvD1dXV9Xj7t27q3XtnD59GlOmTEFISAi8vb3xwAMPAACuXLmi9jrx8fGq//bz80Pfvn1x6dIlAMDZs2exceNGeHl5qX4mTJiA5uZmFBcXG/Q+WpevfKws31w1NTW4fv06EhIS1I4nJCS0e42YmBjVf3fv3h0A1O4XEbVgUCEig7i6uuLAgQPYu3cvoqOjsWrVKvTt21cVENzc3NSul0gkaG5uBgDU1dVhwoQJkEql+Pzzz5GZmYmdO3cCABoaGgyuQ21tLZ555hnk5OSofs6ePYv8/Hz07t1bpHdqHa3vl0QiAQDV/SKiX3WydQWIyHFIJBIkJCQgISEBr776KkJDQ1WBQ5cff/wRFRUVWL58OYKDgwEAWVlZGq89ceIEQkJCAACVlZX46aef0K9fPwDA/fffj4sXLyIyMtLk93DixIl2j5XlAy0BoqmpyaSypVIpevTogaNHj6pajADg6NGjGDp0qGkVJurgGFSIyCAnT57EwYMHMX78eAQFBeHkyZOQy+Xo168fzp07p/O5ISEh6Ny5M1atWoVnn30Wubm5+Pvf/67x2jfffBP+/v7o1q0b/vrXvyIgIEC1mNxf/vIXDB8+HHPnzsVTTz0FT09PXLx4EQcOHMAHH3xg0Ps4evQo3n77bUybNg0HDhzA9u3b8e2336rOh4WF4eDBg0hISIC7uzt8fX0Nu0H/8/LLL+O1115D7969cd9992HDhg3IycnB559/blQ5RNSCXT9EZBCpVIrDhw/joYceQp8+ffDKK69g5cqVmDRpkt7nBgYGYuPGjdi+fTuio6OxfPlyrFixQuO1y5cvxwsvvIDBgwejtLQU33zzDTp37gygZVxHRkYGfvrpJ4waNQqxsbF49dVX0aNHD4Pfx8KFC5GVlYXY2Fj84x//wL/+9S9MmDBBdX7lypU4cOAAgoODERsba3C5SvPnz8dLL72EhQsXYuDAgdi3bx92796NqKgoo8siIkAiCP+bW0hEZEPp6ekYPXo0Kisr4ePjY5HXCAsLw4IFC7BgwQKLlE9E4mOLChEREdktBhUicgo//PCD2rTltj+m6t+/v9YyOe6EyPLY9UNETuH27du4du2a1vOmzhS6fPmy2lYArXXr1g3e3t4mlUtEhmFQISIiIrvFrh8iIiKyWwwqREREZLcYVIiIiMhuMagQERGR3WJQISIiIrvFoEJERER2i0GFiIiI7BaDChEREdmt/w+Z4VZfonV5rwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "base = trip.plot.scatter(x='shape_pt_lon', y='shape_pt_lat');\n", "fig = base.get_figure()\n", "glue('exercise-06-f2', fig, display=False)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 06-g" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "tags": [] }, "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", "
trip_idshape_dist_traveled
010004214_01102311152.0
110004215_01102311152.0
21001407_01102315061.0
310015281_07102321688.0
410015281_08102321688.0
.........
3980869998411_09102314147.0
3980879998411_13102314040.0
3980889999194_06102313597.0
3980899999194_08102313597.0
3980909999194_15102313597.0
\n", "

398091 rows × 2 columns

\n", "
" ], "text/plain": [ " trip_id shape_dist_traveled\n", "0 10004214_011023 11152.0\n", "1 10004215_011023 11152.0\n", "2 1001407_011023 15061.0\n", "3 10015281_071023 21688.0\n", "4 10015281_081023 21688.0\n", "... ... ...\n", "398086 9998411_091023 14147.0\n", "398087 9998411_131023 14040.0\n", "398088 9999194_061023 13597.0\n", "398089 9999194_081023 13597.0\n", "398090 9999194_151023 13597.0\n", "\n", "[398091 rows x 2 columns]" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "# Get total distance traveled per 'trip_id'\n", "stop_times = pd.read_csv('data/gtfs/stop_times.txt')\n", "stop_times = stop_times.groupby('trip_id')['shape_dist_traveled'].max()\n", "stop_times = stop_times.reset_index()\n", "stop_times" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "tags": [ "remove-cell" ] }, "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", "
trip_idshape_dist_traveled
010004214_01102311152.0
110004215_01102311152.0
21001407_01102315061.0
310015281_07102321688.0
410015281_08102321688.0
.........
3980869998411_09102314147.0
3980879998411_13102314040.0
3980889999194_06102313597.0
3980899999194_08102313597.0
3980909999194_15102313597.0
\n", "

398091 rows × 2 columns

\n", "
" ], "text/plain": [ " trip_id shape_dist_traveled\n", "0 10004214_011023 11152.0\n", "1 10004215_011023 11152.0\n", "2 1001407_011023 15061.0\n", "3 10015281_071023 21688.0\n", "4 10015281_081023 21688.0\n", "... ... ...\n", "398086 9998411_091023 14147.0\n", "398087 9998411_131023 14040.0\n", "398088 9999194_061023 13597.0\n", "398089 9999194_081023 13597.0\n", "398090 9999194_151023 13597.0\n", "\n", "[398091 rows x 2 columns]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-g1" } }, "output_type": "display_data" } ], "source": [ "glue('exercise-06-g1', stop_times)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "tags": [] }, "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", "
route_idtrip_idshape_dist_traveled
0117336167_0810237258.0
1213076786_0810237088.0
235655904_0110239883.0
34585026983_0110237025.0
455656121_0810239750.0
............
8183373151_88437NaN
8184373161_88438NaN
818537342585305994_12102316432.0
818637343585305995_12102316761.0
8187373501_88086NaN
\n", "

8188 rows × 3 columns

\n", "
" ], "text/plain": [ " route_id trip_id shape_dist_traveled\n", "0 1 17336167_081023 7258.0\n", "1 2 13076786_081023 7088.0\n", "2 3 5655904_011023 9883.0\n", "3 4 585026983_011023 7025.0\n", "4 5 5656121_081023 9750.0\n", "... ... ... ...\n", "8183 37315 1_88437 NaN\n", "8184 37316 1_88438 NaN\n", "8185 37342 585305994_121023 16432.0\n", "8186 37343 585305995_121023 16761.0\n", "8187 37350 1_88086 NaN\n", "\n", "[8188 rows x 3 columns]" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Join with trips to get 'route_id' per trip\n", "trips = pd.read_csv('data/gtfs/trips.txt')\n", "trips = trips[['trip_id', 'route_id']]\n", "trips = pd.merge(trips, stop_times, on='trip_id')\n", "trips = trips.groupby('route_id').first()\n", "trips = trips.reset_index()\n", "trips" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "tags": [ "remove-cell" ] }, "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", "
route_idtrip_idshape_dist_traveled
0117336167_0810237258.0
1213076786_0810237088.0
235655904_0110239883.0
34585026983_0110237025.0
455656121_0810239750.0
............
8183373151_88437NaN
8184373161_88438NaN
818537342585305994_12102316432.0
818637343585305995_12102316761.0
8187373501_88086NaN
\n", "

8188 rows × 3 columns

\n", "
" ], "text/plain": [ " route_id trip_id shape_dist_traveled\n", "0 1 17336167_081023 7258.0\n", "1 2 13076786_081023 7088.0\n", "2 3 5655904_011023 9883.0\n", "3 4 585026983_011023 7025.0\n", "4 5 5656121_081023 9750.0\n", "... ... ... ...\n", "8183 37315 1_88437 NaN\n", "8184 37316 1_88438 NaN\n", "8185 37342 585305994_121023 16432.0\n", "8186 37343 585305995_121023 16761.0\n", "8187 37350 1_88086 NaN\n", "\n", "[8188 rows x 3 columns]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-g2" } }, "output_type": "display_data" } ], "source": [ "glue('exercise-06-g2', trips)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "tags": [] }, "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", "
route_idroute_short_nameroute_long_nameservice_idtrip_idtrip_headsigndirection_idshape_id
011ת. רכבת יבנה מערב-יבנה<->ת. רכב...1274917336167_081023רכבת יבנה מזרח0135197.0
111ת. רכבת יבנה מערב-יבנה<->ת. רכב...1275017336049_081023רכבת יבנה מזרח0135197.0
211ת. רכבת יבנה מערב-יבנה<->ת. רכב...127495655787_081023רכבת יבנה מזרח0135197.0
311ת. רכבת יבנה מערב-יבנה<->ת. רכב...1275017336048_081023רכבת יבנה מזרח0135197.0
411ת. רכבת יבנה מערב-יבנה<->ת. רכב...1275017336051_081023רכבת יבנה מזרח0135197.0
...........................
39808637350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה100061081_8808680480NaN
39808737350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה100060971_8805880480NaN
39808837350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה100061021_8807080480NaN
39808937350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה100061051_8844380480NaN
39809037350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה100061001_8806480480NaN
\n", "

398091 rows × 8 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "0 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "1 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "2 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "3 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "4 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "... ... ... ... \n", "398086 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "398087 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "398088 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "398089 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "398090 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "\n", " service_id trip_id trip_headsign direction_id shape_id \n", "0 12749 17336167_081023 רכבת יבנה מזרח 0 135197.0 \n", "1 12750 17336049_081023 רכבת יבנה מזרח 0 135197.0 \n", "2 12749 5655787_081023 רכבת יבנה מזרח 0 135197.0 \n", "3 12750 17336048_081023 רכבת יבנה מזרח 0 135197.0 \n", "4 12750 17336051_081023 רכבת יבנה מזרח 0 135197.0 \n", "... ... ... ... ... ... \n", "398086 10006108 1_88086 8048 0 NaN \n", "398087 10006097 1_88058 8048 0 NaN \n", "398088 10006102 1_88070 8048 0 NaN \n", "398089 10006105 1_88443 8048 0 NaN \n", "398090 10006100 1_88064 8048 0 NaN \n", "\n", "[398091 rows x 8 columns]" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Join with routes to get route short/long names\n", "routes = pd.read_csv('data/gtfs/routes.txt')\n", "routes = routes[['route_id', 'route_short_name', 'route_long_name']]\n", "routes = pd.merge(routes, trips, on='route_id')\n", "routes" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "tags": [ "remove-cell" ] }, "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", "
route_idroute_short_nameroute_long_nametrip_idshape_dist_traveled
011ת. רכבת יבנה מערב-יבנה<->ת. רכב...17336167_0810237258.0
121ת. רכבת יבנה מזרח-יבנה<->ת. רכב...13076786_0810237088.0
232ת. רכבת יבנה מערב-יבנה<->ת. רכב...5655904_0110239883.0
34ת. רכבת יבנה מערב-יבנה<->ת. רכב...585026983_0110237025.0
452ת. רכבת יבנה מזרח-יבנה<->ת. רכב...5656121_0810239750.0
..................
818337315NaNתא אוניברסיטה-תל אביב יפו<->באר...1_88437NaN
818437316NaNתא אוניברסיטה-תל אביב יפו<->הרצ...1_88438NaN
81853734246גן טכנולוגי-נצרת<->מסרארה חט''ב...585305994_12102316432.0
81863734346גן טכנולוגי-נצרת<->מסרארה חט''ב...585305995_12102316761.0
818737350NaNבאר שבע מרכז-באר שבע<->נהריה-נהריה1_88086NaN
\n", "

8188 rows × 5 columns

\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "0 1 1 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "1 2 1 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... \n", "2 3 2 ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "3 4 2א ת. רכבת יבנה מערב-יבנה<->ת. רכב... \n", "4 5 2 ת. רכבת יבנה מזרח-יבנה<->ת. רכב... \n", "... ... ... ... \n", "8183 37315 NaN תא אוניברסיטה-תל אביב יפו<->באר... \n", "8184 37316 NaN תא אוניברסיטה-תל אביב יפו<->הרצ... \n", "8185 37342 46 גן טכנולוגי-נצרת<->מסרארה חט''ב... \n", "8186 37343 46 גן טכנולוגי-נצרת<->מסרארה חט''ב... \n", "8187 37350 NaN באר שבע מרכז-באר שבע<->נהריה-נהריה \n", "\n", " trip_id shape_dist_traveled \n", "0 17336167_081023 7258.0 \n", "1 13076786_081023 7088.0 \n", "2 5655904_011023 9883.0 \n", "3 585026983_011023 7025.0 \n", "4 5656121_081023 9750.0 \n", "... ... ... \n", "8183 1_88437 NaN \n", "8184 1_88438 NaN \n", "8185 585305994_121023 16432.0 \n", "8186 585305995_121023 16761.0 \n", "8187 1_88086 NaN \n", "\n", "[8188 rows x 5 columns]" ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-g3" } }, "output_type": "display_data" } ], "source": [ "glue('exercise-06-g3', routes)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "tags": [] }, "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", "
route_idroute_short_nameroute_long_nametrip_idshape_dist_traveled
515519964991ת. מרכזית חוף הכרמל/רציפים בינע...30526427_091023446163.0
547521726991ת. מרכזית אילת/רציפים-אילת<->ת....30526417_061023445475.0
14567307993ת. מרכזית המפרץ/רציפים בינעירונ...2125973_151023432200.0
14557305993ת. מרכזית אילת/רציפים-אילת<->ת....584673295_011023432187.0
11535182399ת. מרכזית חדרה/רציפים-חדרה<->ת....584660100_091023401875.0
\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "5155 19964 991 ת. מרכזית חוף הכרמל/רציפים בינע... \n", "5475 21726 991 ת. מרכזית אילת/רציפים-אילת<->ת.... \n", "1456 7307 993 ת. מרכזית המפרץ/רציפים בינעירונ... \n", "1455 7305 993 ת. מרכזית אילת/רציפים-אילת<->ת.... \n", "1153 5182 399 ת. מרכזית חדרה/רציפים-חדרה<->ת.... \n", "\n", " trip_id shape_dist_traveled \n", "5155 30526427_091023 446163.0 \n", "5475 30526417_061023 445475.0 \n", "1456 2125973_151023 432200.0 \n", "1455 584673295_011023 432187.0 \n", "1153 584660100_091023 401875.0 " ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Sort accordinge to distance traveled\n", "routes = routes.sort_values('shape_dist_traveled', ascending=False).head()\n", "routes" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "tags": [ "remove-cell" ] }, "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", "
route_idroute_short_nameroute_long_nametrip_idshape_dist_traveled
515519964991ת. מרכזית חוף הכרמל/רציפים בינע...30526427_091023446163.0
547521726991ת. מרכזית אילת/רציפים-אילת<->ת....30526417_061023445475.0
14567307993ת. מרכזית המפרץ/רציפים בינעירונ...2125973_151023432200.0
14557305993ת. מרכזית אילת/רציפים-אילת<->ת....584673295_011023432187.0
11535182399ת. מרכזית חדרה/רציפים-חדרה<->ת....584660100_091023401875.0
\n", "
" ], "text/plain": [ " route_id route_short_name route_long_name \\\n", "5155 19964 991 ת. מרכזית חוף הכרמל/רציפים בינע... \n", "5475 21726 991 ת. מרכזית אילת/רציפים-אילת<->ת.... \n", "1456 7307 993 ת. מרכזית המפרץ/רציפים בינעירונ... \n", "1455 7305 993 ת. מרכזית אילת/רציפים-אילת<->ת.... \n", "1153 5182 399 ת. מרכזית חדרה/רציפים-חדרה<->ת.... \n", "\n", " trip_id shape_dist_traveled \n", "5155 30526427_091023 446163.0 \n", "5475 30526417_061023 445475.0 \n", "1456 2125973_151023 432200.0 \n", "1455 584673295_011023 432187.0 \n", "1153 584660100_091023 401875.0 " ] }, "metadata": { "scrapbook": { "mime_prefix": "", "name": "exercise-06-g4" } }, "output_type": "display_data" } ], "source": [ "glue(\"exercise-06-g4\", routes)" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/plain": [ "['ת. מרכזית חוף הכרמל/רציפים בינעירוני-חיפה<->ת. מרכזית אילת/הורדה-אילת-2#',\n", " 'ת. מרכזית אילת/רציפים-אילת<->ת. מרכזית חוף הכרמל/הורדה-חיפה-1#',\n", " 'ת. מרכזית המפרץ/רציפים בינעירוני-חיפה<->ת. מרכזית אילת/הורדה-אילת-2#',\n", " 'ת. מרכזית אילת/רציפים-אילת<->ת. מרכזית המפרץ/הורדה-חיפה-1#',\n", " 'ת. מרכזית חדרה/רציפים-חדרה<->ת. מרכזית אילת/הורדה-אילת-1#']" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routes.head()[\"route_long_name\"].to_list()" ] } ], "metadata": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { "display_name": "Python 3.8.10 64-bit", "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": 4 }