Last active
October 2, 2020 22:13
-
-
Save invisiblefunnel/6015e65684325281e65fa9339a78229b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import matplotlib.pyplot as plt\n", | |
| "import numpy as np\n", | |
| "import partridge as ptg\n", | |
| "import scipy.stats" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "inpath = \"/Users/drw/Downloads/SFMTA-2020-09-04.zip\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<div>\n", | |
| "<style scoped>\n", | |
| " .dataframe tbody tr th:only-of-type {\n", | |
| " vertical-align: middle;\n", | |
| " }\n", | |
| "\n", | |
| " .dataframe tbody tr th {\n", | |
| " vertical-align: top;\n", | |
| " }\n", | |
| "\n", | |
| " .dataframe thead th {\n", | |
| " text-align: right;\n", | |
| " }\n", | |
| "</style>\n", | |
| "<table border=\"1\" class=\"dataframe\">\n", | |
| " <thead>\n", | |
| " <tr style=\"text-align: right;\">\n", | |
| " <th></th>\n", | |
| " <th>route_id</th>\n", | |
| " <th>service_id</th>\n", | |
| " <th>trip_id</th>\n", | |
| " <th>trip_headsign</th>\n", | |
| " <th>direction_id</th>\n", | |
| " <th>block_id</th>\n", | |
| " <th>shape_id</th>\n", | |
| " </tr>\n", | |
| " </thead>\n", | |
| " <tbody>\n", | |
| " <tr>\n", | |
| " <th>0</th>\n", | |
| " <td>15761</td>\n", | |
| " <td>1</td>\n", | |
| " <td>9413147</td>\n", | |
| " <td>Presidio Avenue</td>\n", | |
| " <td>0</td>\n", | |
| " <td>123</td>\n", | |
| " <td>179928</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>1</th>\n", | |
| " <td>15761</td>\n", | |
| " <td>1</td>\n", | |
| " <td>9413148</td>\n", | |
| " <td>Presidio Avenue</td>\n", | |
| " <td>0</td>\n", | |
| " <td>121</td>\n", | |
| " <td>179928</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>2</th>\n", | |
| " <td>15761</td>\n", | |
| " <td>1</td>\n", | |
| " <td>9413149</td>\n", | |
| " <td>Presidio Avenue</td>\n", | |
| " <td>0</td>\n", | |
| " <td>119</td>\n", | |
| " <td>179928</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>3</th>\n", | |
| " <td>15761</td>\n", | |
| " <td>1</td>\n", | |
| " <td>9413150</td>\n", | |
| " <td>Presidio Avenue</td>\n", | |
| " <td>0</td>\n", | |
| " <td>130</td>\n", | |
| " <td>179928</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>4</th>\n", | |
| " <td>15761</td>\n", | |
| " <td>1</td>\n", | |
| " <td>9413151</td>\n", | |
| " <td>Presidio Avenue</td>\n", | |
| " <td>0</td>\n", | |
| " <td>128</td>\n", | |
| " <td>179928</td>\n", | |
| " </tr>\n", | |
| " </tbody>\n", | |
| "</table>\n", | |
| "</div>" | |
| ], | |
| "text/plain": [ | |
| " route_id service_id trip_id trip_headsign direction_id block_id \\\n", | |
| "0 15761 1 9413147 Presidio Avenue 0 123 \n", | |
| "1 15761 1 9413148 Presidio Avenue 0 121 \n", | |
| "2 15761 1 9413149 Presidio Avenue 0 119 \n", | |
| "3 15761 1 9413150 Presidio Avenue 0 130 \n", | |
| "4 15761 1 9413151 Presidio Avenue 0 128 \n", | |
| "\n", | |
| " shape_id \n", | |
| "0 179928 \n", | |
| "1 179928 \n", | |
| "2 179928 \n", | |
| "3 179928 \n", | |
| "4 179928 " | |
| ] | |
| }, | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "view = {\"trips.txt\": {}}\n", | |
| "\n", | |
| "# Choose a date\n", | |
| "view[\"trips.txt\"][\"service_id\"] = ptg.read_busiest_date(inpath)[1]\n", | |
| "\n", | |
| "# Choose a route\n", | |
| "view[\"trips.txt\"][\"route_id\"] = ptg.load_feed(inpath, view).routes.route_id[0]\n", | |
| "\n", | |
| "# Choose a direction\n", | |
| "view[\"trips.txt\"][\"direction_id\"] = ptg.load_feed(inpath, view).trips.direction_id[0]\n", | |
| "\n", | |
| "# Build a working feed\n", | |
| "feed = ptg.load_feed(inpath, view)\n", | |
| "\n", | |
| "feed.trips.head()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<div>\n", | |
| "<style scoped>\n", | |
| " .dataframe tbody tr th:only-of-type {\n", | |
| " vertical-align: middle;\n", | |
| " }\n", | |
| "\n", | |
| " .dataframe tbody tr th {\n", | |
| " vertical-align: top;\n", | |
| " }\n", | |
| "\n", | |
| " .dataframe thead th {\n", | |
| " text-align: right;\n", | |
| " }\n", | |
| "</style>\n", | |
| "<table border=\"1\" class=\"dataframe\">\n", | |
| " <thead>\n", | |
| " <tr style=\"text-align: right;\">\n", | |
| " <th></th>\n", | |
| " <th>stop_id</th>\n", | |
| " <th>stop_code</th>\n", | |
| " <th>stop_name</th>\n", | |
| " <th>stop_desc</th>\n", | |
| " <th>stop_lat</th>\n", | |
| " <th>stop_lon</th>\n", | |
| " <th>zone_id</th>\n", | |
| " <th>stop_url</th>\n", | |
| " </tr>\n", | |
| " </thead>\n", | |
| " <tbody>\n", | |
| " <tr>\n", | |
| " <th>23</th>\n", | |
| " <td>4277</td>\n", | |
| " <td>14277</td>\n", | |
| " <td>Geary Blvd & 33rd Ave</td>\n", | |
| " <td></td>\n", | |
| " <td>37.779735</td>\n", | |
| " <td>-122.493112</td>\n", | |
| " <td></td>\n", | |
| " <td></td>\n", | |
| " </tr>\n", | |
| " </tbody>\n", | |
| "</table>\n", | |
| "</div>" | |
| ], | |
| "text/plain": [ | |
| " stop_id stop_code stop_name stop_desc stop_lat stop_lon \\\n", | |
| "23 4277 14277 Geary Blvd & 33rd Ave 37.779735 -122.493112 \n", | |
| "\n", | |
| " zone_id stop_url \n", | |
| "23 " | |
| ] | |
| }, | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "# Find trips overlapping the time window\n", | |
| "trip_ids = feed.stop_times[\n", | |
| " (feed.stop_times.arrival_time >= 6*60*60) # 6am\n", | |
| " & (feed.stop_times.arrival_time <= 9*60*60) # 9am\n", | |
| "].trip_id.unique()\n", | |
| "\n", | |
| "# Collect the stop_ids for each trip\n", | |
| "trip_stops = []\n", | |
| "for _, stimes in feed.stop_times[feed.stop_times.trip_id.isin(trip_ids)].groupby(\"trip_id\"):\n", | |
| " trip_stops.append(set(stimes.stop_id))\n", | |
| "\n", | |
| "# Find stop_ids shared between all trips\n", | |
| "common_stops = set(trip_stops[0])\n", | |
| "for stop_ids in trip_stops[1:]:\n", | |
| " common_stops &= stop_ids\n", | |
| "\n", | |
| "assert common_stops\n", | |
| "\n", | |
| "# Choose one stop to focus on\n", | |
| "subject_stop_id = list(common_stops)[0]\n", | |
| "\n", | |
| "feed.stops[feed.stops.stop_id==subject_stop_id]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "array([ 8, 8, 8, 8, 8, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n", | |
| " 8, 8, 8, 8, 8, 9, 9, 8, 10, 8, 8, 8, 8, 8, 8, 4, 5,\n", | |
| " 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8,\n", | |
| " 7, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 5,\n", | |
| " 3, 4, 4, 1, 7, 2, 8, 8, 8, 6, 8, 8, 8, 8, 8, 8, 8,\n", | |
| " 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n", | |
| " 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 8, 8, 8, 8, 8, 8, 8,\n", | |
| " 8, 8, 7, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n", | |
| " 6, 8, 6, 8])" | |
| ] | |
| }, | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "stimes = feed.stop_times[feed.stop_times.stop_id==subject_stop_id].sort_values(\"arrival_time\")\n", | |
| "\n", | |
| "headway_seconds = stimes.arrival_time[1:].values - stimes.arrival_time[:-1].values\n", | |
| "headway_minutes = (headway_seconds / 60.).round().astype(np.int)\n", | |
| "\n", | |
| "headway_minutes" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "(7.59, 8.0, 8)" | |
| ] | |
| }, | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "(\n", | |
| " np.mean(headway_minutes).round(2),\n", | |
| " np.median(headway_minutes),\n", | |
| " scipy.stats.mode(headway_minutes).mode[0]\n", | |
| ")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "image/png": "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\n", | |
| "text/plain": [ | |
| "<Figure size 432x288 with 1 Axes>" | |
| ] | |
| }, | |
| "metadata": { | |
| "needs_background": "light" | |
| }, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "plt.hist(headway_minutes, bins=10);" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.8.2" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 4 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment