Skip to content

Instantly share code, notes, and snippets.

@invisiblefunnel
Last active October 2, 2020 22:13
Show Gist options
  • Save invisiblefunnel/6015e65684325281e65fa9339a78229b to your computer and use it in GitHub Desktop.
Save invisiblefunnel/6015e65684325281e65fa9339a78229b to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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 &amp; 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