diff --git a/.gitattributes b/.gitattributes index deda00c72..0df48f948 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,4 @@ portfolio/**/*.ipynb filter=lfs diff=lfs merge=lfs -text -portfolio/ntd_monthly_ridership/**/*.ipynb filter=lfs diff=lfs merge=lfs -text -portfolio/dla/district_*/*.ipynb filter=lfs diff=lfs merge=lfs -text -portfolio/parallel_corridors/district_*/*.ipynb filter=lfs diff=lfs merge=lfs -text -portfolio/district_digest/district_*/*.ipynb filter=lfs diff=lfs merge=lfs -text +portfolio/**/**/*.ipynb filter=lfs diff=lfs merge=lfs -text “portfolio/**/**/*.ipynb” filter=lfs diff=lfs merge=lfs -text “portfolio/**/*.ipynb” filter=lfs diff=lfs merge=lfs -text diff --git a/Makefile b/Makefile index 54f786995..a2af445cd 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,9 @@ build_portfolio_site: #need git rm because otherwise, just local removal, but git change is untracked #git rm portfolio/$(site)/ -rf python portfolio/portfolio.py clean $(site) + python portfolio/portfolio.py build $(site) gcloud auth login --login-config=iac/login.json && gcloud config set project cal-itp-data-infra - python portfolio/portfolio.py build $(site) --deploy + python portfolio/portfolio.py build $(site) --no-execute-papermill --deploy git add portfolio/sites/$(site).yml #make production_portfolio diff --git a/_shared_utils/requirements.txt b/_shared_utils/requirements.txt index 6ac6c4ccf..2b706a34b 100644 --- a/_shared_utils/requirements.txt +++ b/_shared_utils/requirements.txt @@ -3,6 +3,8 @@ altair-transform==0.2.0 great_tables==0.16.1 omegaconf==2.3.0 # better yaml configuration polars==1.22.0 +pytest (>=8.4.1, <9.0.0) quarto-cli==1.6.40 quarto==0.1.0 -pytest (>=8.4.1, <9.0.0) +vegafusion==2.0.2 +vl-convert-python>=1.6.0 diff --git a/portfolio/portfolio.py b/portfolio/portfolio.py index e5005d5b2..e01369c85 100644 --- a/portfolio/portfolio.py +++ b/portfolio/portfolio.py @@ -65,7 +65,7 @@ def parameterize_filename(i: int, old_path: Path, params: Dict) -> Path: class Chapter(BaseModel): - caption: Optional[Any] + caption: Optional[Any] = None notebook: Optional[Path] = None params: Dict = {} sections: List[Dict] = [] @@ -215,7 +215,7 @@ class Site(BaseModel): output_dir: Path name: str title: str - directory: Path + directory: Path readme: Optional[Path] = "README.md" notebook: Optional[Path] = None parts: List[Part] @@ -226,14 +226,14 @@ def __init__(self, **data): for part in self.parts: part.site = self - - @validator('readme', pre=True, always=True) + + @validator('readme', pre=True, always=True, check_fields=False) def default_readme(cls, v, *, values, **kwargs): if "./" in v: return Path(v) else: return (values['directory'] / Path("README.md")) or (values['directory'] / Path(v)) - + @property def slug(self) -> str: return slugify(self.title) diff --git a/portfolio/requirements.txt b/portfolio/requirements.txt index 50300ba82..67ceef25a 100644 --- a/portfolio/requirements.txt +++ b/portfolio/requirements.txt @@ -1,10 +1,10 @@ -papermill~=2.4 -nbformat~=5.8 -typer~=0.9 -jupyter-book==1.0.0 +#papermill~=2.4 +#nbformat~=5.8 +#typer~=0.9 +jupyter-book>=1.0.0 python-slugify==6.1.1 pyaml==21.10.1 -humanize~=4.6 -pydantic~=1.9 +#humanize~=4.6 +#pydantic>=2.0 calitp_data_analysis -axe-selenium-python +axe-selenium-python \ No newline at end of file diff --git a/portfolio/rt_trip_updates_stop_metrics/README.md b/portfolio/rt_trip_updates_stop_metrics/README.md index 71653d77f..10e4e7c42 100644 --- a/portfolio/rt_trip_updates_stop_metrics/README.md +++ b/portfolio/rt_trip_updates_stop_metrics/README.md @@ -1,7 +1,92 @@ # README +One of the most common transit user behaviors is to consult an app (Google Maps, Apple Maps, NextBus, etc) to find out when the bus or train is going to arrive. + +That widely desired piece of information is powered by GTFS Real-Time Trip Updates, specifically the [Stop Time Updates](https://gtfs.org/documentation/realtime/reference/#message-stoptimeupdate) specification. + GTFS Real Time trip updates performance metrics, specifically the stop time update messages. Accurate and reliable information should be provided to transit users for journey planning. These performance metrics provide insights into: + * availability and completeness of RT - is there information available for users? * prediction inconsistency - how much are predictions changing from minute to minute as the bus approaches time of arrival? * prediction reliability and accuracy - are these predictions accurate (when compared to our estimated actual time of arrival)? + + +## Reliable Prediction Accuracy + +The prediction is considered **accurate** if it falls within the bounds of this equation: `-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time to Prediction+1.5)`. + +As the bus approaches each stop, the software is making predictions for when the bus should arrive. When the bus is 30 min away from arrival, there is a more generous buffer for accuracy; this buffer tightens as the bus is nearing the stop. + +| Minutes Until Bus Arives | Accurate Within Bounds | +|--------------------------|---------------------------------| +| 0 min | -0.26 min early - 0.41 min late | +| 10 min | -2.42 min early - 2.44 min late | +| 30 min | -3.44 min early - 3.45 min late | + +* Positive values = arrival came **after** the prediction. + * actual_arrival = 8:05 am + * predicted arrival = 8:00 am + * actual_arrival - predicted_arrival = +5 seconds + * follow the prediction, you will catch the bus +* Negative values = arrival came **before** the prediction. + * actual_arrival = 8:05 am + * predicted arrival = 8:10 am + * actual_arrival - predicted_arrival = -5 seconds + * follow the prediction, you will **miss** the bus...this is very bad! + * we want fewer of these kinds of predictions, and would much rather wait for the bus than to miss it + +## Availability and Completeness of Predictions + +* This metric is the easiest to achieve. For starters, having information is better than no information. +* For each instance of scheduled stop arrival, there is complete information if there are at least 2 predictions each minute. +* For the 30 minute period before the bus arrives at each stop, each minute is an observation that goes into this calculation (up to 30 observations). +* This ensures that we have fairly equal number of observations for each stop and can compare across stops. + * We want to avoid having 30 minutes of predictions for the 1st stop and 60 minutes of predictions for the last stop and comparing metrics that have different denominators. + +## Prediction Inconsistency + +* This metric (also called jitter or wobble) captures another aspect of transit user experience. Any change in prediction is counted, so this metric **only has positive values**, but smaller positive values are better. + * If the prediction is changing from minute to minute, a large spread would show up. + * If the prediction is fairly consistent, we would see small spread. +* There is [research](https://www.sciencedirect.com/science/article/abs/pii/S0965856416303494) around how transit users perceive wait time, and that users perceive longer wait times than what is actually experienced. Decreasing the perceived wait time by providing real-time information has positive benefits for user experience. + +## Master Services Agreement +Exhibit H definitions (pg 53 on pdf) + +| **Item** | **Report Metric** | **Definition** | **Implementation Notes** | +|---|---|---|---| +| 3. Availability of
Acceptable StopTimeUpdate
Messages | pct_tu_complete_minutes,
n_tu_complete_minutes,
n_tu_minutes_available | Percent of time riders have up-to-date prediction information available, calculated as the percent of one-minute time bins for a given trip and stop during a Trip Time Span where there are two (2) or greater GTFS-RT StopTimeUpdate arrival predictions per minute. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 9. Experienced Wait
Time Delay | prediction_error_label,
avg_prediction_error_minutes | The amount of time a transit rider perceives they have waited after seeing the real-time information in their Journey Planning Application and the arrival of the next vehicle arrives at their stop. This is calculated as the time interval between the next trip to arrive at a stop for a given route_id/shape_id/stop_id combination and the next predicted arrival time from a StopTimeUpdate message for that route_id/shape_id/stop_id combination as sampled for each minute of the day that the route_id/shape_id/stop_id combination is in service. | Use a simpler derived version with average
prediction error.
Current aggregation does not support
route aggregation yet. | +| 23. Measurement Time Windows | | A series of 30 consecutive time windows, each starting one (1) minute apart and lasting two (2) minutes. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 27. Prediction Error | avg_prediction_error_minutes | Actual Trip Stop Arrival Time minus the Predicted Trip Stop Arrival Time in seconds. Note that while Prediction Error is not the final metric in this case, it is useful to retain this value into the future and in archival storage in the event that
the definition of the frontier defined in Reliable Accuracy is changed in the future based on a specific agency’s needs | | +| 28. Prediction
Inconsistency | avg_prediction_spread_minutes | How much the prediction changes in the last thirty (30) minutes before a vehicle arrives at a stop, calculated for a given trip and stop as the average Predicted Trip Stop Arrival Spread of all Measurement Time Windows where a given window has a StopTimeUpdate message for the trip and stop with a timestamp in that window. | | +| 29. Prediction Reliability | pct_tu_accurate_minutes,
n_tu_accurate_minutes,
n_tu_minutes_available,
pct_tu_predictions_early/ontime/late,
n_predictions,
n_predictions_early/ontime/late | The percent of time transit riders are looking at a reliably good prediction – understanding that the closer a vehicle is
to a stop, the better the prediction should be, calculated as the percent of minutes for each stop for each trip where predictions have Reliable Accuracy, starting sixty (60) minutes before the first scheduled stop for the trip. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 32. Reliable Accuracy | pct_tu_accurate_minutes,
n_tu_accurate_minutes,
n_tu_minutes_available,
pct_tu_predictions_early/ontime/late,
n_predictions,
n_predictions_early/ontime/late | A prediction has reliable accuracy if:
-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time
to Prediction+1.5). | | +| 39. Time to Prediction | | The current time until the Predicted Trip Stop Arrival Time in minutes | | +| 43. Trip Start Time | | Time of the first scheduled stop arrival of the trip per the GTFS Schedule for trips with ScheduleRelationship =
SCHEDULED or CANCELED or the first predicted arrival time for other ScheduleRelationship values. | | +| 44. Trip Time Span | | Time in minutes from the Trip Start Time to the arrival time
at the stop being measured | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | + +## References +* Caltrans GTFS RT Master Service Agreement Contract + * Swiftly provides a prediction accuracy exponential equation +* Professor Gregory Newmark's paper: [Assessing GTFS Accuracy](https://transweb.sjsu.edu/sites/default/files/2017-Newmark-Public-Transit-Statistical-Analysis.pdf) + * This project is a work in progress for productionizing and implementing all the ideas presented in this paper. + * This paper provides the basis of policy and planning interpretations around the various metrics. + * We replicate as many of the visualizations and tables as possible. +* Yingling Fan, Andrew Guthrie, David Levinson's paper on [Waiting time perceptions at transit stops and stations](https://www.sciencedirect.com/science/article/abs/pii/S0965856416303494) + +### Data Models and Data Processing Scripts +1. Big Query SQL models (upstream to downstream SQL) + * 2 week [sample](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_stop_time_updates_sample) + * [actual arrivals](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.int_gtfs_rt__trip_updates_trip_stop_day_map_grouping) + * [daily stop time metrics](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_stop_time_metrics) + * [daily stop metrics](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_trip_updates_stop_metrics) --> desired future aggregation: move to this stop on a June 2025 weekday instead of this stop on June 1, 2025 + * [GitHub issue](https://github.com/cal-itp/data-infra/issues/4101) + + +2. Python scripts + * [report notebook](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/rt_trip_updates_report.ipynb) + * [Makefile](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/Makefile) + * [download warehouse tables](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/download_warehouse_tables.py) + * [prep data](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/prep_data.py) \ No newline at end of file diff --git a/portfolio/rt_trip_updates_stop_metrics/_toc.yml b/portfolio/rt_trip_updates_stop_metrics/_toc.yml index 0d2f44a2e..e0ab0af6a 100644 --- a/portfolio/rt_trip_updates_stop_metrics/_toc.yml +++ b/portfolio/rt_trip_updates_stop_metrics/_toc.yml @@ -26,7 +26,6 @@ parts: - file: name_bay-area-511-union-city-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-union-city-transit-schedule.ipynb - file: name_bay-area-511-vine-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-vine-transit-schedule.ipynb - file: name_beach-cities-gmv-schedule/00__rt_trip_updates_report__name_beach-cities-gmv-schedule.ipynb - - file: name_beaumont-pass-schedule/00__rt_trip_updates_report__name_beaumont-pass-schedule.ipynb - file: name_beaumont-transit-schedule/00__rt_trip_updates_report__name_beaumont-transit-schedule.ipynb - file: name_big-blue-bus-swiftly-schedule/00__rt_trip_updates_report__name_big-blue-bus-swiftly-schedule.ipynb - file: name_bruinbus-schedule/00__rt_trip_updates_report__name_bruinbus-schedule.ipynb @@ -37,7 +36,6 @@ parts: - file: name_eastern-sierra-schedule/00__rt_trip_updates_report__name_eastern-sierra-schedule.ipynb - file: name_fairfield-schedule/00__rt_trip_updates_report__name_fairfield-schedule.ipynb - file: name_fresno-schedule/00__rt_trip_updates_report__name_fresno-schedule.ipynb - - file: name_historic-tuolumne-schedule/00__rt_trip_updates_report__name_historic-tuolumne-schedule.ipynb - file: name_humboldt-schedule/00__rt_trip_updates_report__name_humboldt-schedule.ipynb - file: name_irvine-connect-schedule/00__rt_trip_updates_report__name_irvine-connect-schedule.ipynb - file: name_kern-schedule/00__rt_trip_updates_report__name_kern-schedule.ipynb @@ -49,7 +47,6 @@ parts: - file: name_madera-county-connection-schedule/00__rt_trip_updates_report__name_madera-county-connection-schedule.ipynb - file: name_marin-gmv-schedule/00__rt_trip_updates_report__name_marin-gmv-schedule.ipynb - file: name_marin-optibus-schedule/00__rt_trip_updates_report__name_marin-optibus-schedule.ipynb - - file: name_marin-schedule/00__rt_trip_updates_report__name_marin-schedule.ipynb - file: name_mendocino-schedule/00__rt_trip_updates_report__name_mendocino-schedule.ipynb - file: name_merced-gmv-schedule/00__rt_trip_updates_report__name_merced-gmv-schedule.ipynb - file: name_monterey-salinas-schedule/00__rt_trip_updates_report__name_monterey-salinas-schedule.ipynb @@ -57,12 +54,10 @@ parts: - file: name_nevada-county-schedule/00__rt_trip_updates_report__name_nevada-county-schedule.ipynb - file: name_north-county-schedule/00__rt_trip_updates_report__name_north-county-schedule.ipynb - file: name_octa-schedule/00__rt_trip_updates_report__name_octa-schedule.ipynb - - file: name_ojai-schedule/00__rt_trip_updates_report__name_ojai-schedule.ipynb - file: name_petaluma-gmv-schedule/00__rt_trip_updates_report__name_petaluma-gmv-schedule.ipynb - file: name_presidigo-schedule/00__rt_trip_updates_report__name_presidigo-schedule.ipynb - file: name_redding-schedule/00__rt_trip_updates_report__name_redding-schedule.ipynb - file: name_redwood-coast-schedule/00__rt_trip_updates_report__name_redwood-coast-schedule.ipynb - - file: name_redwood-coast-schedulel/00__rt_trip_updates_report__name_redwood-coast-schedulel.ipynb - file: name_roseville-transit-gmv-schedule/00__rt_trip_updates_report__name_roseville-transit-gmv-schedule.ipynb - file: name_scvta-schedule/00__rt_trip_updates_report__name_scvta-schedule.ipynb - file: name_smart-schedule/00__rt_trip_updates_report__name_smart-schedule.ipynb @@ -75,7 +70,6 @@ parts: - file: name_torrance-schedule/00__rt_trip_updates_report__name_torrance-schedule.ipynb - file: name_tri-valley-wheels-schedule/00__rt_trip_updates_report__name_tri-valley-wheels-schedule.ipynb - file: name_tuolumne-remix-schedule/00__rt_trip_updates_report__name_tuolumne-remix-schedule.ipynb - - file: name_tuolumne-schedule/00__rt_trip_updates_report__name_tuolumne-schedule.ipynb - file: name_turlock-schedule/00__rt_trip_updates_report__name_turlock-schedule.ipynb - file: name_union-city-gmv-schedule/00__rt_trip_updates_report__name_union-city-gmv-schedule.ipynb - file: name_vctc-gmv-schedule/00__rt_trip_updates_report__name_vctc-gmv-schedule.ipynb diff --git a/portfolio/rt_trip_updates_stop_metrics/name_ac-transit-schedule/00__rt_trip_updates_report__name_ac-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_ac-transit-schedule/00__rt_trip_updates_report__name_ac-transit-schedule.ipynb index d1c928b1a..d90b03e65 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_ac-transit-schedule/00__rt_trip_updates_report__name_ac-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_ac-transit-schedule/00__rt_trip_updates_report__name_ac-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c7e0259fecd5e1b610e5291986c332ab5d1e81303250c92df42fd4209de632e -size 12153344 +oid sha256:cf3603548a7147f1769b25044eaed8afe664175594e53bd15b1f404645c3f52f +size 8979358 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule-v2/00__rt_trip_updates_report__name_anaheim-resort-schedule-v2.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule-v2/00__rt_trip_updates_report__name_anaheim-resort-schedule-v2.ipynb index 024abbfd8..b8ed34033 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule-v2/00__rt_trip_updates_report__name_anaheim-resort-schedule-v2.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule-v2/00__rt_trip_updates_report__name_anaheim-resort-schedule-v2.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9e5a723b01f3349cf8dc1e3ce8ecc08a9a04092358bba362d7ca1e3c6260cda -size 784349 +oid sha256:bb361bb0ce44d32ad3467f38000bb6d785d773a582f585403dc3a37ce953f202 +size 832792 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule/00__rt_trip_updates_report__name_anaheim-resort-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule/00__rt_trip_updates_report__name_anaheim-resort-schedule.ipynb index 734f1fcfd..b00718faf 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule/00__rt_trip_updates_report__name_anaheim-resort-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_anaheim-resort-schedule/00__rt_trip_updates_report__name_anaheim-resort-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b90234c0f6137f9b6a0466b7d75e901f624794dc1162ae5ffda9283d4313ce5b -size 938515 +oid sha256:3e23229f0ff0c3728251c739bf1f0f22600ccb5b2de46a794ac548a95ef694d0 +size 825971 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_banning-pass-schedule/00__rt_trip_updates_report__name_banning-pass-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_banning-pass-schedule/00__rt_trip_updates_report__name_banning-pass-schedule.ipynb index a5fc307ae..d216bcb4a 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_banning-pass-schedule/00__rt_trip_updates_report__name_banning-pass-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_banning-pass-schedule/00__rt_trip_updates_report__name_banning-pass-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b468188bc78e1f98f805d38e5a88eabb09baca11d003bdbdf3e3f34e18363dbb -size 418096 +oid sha256:c47830e212e2cc7d261d3b39b0f7b69f8a4e8f7b181092e223ecf66d4f544478 +size 825356 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_basin-transit-gmv-schedule/00__rt_trip_updates_report__name_basin-transit-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_basin-transit-gmv-schedule/00__rt_trip_updates_report__name_basin-transit-gmv-schedule.ipynb index 798407b49..412e6a6cb 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_basin-transit-gmv-schedule/00__rt_trip_updates_report__name_basin-transit-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_basin-transit-gmv-schedule/00__rt_trip_updates_report__name_basin-transit-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abba3b429db88313e773789450c6765818c1dd65370f21b5b34d7e30b8d111bc -size 957524 +oid sha256:c87fe4d1694c6c5f56b5dc105a7d1554979e1b26436354b3c6b8089885fe73a3 +size 1247056 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ac-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-ac-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ac-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-ac-transit-schedule.ipynb index ef87184da..4527220ff 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ac-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-ac-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ac-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-ac-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c02d71e1e8e3e03554069d28bb793d49a59c2734624dca0f3d5f58564e3fc198 -size 9299910 +oid sha256:25b55e06ff3c3689b228de4ddd157cf904a8dfe659653673dc66734421ed8cad +size 8707500 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ace-schedule/00__rt_trip_updates_report__name_bay-area-511-ace-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ace-schedule/00__rt_trip_updates_report__name_bay-area-511-ace-schedule.ipynb index 40a4e8795..a616c3e96 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ace-schedule/00__rt_trip_updates_report__name_bay-area-511-ace-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-ace-schedule/00__rt_trip_updates_report__name_bay-area-511-ace-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a84e399e2b790f5ab38d37c5bc7e4bb643dbf9c600a562ef6709139b610a8619 -size 305995 +oid sha256:ba03a892378aecc0f2dc1aae6cd7126bd02dae797dc35618f90bfc105816abff +size 563891 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-capitol-corridor-schedule/00__rt_trip_updates_report__name_bay-area-511-capitol-corridor-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-capitol-corridor-schedule/00__rt_trip_updates_report__name_bay-area-511-capitol-corridor-schedule.ipynb index c0f5be0f5..837b8b71e 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-capitol-corridor-schedule/00__rt_trip_updates_report__name_bay-area-511-capitol-corridor-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-capitol-corridor-schedule/00__rt_trip_updates_report__name_bay-area-511-capitol-corridor-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a75f616c8560e533f1660c03ca2a4858a3e72d7f3597b81473e2730a108bce29 -size 385452 +oid sha256:fa4e538e2fc83a4727408bdbb79b0b9de97e6a8fb738f373e8cbbfc6c38d6efb +size 808710 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-county-connection-schedule/00__rt_trip_updates_report__name_bay-area-511-county-connection-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-county-connection-schedule/00__rt_trip_updates_report__name_bay-area-511-county-connection-schedule.ipynb index fb931c503..0103ffd25 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-county-connection-schedule/00__rt_trip_updates_report__name_bay-area-511-county-connection-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-county-connection-schedule/00__rt_trip_updates_report__name_bay-area-511-county-connection-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e57a77ed8ba2971b5aa81da153ee086f63b3311c28dc4c1eacdb2407db591c4c -size 2721322 +oid sha256:ee883b84599e37e01f2ed1d226be7a6de50be25fb3de79948c9a23568941236d +size 2682577 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-fairfield-and-suisun-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-fairfield-and-suisun-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-fairfield-and-suisun-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-fairfield-and-suisun-transit-schedule.ipynb index 2775e03d5..c88073062 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-fairfield-and-suisun-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-fairfield-and-suisun-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-fairfield-and-suisun-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-fairfield-and-suisun-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21ace3307a528ce580d204ce5fa4bbb82305e77a9c5859b65277b750efe4d6d0 -size 520922 +oid sha256:60759327c53fbf0a858723299217b44b9b24d14e88154ed644656938272bb00c +size 879920 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-golden-gate-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-golden-gate-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-golden-gate-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-golden-gate-transit-schedule.ipynb index 8fdee1eb2..2c357120d 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-golden-gate-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-golden-gate-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-golden-gate-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-golden-gate-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d82ec278f2982dbd5657daf817dbab6c092bf58cb098611dd2bb5e662211e32d -size 1587364 +oid sha256:bed9cb1de4e2e6e7fd07b8448d5e5a4029f0e36714a1244c9fcb8f2c67ec1083 +size 1411636 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-marin-schedule/00__rt_trip_updates_report__name_bay-area-511-marin-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-marin-schedule/00__rt_trip_updates_report__name_bay-area-511-marin-schedule.ipynb index 0b58d5dcd..b6ee33581 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-marin-schedule/00__rt_trip_updates_report__name_bay-area-511-marin-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-marin-schedule/00__rt_trip_updates_report__name_bay-area-511-marin-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fb4b18b6de54c551bbe834f1fa0e69e4621b96246a4a4f5b551d0a09106b12e -size 1898559 +oid sha256:294be3462f7fbd8499280eef072204f0ad003093bbc655b164661b950420522b +size 1702019 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-petaluma-schedule/00__rt_trip_updates_report__name_bay-area-511-petaluma-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-petaluma-schedule/00__rt_trip_updates_report__name_bay-area-511-petaluma-schedule.ipynb index c76701521..4b79cc5a0 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-petaluma-schedule/00__rt_trip_updates_report__name_bay-area-511-petaluma-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-petaluma-schedule/00__rt_trip_updates_report__name_bay-area-511-petaluma-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24b1070f5096ab983c45150907890689bf2067cb6b63b1849139d35067ef0243 -size 716319 +oid sha256:26a28e3c60cd8913b6b905a1db840eb725830f012b531b713ae6ada8a09f3877 +size 1142398 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-presidigo-schedule/00__rt_trip_updates_report__name_bay-area-511-presidigo-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-presidigo-schedule/00__rt_trip_updates_report__name_bay-area-511-presidigo-schedule.ipynb index 1ecf9f60a..c652836b2 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-presidigo-schedule/00__rt_trip_updates_report__name_bay-area-511-presidigo-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-presidigo-schedule/00__rt_trip_updates_report__name_bay-area-511-presidigo-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e235f97b2a50052d162de3a6d5c434e53f26fa81579bafb3cfca664fd78d467 -size 438069 +oid sha256:69d30b00add0c98da0a806ca8d65cb52919860ca4d36e3caeb4106dda9966062 +size 863802 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-samtrans-schedule/00__rt_trip_updates_report__name_bay-area-511-samtrans-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-samtrans-schedule/00__rt_trip_updates_report__name_bay-area-511-samtrans-schedule.ipynb index f66a6fd42..787d69b83 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-samtrans-schedule/00__rt_trip_updates_report__name_bay-area-511-samtrans-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-samtrans-schedule/00__rt_trip_updates_report__name_bay-area-511-samtrans-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d85ff9825f2fbd1efb000eca2f7381c3caccb0300a7f8b8bbb4c7a44277609ac -size 3934838 +oid sha256:5b4a0d5559d97edc7d23dabd8bb17a0493ffa6e6d1833cc8af99513dc0f0f525 +size 4455614 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_bay-area-511-san-francisco-bay-ferry-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_bay-area-511-san-francisco-bay-ferry-schedule.ipynb index c14010110..73f42d6fd 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_bay-area-511-san-francisco-bay-ferry-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_bay-area-511-san-francisco-bay-ferry-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72204bc6ce54e5831b787e6dfe513e527f1a0178a660959a890e7894c1bdf904 -size 362166 +oid sha256:9ffa0199afe76b8ca9fe41ac67427d8cadcb7b792993da22e294c234c9008737 +size 262472 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-clara-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-clara-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-clara-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-clara-transit-schedule.ipynb index 1638f667c..f5b6f00c2 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-clara-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-clara-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-clara-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-clara-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bf2153194ebe26a8a7af324b661c1976cfe3c498abe57c22a8814b0ca927e72 -size 8583638 +oid sha256:a3dda13289465259f68a74d2125ba7e9e24e27742e112869b760974f002327e1 +size 6812677 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-rosa-citybus-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-rosa-citybus-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-rosa-citybus-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-rosa-citybus-schedule.ipynb index cd23e2336..f0cbe1bb8 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-rosa-citybus-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-rosa-citybus-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-santa-rosa-citybus-schedule/00__rt_trip_updates_report__name_bay-area-511-santa-rosa-citybus-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c47ddb347df5a254bd701c014ce859af4f7fcf54fd8ec02bfbdecb0de904c017 -size 1668155 +oid sha256:be034de3eb018ba71ec580e138a9c9d348fa60e23799cb05ed8ae743b8743573 +size 1791663 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-sonoma-marin-area-rail-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-sonoma-marin-area-rail-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-sonoma-marin-area-rail-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-sonoma-marin-area-rail-transit-schedule.ipynb index 3f22f509b..41f623edc 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-sonoma-marin-area-rail-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-sonoma-marin-area-rail-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-sonoma-marin-area-rail-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-sonoma-marin-area-rail-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:759eda8eb9ae92388568b864aa948e879f77d86e3dfe442be2c599fee757854c -size 390807 +oid sha256:cf7d1452ea3ec4ff63ba6592316f0840d686cd82b4bd4c43f4bfb75ebf900ced +size 835625 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-delta-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-delta-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-delta-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-delta-schedule.ipynb index b76bde9cb..65f7c44d9 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-delta-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-delta-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-delta-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-delta-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bafe7655b7311b2756045fff9aac2c3c770674e7700dea5555afe36b9aeb17f5 -size 318756 +oid sha256:5b8b00977146596bf8e6f6d4df57dff1414a36ffcc5d9b9307c7fbe5498ac188 +size 514859 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-valley-wheels-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-valley-wheels-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-valley-wheels-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-valley-wheels-schedule.ipynb index d27d993f1..668b95c55 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-valley-wheels-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-valley-wheels-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-tri-valley-wheels-schedule/00__rt_trip_updates_report__name_bay-area-511-tri-valley-wheels-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:078fdbb6d940cc028aaa17a6f00483124e32b8705dd91d4bfeebb98a13ecf478 -size 1986568 +oid sha256:fd030fbb28ae13f4dc4172b843a315126aed21d3e6dba46933e35aabdea185ab +size 1728180 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-union-city-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-union-city-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-union-city-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-union-city-transit-schedule.ipynb index f4e47428d..12cf62890 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-union-city-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-union-city-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-union-city-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-union-city-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26f498c4aff63e76251dead69cb769d21581598548eafa8ed15a3f4ee75dc556 -size 892876 +oid sha256:ba82df7d7abb01fe5cf877d76d383e38323682a2665412f7e67b6b4da512e4bb +size 1159146 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-vine-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-vine-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-vine-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-vine-transit-schedule.ipynb index 1f1969cf6..15df7b78d 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-vine-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-vine-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bay-area-511-vine-transit-schedule/00__rt_trip_updates_report__name_bay-area-511-vine-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:196c0e9efee08ca5fb5c3f9d7b4dc9bc3504ce6349b5034b2319c7a4a5d3125b -size 1119084 +oid sha256:9f1ec9af9064445653467a32fa239227b818781155d551c2a7bbed7bc1b72512 +size 1226820 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_beach-cities-gmv-schedule/00__rt_trip_updates_report__name_beach-cities-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_beach-cities-gmv-schedule/00__rt_trip_updates_report__name_beach-cities-gmv-schedule.ipynb index c4d7157bf..d4d525d64 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_beach-cities-gmv-schedule/00__rt_trip_updates_report__name_beach-cities-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_beach-cities-gmv-schedule/00__rt_trip_updates_report__name_beach-cities-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7750a2d020a14b91501e77d1c523fb6e3e2fbe32e5106894b5b6586ab4e874aa -size 1344847 +oid sha256:2f6ea293033255a4ae869a96d3c1ba6fb13ab7aff3d4408057f272336e1cdd48 +size 1318426 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_beaumont-pass-schedule/00__rt_trip_updates_report__name_beaumont-pass-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_beaumont-pass-schedule/00__rt_trip_updates_report__name_beaumont-pass-schedule.ipynb deleted file mode 100644 index 6a36b0cea..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_beaumont-pass-schedule/00__rt_trip_updates_report__name_beaumont-pass-schedule.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd4c42b53c18a916eb6c059bab10786600c6236ddc8544e63f6926457020a28a -size 543124 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_beaumont-transit-schedule/00__rt_trip_updates_report__name_beaumont-transit-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_beaumont-transit-schedule/00__rt_trip_updates_report__name_beaumont-transit-schedule.ipynb index 24630478e..07e8f130f 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_beaumont-transit-schedule/00__rt_trip_updates_report__name_beaumont-transit-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_beaumont-transit-schedule/00__rt_trip_updates_report__name_beaumont-transit-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:808c0de4ab478a2436b5793133e594ae5d922277c672ce84ff15f7876336aff9 -size 494545 +oid sha256:55bfbdf3daad9d666ac732fb9f76dc022a10bc660d9b01c08cac298dda6153b8 +size 933302 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_big-blue-bus-swiftly-schedule/00__rt_trip_updates_report__name_big-blue-bus-swiftly-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_big-blue-bus-swiftly-schedule/00__rt_trip_updates_report__name_big-blue-bus-swiftly-schedule.ipynb index 221363665..9c10aaf77 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_big-blue-bus-swiftly-schedule/00__rt_trip_updates_report__name_big-blue-bus-swiftly-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_big-blue-bus-swiftly-schedule/00__rt_trip_updates_report__name_big-blue-bus-swiftly-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79fe1402cc5fb5e80792d775d31cad4f0ed949bcd2ada2a3c533ebb4f414d1f4 -size 1034168 +oid sha256:1883aabe778794d7d38cd5d372c017ffb98fab64522e531426267df3bcedb6f8 +size 2001724 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_bruinbus-schedule/00__rt_trip_updates_report__name_bruinbus-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_bruinbus-schedule/00__rt_trip_updates_report__name_bruinbus-schedule.ipynb index 72dafb5dc..b753058aa 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_bruinbus-schedule/00__rt_trip_updates_report__name_bruinbus-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_bruinbus-schedule/00__rt_trip_updates_report__name_bruinbus-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5966b0289823c91a60b0e457ef327c6d128a704ad2502b6994bbde5756c304b8 -size 242270 +oid sha256:a859b199686799b8b440d50bdda004eff8d27fc39ce86bd58e908299804b1cfe +size 387477 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_burbank-schedule/00__rt_trip_updates_report__name_burbank-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_burbank-schedule/00__rt_trip_updates_report__name_burbank-schedule.ipynb index b488d1796..3bb8d53e7 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_burbank-schedule/00__rt_trip_updates_report__name_burbank-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_burbank-schedule/00__rt_trip_updates_report__name_burbank-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de2aa8480d1152afc09fefea194e1a7aead76a1336c22063524809581d4a527b -size 365712 +oid sha256:b8fcdb434bd41a70fcffad078e6e45f685ce0020f26d774ae0a39124e9d6c186 +size 704948 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_commerce-schedule/00__rt_trip_updates_report__name_commerce-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_commerce-schedule/00__rt_trip_updates_report__name_commerce-schedule.ipynb index bb6fa3fcf..d6b7e014a 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_commerce-schedule/00__rt_trip_updates_report__name_commerce-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_commerce-schedule/00__rt_trip_updates_report__name_commerce-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c51a6fc063de9a597ee478596c0ce3ddb957bf71e659c5cf6fa141c7f57dee0f -size 1166541 +oid sha256:75f11a2ee4f00a87ed2cc93cfecda1027103470048a751120e9df72726bbd702 +size 1381127 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_county-connection-schedule/00__rt_trip_updates_report__name_county-connection-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_county-connection-schedule/00__rt_trip_updates_report__name_county-connection-schedule.ipynb index e81f4a5f3..4f1e1df90 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_county-connection-schedule/00__rt_trip_updates_report__name_county-connection-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_county-connection-schedule/00__rt_trip_updates_report__name_county-connection-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef211f0420ced52b69a26027366d37aec27f26ee86ce4036cdc405ebe9da25cf -size 4531856 +oid sha256:ce0b6f8ba6e279c55b427099bcadc1a002fcae1e5d48b71a4b97b01a20f799bc +size 2800328 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_desert-roadrunner-gmv-schedule/00__rt_trip_updates_report__name_desert-roadrunner-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_desert-roadrunner-gmv-schedule/00__rt_trip_updates_report__name_desert-roadrunner-gmv-schedule.ipynb index 4a8bb811b..59ecc7970 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_desert-roadrunner-gmv-schedule/00__rt_trip_updates_report__name_desert-roadrunner-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_desert-roadrunner-gmv-schedule/00__rt_trip_updates_report__name_desert-roadrunner-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d6721b525ac12d9dcf2927bb8e27d6fa2d7347a371aba4f117fbc7f2840344d -size 357697 +oid sha256:7757dea4cb0001bf01181d55075c785c8037d84663908643b3bed9fdbde345c5 +size 717643 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_eastern-sierra-schedule/00__rt_trip_updates_report__name_eastern-sierra-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_eastern-sierra-schedule/00__rt_trip_updates_report__name_eastern-sierra-schedule.ipynb index de2c09d80..c6567463e 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_eastern-sierra-schedule/00__rt_trip_updates_report__name_eastern-sierra-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_eastern-sierra-schedule/00__rt_trip_updates_report__name_eastern-sierra-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e214fea3d7df8250d249c652d572075eacaa9cbd990d0e17e5976c71bdb0911 -size 1138832 +oid sha256:57b1e198a5c1961066b698aa89502c1bd63eb13d934ad338af8c0ad598817a29 +size 1111967 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_fairfield-schedule/00__rt_trip_updates_report__name_fairfield-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_fairfield-schedule/00__rt_trip_updates_report__name_fairfield-schedule.ipynb index 96b437f4e..020908f14 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_fairfield-schedule/00__rt_trip_updates_report__name_fairfield-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_fairfield-schedule/00__rt_trip_updates_report__name_fairfield-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6dc14be43187ddaa7889c73fd3012a614eaf7d7f4c0d3d683b49cf2b545bbab -size 522093 +oid sha256:336c40e338d74c36598ad3a4b3806f317735a8f8f928070747b1789555bd2a23 +size 898258 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_fresno-schedule/00__rt_trip_updates_report__name_fresno-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_fresno-schedule/00__rt_trip_updates_report__name_fresno-schedule.ipynb index fb11302ce..311f5095f 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_fresno-schedule/00__rt_trip_updates_report__name_fresno-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_fresno-schedule/00__rt_trip_updates_report__name_fresno-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5645f49542ad4910d921845141d6b4d5f9c74161610bb4a26ad9a04927a4551 -size 3709091 +oid sha256:555e28bae0805ed8b5cdb2debacb5850bbc363666e4a567b1582cd25e41d1c13 +size 4281763 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_historic-tuolumne-schedule/00__rt_trip_updates_report__name_historic-tuolumne-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_historic-tuolumne-schedule/00__rt_trip_updates_report__name_historic-tuolumne-schedule.ipynb deleted file mode 100644 index c02f41b00..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_historic-tuolumne-schedule/00__rt_trip_updates_report__name_historic-tuolumne-schedule.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:92ac91e279df92679aa23787b15ec35fbd3ba7a0283289b023d83126b8c4fbac -size 407503 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_humboldt-schedule/00__rt_trip_updates_report__name_humboldt-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_humboldt-schedule/00__rt_trip_updates_report__name_humboldt-schedule.ipynb index a8b76f478..320ae24f1 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_humboldt-schedule/00__rt_trip_updates_report__name_humboldt-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_humboldt-schedule/00__rt_trip_updates_report__name_humboldt-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7f2230dbfce86c695c3646385458bd9f43a39bf379f64c9dd791e0bf707855c -size 1171492 +oid sha256:3fe1a1139176f027b2370e2248397e9be5314d00cbc073051e1297e3db786ec2 +size 1223182 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_irvine-connect-schedule/00__rt_trip_updates_report__name_irvine-connect-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_irvine-connect-schedule/00__rt_trip_updates_report__name_irvine-connect-schedule.ipynb index f78397b2e..9ec30ed1f 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_irvine-connect-schedule/00__rt_trip_updates_report__name_irvine-connect-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_irvine-connect-schedule/00__rt_trip_updates_report__name_irvine-connect-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:985b049907902e42f6aa47ca356a52820bf2155a2d7d6d273be0a9990f589562 -size 836870 +oid sha256:5dc380189871a080b3cb29df01006eff39f90d4ce568938f69fbfdeebb3e8f41 +size 945693 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_kern-schedule/00__rt_trip_updates_report__name_kern-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_kern-schedule/00__rt_trip_updates_report__name_kern-schedule.ipynb index 8487f2430..0594f4026 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_kern-schedule/00__rt_trip_updates_report__name_kern-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_kern-schedule/00__rt_trip_updates_report__name_kern-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73409d6db5044cc343ba19b938caf2fbc2ed5b79c3c4a7f2f1ec6a27cf0bda9a -size 976301 +oid sha256:455f03c75c1725fa2b500d9506e89ddebe0aae2c4feee2fde0f4d8ac1ab7b38d +size 1217561 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_la-dot-schedule/00__rt_trip_updates_report__name_la-dot-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_la-dot-schedule/00__rt_trip_updates_report__name_la-dot-schedule.ipynb index 42bf4e34c..c53fadddb 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_la-dot-schedule/00__rt_trip_updates_report__name_la-dot-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_la-dot-schedule/00__rt_trip_updates_report__name_la-dot-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:311ecc359add60ce5beac51ce2ab68f34f011123c4fd173bc217ffa337f1024a -size 22592281 +oid sha256:4be3d4e61ccec17462de42389326fa7fa43d64cda4ff248278b03cc1626818a7 +size 7289130 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_la-metro-bus-schedule/00__rt_trip_updates_report__name_la-metro-bus-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_la-metro-bus-schedule/00__rt_trip_updates_report__name_la-metro-bus-schedule.ipynb index 74b7239d4..c33b5ada2 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_la-metro-bus-schedule/00__rt_trip_updates_report__name_la-metro-bus-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_la-metro-bus-schedule/00__rt_trip_updates_report__name_la-metro-bus-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd3bcb00b6f5a29f28748db209cb2fb92f10dbc6036563a73895e85dfb6612cf -size 39934594 +oid sha256:05981ef49f93bcef7d91553c17f0cff8813f23561e4bbda4db6c94a848e14c34 +size 29112983 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_la-metro-rail-schedule/00__rt_trip_updates_report__name_la-metro-rail-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_la-metro-rail-schedule/00__rt_trip_updates_report__name_la-metro-rail-schedule.ipynb index 225fdf4e7..6c4fa6e52 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_la-metro-rail-schedule/00__rt_trip_updates_report__name_la-metro-rail-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_la-metro-rail-schedule/00__rt_trip_updates_report__name_la-metro-rail-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa2a4e2a68a3987f05d93d7f2bf34c3ecb5f67e783442381e07e8e8fd4499cf3 -size 1025223 +oid sha256:5cc00464b45a617baeac97ea213efbac3b388c725b9627d653799d02426e25e7 +size 1039111 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_lake-schedule/00__rt_trip_updates_report__name_lake-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_lake-schedule/00__rt_trip_updates_report__name_lake-schedule.ipynb index d708b7a99..815af2e76 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_lake-schedule/00__rt_trip_updates_report__name_lake-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_lake-schedule/00__rt_trip_updates_report__name_lake-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9778031831019cd537ec2ab791d7cd7c66a1c694f514a939f77e34c544db8df8 -size 1139276 +oid sha256:85cfcf81935c7bf5eb52f9780daafa95734b72c9325bd767423cbbfb263c3cea +size 1210492 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_lawndale-beat-gmv-schedule/00__rt_trip_updates_report__name_lawndale-beat-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_lawndale-beat-gmv-schedule/00__rt_trip_updates_report__name_lawndale-beat-gmv-schedule.ipynb index 719bd1560..bc2893cb5 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_lawndale-beat-gmv-schedule/00__rt_trip_updates_report__name_lawndale-beat-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_lawndale-beat-gmv-schedule/00__rt_trip_updates_report__name_lawndale-beat-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:932bef5d06cf34cf8bc062f12e194bf05109878e56ae874c7aa7985320a0c1a1 -size 331295 +oid sha256:d9622c02a6dd2cf09269415b5fad4cc1b9e515519923d7532321febb63f4e8fd +size 636153 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_madera-county-connection-schedule/00__rt_trip_updates_report__name_madera-county-connection-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_madera-county-connection-schedule/00__rt_trip_updates_report__name_madera-county-connection-schedule.ipynb index a02505a4f..ee4eceb1b 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_madera-county-connection-schedule/00__rt_trip_updates_report__name_madera-county-connection-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_madera-county-connection-schedule/00__rt_trip_updates_report__name_madera-county-connection-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbde60533bc99d864961f536b4fbb0ad2fe2193e347345b2bf9c4b455f50dcd1 -size 368769 +oid sha256:4447fded56d8ea95b035029aab02b318fb338bbef91ce121cbff8ebfe24864d7 +size 677101 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_marin-gmv-schedule/00__rt_trip_updates_report__name_marin-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_marin-gmv-schedule/00__rt_trip_updates_report__name_marin-gmv-schedule.ipynb index 617e5b366..02699df00 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_marin-gmv-schedule/00__rt_trip_updates_report__name_marin-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_marin-gmv-schedule/00__rt_trip_updates_report__name_marin-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ca39a37dcc50baac41eca979944a348b5c174d4981aafc3eac0519cb0661059 -size 2655238 +oid sha256:dd386cc5407b06a38cca82468dc289766080ae463628a131c77a9e7c5f365607 +size 2084597 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_marin-optibus-schedule/00__rt_trip_updates_report__name_marin-optibus-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_marin-optibus-schedule/00__rt_trip_updates_report__name_marin-optibus-schedule.ipynb index f5af34d07..7328e9552 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_marin-optibus-schedule/00__rt_trip_updates_report__name_marin-optibus-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_marin-optibus-schedule/00__rt_trip_updates_report__name_marin-optibus-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f329e5fde1799859c516978b74206398888652d68ac95a43e7f99e4ea7ead72 -size 1385223 +oid sha256:ea7e60d8f3fbd984035454c01c49b19f7a2beef8924c01c066c95c3bf6ce0d86 +size 1727605 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_marin-schedule/00__rt_trip_updates_report__name_marin-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_marin-schedule/00__rt_trip_updates_report__name_marin-schedule.ipynb deleted file mode 100644 index d6523c3a7..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_marin-schedule/00__rt_trip_updates_report__name_marin-schedule.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dcebc7c0a4f3a0724be25513bc6a5488a49f5fc142bbca8e83e0cb8666f881a8 -size 1385187 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_mendocino-schedule/00__rt_trip_updates_report__name_mendocino-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_mendocino-schedule/00__rt_trip_updates_report__name_mendocino-schedule.ipynb index 931d7014c..f4cdf7dc1 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_mendocino-schedule/00__rt_trip_updates_report__name_mendocino-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_mendocino-schedule/00__rt_trip_updates_report__name_mendocino-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1dfb4c4049e0eb0a53004061d9951c981e80b01d243a7e3996bbd5dec95f95de -size 775813 +oid sha256:a793e4b19bfba9d12b0d67d7eaea33af0ff17dea9bb17c32680ccd3f61b9cfbe +size 1145540 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_merced-gmv-schedule/00__rt_trip_updates_report__name_merced-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_merced-gmv-schedule/00__rt_trip_updates_report__name_merced-gmv-schedule.ipynb index 6887ddead..08379ef63 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_merced-gmv-schedule/00__rt_trip_updates_report__name_merced-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_merced-gmv-schedule/00__rt_trip_updates_report__name_merced-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12d5d739bda552b34827b9e2dd05d23fdf218f843a9157cf8247c8f544c199bf -size 1999331 +oid sha256:72f82a55026a1bd3b5f6302b8c168e2cdccb6a1aa09d2c35efaeb2f89ba44ff5 +size 1696760 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_monterey-salinas-schedule/00__rt_trip_updates_report__name_monterey-salinas-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_monterey-salinas-schedule/00__rt_trip_updates_report__name_monterey-salinas-schedule.ipynb index 59edbe0df..7f73618f9 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_monterey-salinas-schedule/00__rt_trip_updates_report__name_monterey-salinas-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_monterey-salinas-schedule/00__rt_trip_updates_report__name_monterey-salinas-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6171f272705258e7b174302be2380e73dee380a2135b6c3f29f51a2f1ac7819 -size 2569140 +oid sha256:fdef237f04fd1d24f2ff137a491ce5ef9e2f3c76a7c45ac71d2801a554f8cbd0 +size 518670 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_mountain-transit-gmv-schedule/00__rt_trip_updates_report__name_mountain-transit-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_mountain-transit-gmv-schedule/00__rt_trip_updates_report__name_mountain-transit-gmv-schedule.ipynb index c6f67d4fc..27f6e6fe1 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_mountain-transit-gmv-schedule/00__rt_trip_updates_report__name_mountain-transit-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_mountain-transit-gmv-schedule/00__rt_trip_updates_report__name_mountain-transit-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24399889febd9d7a506e40ed198f9d372fe2f9bbdb7ace2dff18a6a5c141c194 -size 1082122 +oid sha256:9b8eec0c6eed8ce13d8412c601c33a088f16fba7c79b1ebe96f466092cba768e +size 1145154 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_nevada-county-schedule/00__rt_trip_updates_report__name_nevada-county-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_nevada-county-schedule/00__rt_trip_updates_report__name_nevada-county-schedule.ipynb index 892d960c7..7d199dd5d 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_nevada-county-schedule/00__rt_trip_updates_report__name_nevada-county-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_nevada-county-schedule/00__rt_trip_updates_report__name_nevada-county-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41416da2e3fe4d6f01d4fd4c840fb55be29471d49b0f09c27741848b7ec6d504 -size 708653 +oid sha256:ddf6be25c0d308fb5b886449e82ce5ffa73a3e173c73594bd4104f3890dbd540 +size 1011860 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_north-county-schedule/00__rt_trip_updates_report__name_north-county-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_north-county-schedule/00__rt_trip_updates_report__name_north-county-schedule.ipynb index 89c76de62..d537dd838 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_north-county-schedule/00__rt_trip_updates_report__name_north-county-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_north-county-schedule/00__rt_trip_updates_report__name_north-county-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4783db7d01d09f02e5543bed7b8a22d0f60b897c3a63d76ab26a11005c5d2c2e -size 6065579 +oid sha256:ace389647f31fbfa941699ff0e5f134652f3b342db45868d532e422017434046 +size 3892538 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_octa-schedule/00__rt_trip_updates_report__name_octa-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_octa-schedule/00__rt_trip_updates_report__name_octa-schedule.ipynb index 20a5219f5..7a56a4f3d 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_octa-schedule/00__rt_trip_updates_report__name_octa-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_octa-schedule/00__rt_trip_updates_report__name_octa-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3154e047cbca0878051aac346ebca0f888fcddecc85e212b30f71c9523492e56 -size 9063001 +oid sha256:76a86d158f6f24aaecd4f0ee577037061909f10e96fa39e639674c036c7d01ba +size 9357915 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_ojai-schedule/00__rt_trip_updates_report__name_ojai-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_ojai-schedule/00__rt_trip_updates_report__name_ojai-schedule.ipynb deleted file mode 100644 index 6c3e70d79..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_ojai-schedule/00__rt_trip_updates_report__name_ojai-schedule.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6d3970cf83d6d6f292f7d7631a9f7949ffdb4b8fdda7df910236fd2471af0ed -size 4317110 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_petaluma-gmv-schedule/00__rt_trip_updates_report__name_petaluma-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_petaluma-gmv-schedule/00__rt_trip_updates_report__name_petaluma-gmv-schedule.ipynb index a22bf32dc..10bafd6de 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_petaluma-gmv-schedule/00__rt_trip_updates_report__name_petaluma-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_petaluma-gmv-schedule/00__rt_trip_updates_report__name_petaluma-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:228836296bc119d42208011f8e4fc1c0019a0e41a30ab6f1324137d80f621c14 -size 951719 +oid sha256:3330524d8cd64e4ae7e3cedf8ba764b88375424ce952f9fcb736f4a7d13505e1 +size 1152368 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_presidigo-schedule/00__rt_trip_updates_report__name_presidigo-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_presidigo-schedule/00__rt_trip_updates_report__name_presidigo-schedule.ipynb index 27b6afb45..5ebcb1ae4 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_presidigo-schedule/00__rt_trip_updates_report__name_presidigo-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_presidigo-schedule/00__rt_trip_updates_report__name_presidigo-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:317bd7602db536a8c8aa3dc4531dfd26eea0f3aaed2fb0d900242d7419be198f -size 547286 +oid sha256:039dc0019cd392c52a0a202488b82d6832ac591fb0613a827fab5404ac7b75f7 +size 854800 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_redding-schedule/00__rt_trip_updates_report__name_redding-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_redding-schedule/00__rt_trip_updates_report__name_redding-schedule.ipynb index 52a8cf956..83c1423fd 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_redding-schedule/00__rt_trip_updates_report__name_redding-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_redding-schedule/00__rt_trip_updates_report__name_redding-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5e9a780227956879511c77952996d0526684a747ede0c9bf2b156b86b761371 -size 912953 +oid sha256:fe9e0503f8dbe903fd21a98f33d97729675ca4bd88c00e5c2a322f3016292b50 +size 1348331 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedule/00__rt_trip_updates_report__name_redwood-coast-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedule/00__rt_trip_updates_report__name_redwood-coast-schedule.ipynb index 484b9d1a9..cbe661ac4 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedule/00__rt_trip_updates_report__name_redwood-coast-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedule/00__rt_trip_updates_report__name_redwood-coast-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fff9ee2bcac9db04373aaa82cc9b791c27146ea8d193d39cdb004af3743c6d2b -size 747791 +oid sha256:f7620c04f3348954880cabe4fb061718880ebfa2e7dd68bd43dab93078d0849c +size 936334 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedulel/00__rt_trip_updates_report__name_redwood-coast-schedulel.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedulel/00__rt_trip_updates_report__name_redwood-coast-schedulel.ipynb deleted file mode 100644 index 979e47441..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_redwood-coast-schedulel/00__rt_trip_updates_report__name_redwood-coast-schedulel.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e2ac8020f5ff7f3664084e2a09c3b7fc461efb0b1c798c1e9c6b936ca64e83ca -size 548930 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_roseville-transit-gmv-schedule/00__rt_trip_updates_report__name_roseville-transit-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_roseville-transit-gmv-schedule/00__rt_trip_updates_report__name_roseville-transit-gmv-schedule.ipynb index 66fa1ff55..2daade094 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_roseville-transit-gmv-schedule/00__rt_trip_updates_report__name_roseville-transit-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_roseville-transit-gmv-schedule/00__rt_trip_updates_report__name_roseville-transit-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d744de70f38c380d4495d59cb13dae9eee5f7b90429703ba8ec72f7753f3bc5 -size 300513 +oid sha256:74b82f05dab094824ab8816d4b1613bd2f47963013c11be44759eb8662ffe5af +size 512997 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_san-francisco-bay-ferry-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_san-francisco-bay-ferry-schedule.ipynb index 6f67423f8..4548f82f1 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_san-francisco-bay-ferry-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_san-francisco-bay-ferry-schedule/00__rt_trip_updates_report__name_san-francisco-bay-ferry-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f2c3705ca249f8e2f70052d46b9ef3de441e26a40fcd95b2466f99f521cf3bf -size 362318 +oid sha256:b98991b8e1ed1d333e6c5f3f020d1c0ba8efea3f788fbf1d976b6e9d569087de +size 262407 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_san-joaquin-schedule/00__rt_trip_updates_report__name_san-joaquin-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_san-joaquin-schedule/00__rt_trip_updates_report__name_san-joaquin-schedule.ipynb index cb2399059..84ef0b694 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_san-joaquin-schedule/00__rt_trip_updates_report__name_san-joaquin-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_san-joaquin-schedule/00__rt_trip_updates_report__name_san-joaquin-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79e79bad189fe18b1e842c75d447571cdcbd57c4f025077f9576c72649324944 -size 1663293 +oid sha256:a713162b1799048ff9498f63658652bf6d666b80d3c968274139fad362612b65 +size 2120055 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_santa-rosa-citybus-gmv-schedule/00__rt_trip_updates_report__name_santa-rosa-citybus-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_santa-rosa-citybus-gmv-schedule/00__rt_trip_updates_report__name_santa-rosa-citybus-gmv-schedule.ipynb index be933c6c0..695970ee3 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_santa-rosa-citybus-gmv-schedule/00__rt_trip_updates_report__name_santa-rosa-citybus-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_santa-rosa-citybus-gmv-schedule/00__rt_trip_updates_report__name_santa-rosa-citybus-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31b8d3e6142da2b24799c525f5cbadea3ee9558882b9d8b92570ebee8407c85c -size 1209119 +oid sha256:65cb7865620a64ebabdc480354f1b9f3e4bc52ac68f51d4db7a2074fce3a1562 +size 1812375 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_scvta-schedule/00__rt_trip_updates_report__name_scvta-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_scvta-schedule/00__rt_trip_updates_report__name_scvta-schedule.ipynb index f6f54bd74..620081b76 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_scvta-schedule/00__rt_trip_updates_report__name_scvta-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_scvta-schedule/00__rt_trip_updates_report__name_scvta-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bb9aabf4cb000a0e613ff41aedac1d9dfb678c78df938b851e1b81b43e97d8e -size 9533431 +oid sha256:863fd5ba04a0da68e2dff43343f7bb95f51457373bb7c783c0367d9c2546b452 +size 6805912 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_smart-schedule/00__rt_trip_updates_report__name_smart-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_smart-schedule/00__rt_trip_updates_report__name_smart-schedule.ipynb index 3495ee9ef..28f4efd16 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_smart-schedule/00__rt_trip_updates_report__name_smart-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_smart-schedule/00__rt_trip_updates_report__name_smart-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:309cc03b07ff3a3f12f8ca65983272796e070a91c4e3f37cb330a6cbd0bcee35 -size 385625 +oid sha256:50d50df82cfb869f7c19d6bf5cb3e146739b39dbe94ff2f85d23d64ff6eba727 +size 849004 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tahoe-transportation-district-gmv-schedule/00__rt_trip_updates_report__name_tahoe-transportation-district-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tahoe-transportation-district-gmv-schedule/00__rt_trip_updates_report__name_tahoe-transportation-district-gmv-schedule.ipynb index c9cc8a36c..625e84ba9 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_tahoe-transportation-district-gmv-schedule/00__rt_trip_updates_report__name_tahoe-transportation-district-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_tahoe-transportation-district-gmv-schedule/00__rt_trip_updates_report__name_tahoe-transportation-district-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8688639957c27a0aac76cdd199691bb198f154d0d54f37db673d61b516627fa7 -size 686772 +oid sha256:efb0d284929716e18a892b1c391226ac82b1d9d2ae4463ee0dbd5e7004ab3f64 +size 1082678 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tcrta-tripshot-schedule/00__rt_trip_updates_report__name_tcrta-tripshot-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tcrta-tripshot-schedule/00__rt_trip_updates_report__name_tcrta-tripshot-schedule.ipynb index e3842c5a4..4d4b3d1c4 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_tcrta-tripshot-schedule/00__rt_trip_updates_report__name_tcrta-tripshot-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_tcrta-tripshot-schedule/00__rt_trip_updates_report__name_tcrta-tripshot-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59849f6f5f5b0818f2a167b88c68b9799686567b565ce940862dfcb09c2df268 -size 734861 +oid sha256:fdf72f59b6689741492c219af73a60483c93f5c7506f249e3a2c9df020ee3700 +size 1099107 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tehama-schedule/00__rt_trip_updates_report__name_tehama-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tehama-schedule/00__rt_trip_updates_report__name_tehama-schedule.ipynb index 293465b07..af1d8f8df 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_tehama-schedule/00__rt_trip_updates_report__name_tehama-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_tehama-schedule/00__rt_trip_updates_report__name_tehama-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17065e13be5da561d40c1f042a7e46e3b3a287976a7ad34c568b4a2c307b4152 -size 550478 +oid sha256:f97a885fe5077f0db1cb50ec267ac79dd74e71345c2c3e34419c99279f1b9044 +size 825343 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_torrance-schedule/00__rt_trip_updates_report__name_torrance-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_torrance-schedule/00__rt_trip_updates_report__name_torrance-schedule.ipynb index b84ddd974..f4739ffe7 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_torrance-schedule/00__rt_trip_updates_report__name_torrance-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_torrance-schedule/00__rt_trip_updates_report__name_torrance-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61fe378eaad06f4c0105483acb0e0fb9010622a1fe994a8e0ef7fb71ec39286d -size 1109480 +oid sha256:06d4f597a7efb392b10128a64465c6f3dce776a85b5482a76d2368b588109a6b +size 2004179 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tri-valley-wheels-schedule/00__rt_trip_updates_report__name_tri-valley-wheels-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tri-valley-wheels-schedule/00__rt_trip_updates_report__name_tri-valley-wheels-schedule.ipynb index 8e3805273..df1340a49 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_tri-valley-wheels-schedule/00__rt_trip_updates_report__name_tri-valley-wheels-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_tri-valley-wheels-schedule/00__rt_trip_updates_report__name_tri-valley-wheels-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5769d4c8428dcb3fdd442654fdf1123eb66c0baa74087cfdb4d9308d878ab449 -size 1462586 +oid sha256:28531238935f4e173313ddbbddd18261842fa0aa2d434919b5073804b985ba65 +size 1743456 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-remix-schedule/00__rt_trip_updates_report__name_tuolumne-remix-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-remix-schedule/00__rt_trip_updates_report__name_tuolumne-remix-schedule.ipynb index 0fa183e1d..3383d2a92 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-remix-schedule/00__rt_trip_updates_report__name_tuolumne-remix-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-remix-schedule/00__rt_trip_updates_report__name_tuolumne-remix-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41a6832c681f9dd510eaf84354a0de2e40a5455b84a08e348d95c1b15884bdb5 -size 425563 +oid sha256:cc8ccf99f97c51bf78ec17b98651b9e4df1efc942959d082e80301170f1a092e +size 742614 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-schedule/00__rt_trip_updates_report__name_tuolumne-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-schedule/00__rt_trip_updates_report__name_tuolumne-schedule.ipynb deleted file mode 100644 index fecf69a15..000000000 --- a/portfolio/rt_trip_updates_stop_metrics/name_tuolumne-schedule/00__rt_trip_updates_report__name_tuolumne-schedule.ipynb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0fffbc224ae7706ee8e736d085253e31423c1d78f70c390ddcb1ef2d7eb58b7c -size 407462 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_turlock-schedule/00__rt_trip_updates_report__name_turlock-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_turlock-schedule/00__rt_trip_updates_report__name_turlock-schedule.ipynb index 77106fdd9..a168be7d1 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_turlock-schedule/00__rt_trip_updates_report__name_turlock-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_turlock-schedule/00__rt_trip_updates_report__name_turlock-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c325ac5bbf5c3f607f8e23b6fc95a992e56a43a09792dbef47a00d16237864c -size 491812 +oid sha256:4bad0c28edd36e82ef9549afdaa24d628aec0a3970ba677cee6dac456efe3fa5 +size 896702 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_union-city-gmv-schedule/00__rt_trip_updates_report__name_union-city-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_union-city-gmv-schedule/00__rt_trip_updates_report__name_union-city-gmv-schedule.ipynb index b21a1548b..4eefd3626 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_union-city-gmv-schedule/00__rt_trip_updates_report__name_union-city-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_union-city-gmv-schedule/00__rt_trip_updates_report__name_union-city-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46047f84fa630404cfd34a257c0ea20efa1c459a1fb1869f70311b82b7c4dda3 -size 1138986 +oid sha256:aceb8b805479932afe58595dad87bd994b40b13459c9de7270a204493a0b10ba +size 1164778 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_vctc-gmv-schedule/00__rt_trip_updates_report__name_vctc-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_vctc-gmv-schedule/00__rt_trip_updates_report__name_vctc-gmv-schedule.ipynb index c70ebbf7d..6d6cef4c9 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_vctc-gmv-schedule/00__rt_trip_updates_report__name_vctc-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_vctc-gmv-schedule/00__rt_trip_updates_report__name_vctc-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c15c50bdb7d3c5f7d8e2116101ac49e8fcf721c77d77d62d4a40ec8b28f612b -size 8543213 +oid sha256:9803d76f05556cb9ea359b008161cc02fad8aa4606d65d6f987ce1a120f25387 +size 3591435 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_victor-valley-gmv-schedule/00__rt_trip_updates_report__name_victor-valley-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_victor-valley-gmv-schedule/00__rt_trip_updates_report__name_victor-valley-gmv-schedule.ipynb index b80396042..2decb2673 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_victor-valley-gmv-schedule/00__rt_trip_updates_report__name_victor-valley-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_victor-valley-gmv-schedule/00__rt_trip_updates_report__name_victor-valley-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9adec0527950270c2cf06c8b9a59a720c1b3d5ad4ab96514dad0a5945e73d848 -size 5619382 +oid sha256:b517f8da6c2c70df732cfc3ff39a3e54cb1d8a60ea42cb5708e9dfef75932ac3 +size 3216158 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_vine-gmv-schedule/00__rt_trip_updates_report__name_vine-gmv-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_vine-gmv-schedule/00__rt_trip_updates_report__name_vine-gmv-schedule.ipynb index 42a15dd14..fe4c430b3 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_vine-gmv-schedule/00__rt_trip_updates_report__name_vine-gmv-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_vine-gmv-schedule/00__rt_trip_updates_report__name_vine-gmv-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4b885b8f978df8693a441ccafa1710d5dbaa097f86c03d8068fa6628802fd94 -size 1434437 +oid sha256:282098f0766cca63f6cfb35d4720c45ea587e19b77e3c021b6c1c153036c862d +size 1430721 diff --git a/portfolio/rt_trip_updates_stop_metrics/name_visalia-schedule/00__rt_trip_updates_report__name_visalia-schedule.ipynb b/portfolio/rt_trip_updates_stop_metrics/name_visalia-schedule/00__rt_trip_updates_report__name_visalia-schedule.ipynb index 23831b868..06c898647 100644 --- a/portfolio/rt_trip_updates_stop_metrics/name_visalia-schedule/00__rt_trip_updates_report__name_visalia-schedule.ipynb +++ b/portfolio/rt_trip_updates_stop_metrics/name_visalia-schedule/00__rt_trip_updates_report__name_visalia-schedule.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56d39f9c808be0e042c988eeb86c83bdeaf78b369a93b953c0ba0b86ddd7c5e4 -size 1649921 +oid sha256:dff990f0c0213ca40a560618f2d0467a32aee11987b7ff199ea5e25d3e218853 +size 1908088 diff --git a/portfolio/sites/rt_trip_updates_stop_metrics.yml b/portfolio/sites/rt_trip_updates_stop_metrics.yml index 3ce5e18d7..0c2c69c58 100644 --- a/portfolio/sites/rt_trip_updates_stop_metrics.yml +++ b/portfolio/sites/rt_trip_updates_stop_metrics.yml @@ -51,8 +51,6 @@ parts: name: Bay Area 511 Vine Transit Schedule - params: name: Beach Cities GMV Schedule - - params: - name: Beaumont Pass Schedule - params: name: Beaumont Transit Schedule - params: @@ -73,8 +71,6 @@ parts: name: Fairfield Schedule - params: name: Fresno Schedule - - params: - name: Historic Tuolumne Schedule - params: name: Humboldt Schedule - params: @@ -97,8 +93,6 @@ parts: name: Marin GMV Schedule - params: name: Marin Optibus Schedule - - params: - name: Marin Schedule - params: name: Mendocino Schedule - params: @@ -113,8 +107,6 @@ parts: name: North County Schedule - params: name: OCTA Schedule - - params: - name: Ojai Schedule - params: name: Petaluma GMV Schedule - params: @@ -123,8 +115,6 @@ parts: name: Redding Schedule - params: name: Redwood Coast Schedule - - params: - name: Redwood Coast Schedulel - params: name: Roseville Transit GMV Schedule - params: @@ -149,8 +139,6 @@ parts: name: Tri-Valley Wheels Schedule - params: name: Tuolumne Remix Schedule - - params: - name: Tuolumne Schedule - params: name: Turlock Schedule - params: diff --git a/rt_predictions/07_stop_prediction_error_exploration.ipynb b/rt_predictions/07_stop_prediction_error_exploration.ipynb new file mode 100644 index 000000000..d8cc3c311 --- /dev/null +++ b/rt_predictions/07_stop_prediction_error_exploration.ipynb @@ -0,0 +1,1461 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "45c2f6d0-52f7-456d-8c10-725e2c3fab0b", + "metadata": {}, + "source": [ + "# Daily Stop Grain Exploration\n", + "\n", + "1. Make sure that `avg_prediction_error_sec` matches up with how a prediction is categorized as `early/on_time/late`, and make sure those seconds have the right signs.\n", + "1. Make sure that `early/on_time/late` metrics make sense with `pct_accuracy`\n", + "1. Deeper dive into the \"accuracy\" exponential curve. See if we can use this as \"expected wait time\" metric." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d2c0f29f-b019-41d3-9a45-499ecb76344b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import altair as alt\n", + "import pandas as pd\n", + "\n", + "import prep_data\n", + "from rt_msa_utils import PREDICTIONS_GCS, RT_MSA_DICT\n", + "\n", + "alt.data_transformers.enable(\"vegafusion\")\n", + "\n", + "DOWNLOAD_DICT = RT_MSA_DICT.rt_trip_updates_downloads" + ] + }, + { + "cell_type": "markdown", + "id": "4998a876-dc95-4f49-90d7-123b78e2a3a5", + "metadata": {}, + "source": [ + "## Daily Stop Grain\n", + "### Avg prediction error seconds is positive for bus arriving after prediction says (prediction is **earlier** than actual)\n", + "* yes, the sign direction is correct\n", + "* we will want to remove outliers, maybe anything above a certain threshold of minutes (here, it's 1% or less for outliers)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7cbc169a-0bb0-4254-82e5-1c33008c19a9", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "key object\n", + "stop_key object\n", + "base64_url object\n", + "service_date datetime64[ns]\n", + "stop_id object\n", + "schedule_feed_key object\n", + "avg_prediction_error_sec float64\n", + "n_tu_accurate_minutes Int64\n", + "n_tu_complete_minutes Int64\n", + "n_tu_minutes_available Int64\n", + "avg_prediction_spread_minutes float64\n", + "n_predictions Int64\n", + "n_predictions_early Int64\n", + "n_predictions_ontime Int64\n", + "n_predictions_late Int64\n", + "n_tu_trips Int64\n", + "dtype: object" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "FILE = RT_MSA_DICT.rt_trip_updates_downloads.daily_stop_grain\n", + "\n", + "daily_df = pd.read_parquet(\n", + " f\"{PREDICTIONS_GCS}{FILE}.parquet\"\n", + ")\n", + "\n", + "daily_df.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "85f40f62-808e-4a6b-96e6-981b232fcbf9", + "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", + "
avg_prediction_error_secpct_tu_predictions_earlypct_tu_predictions_ontimepct_tu_predictions_late
count926463.000000942162.0942162.0942162.0
mean49.1874350.6313390.039020.302079
std123.1586590.1974010.1070540.161343
min-22509.6923080.00.00.0
1%-185.9202270.00.00.0
5%-46.2433390.250.00.05
10%-15.8333330.390.00.11
25%21.0454540.530.010.19
50%55.8866650.670.010.29
75%85.3999780.770.020.4
90%115.5613610.840.060.51
95%138.6942200.880.180.58
99%214.4279550.960.510.75
max1513.9304761.01.01.0
\n", + "
" + ], + "text/plain": [ + " avg_prediction_error_sec pct_tu_predictions_early \\\n", + "count 926463.000000 942162.0 \n", + "mean 49.187435 0.631339 \n", + "std 123.158659 0.197401 \n", + "min -22509.692308 0.0 \n", + "1% -185.920227 0.0 \n", + "5% -46.243339 0.25 \n", + "10% -15.833333 0.39 \n", + "25% 21.045454 0.53 \n", + "50% 55.886665 0.67 \n", + "75% 85.399978 0.77 \n", + "90% 115.561361 0.84 \n", + "95% 138.694220 0.88 \n", + "99% 214.427955 0.96 \n", + "max 1513.930476 1.0 \n", + "\n", + " pct_tu_predictions_ontime pct_tu_predictions_late \n", + "count 942162.0 942162.0 \n", + "mean 0.03902 0.302079 \n", + "std 0.107054 0.161343 \n", + "min 0.0 0.0 \n", + "1% 0.0 0.0 \n", + "5% 0.0 0.05 \n", + "10% 0.0 0.11 \n", + "25% 0.01 0.19 \n", + "50% 0.01 0.29 \n", + "75% 0.02 0.4 \n", + "90% 0.06 0.51 \n", + "95% 0.18 0.58 \n", + "99% 0.51 0.75 \n", + "max 1.0 1.0 " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df = prep_data.calculate_percents(daily_df)\n", + "\n", + "daily_df[prep_data.PREDICTION_ERROR_COLS].describe(\n", + " percentiles = prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4a1631ac-b2be-4682-910e-6b017d78f54e", + "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", + "
avg_prediction_error_secpct_tu_predictions_earlypct_tu_predictions_ontimepct_tu_predictions_late
count914559.000000914559.0914559.0914559.0
mean51.4685110.6433980.0396250.306053
std56.7340820.1781160.1083010.154067
min-250.0000000.00.00.0
1%-130.5673980.010.00.0
5%-40.8380480.320.00.08
10%-13.8089010.410.00.12
25%21.6537520.540.010.2
50%55.8960780.670.010.29
75%84.9697490.770.020.4
90%113.9930450.840.060.51
95%134.8917080.880.180.57
99%186.1138210.960.530.72
max249.9890721.01.01.0
\n", + "
" + ], + "text/plain": [ + " avg_prediction_error_sec pct_tu_predictions_early \\\n", + "count 914559.000000 914559.0 \n", + "mean 51.468511 0.643398 \n", + "std 56.734082 0.178116 \n", + "min -250.000000 0.0 \n", + "1% -130.567398 0.01 \n", + "5% -40.838048 0.32 \n", + "10% -13.808901 0.41 \n", + "25% 21.653752 0.54 \n", + "50% 55.896078 0.67 \n", + "75% 84.969749 0.77 \n", + "90% 113.993045 0.84 \n", + "95% 134.891708 0.88 \n", + "99% 186.113821 0.96 \n", + "max 249.989072 1.0 \n", + "\n", + " pct_tu_predictions_ontime pct_tu_predictions_late \n", + "count 914559.0 914559.0 \n", + "mean 0.039625 0.306053 \n", + "std 0.108301 0.154067 \n", + "min 0.0 0.0 \n", + "1% 0.0 0.0 \n", + "5% 0.0 0.08 \n", + "10% 0.0 0.12 \n", + "25% 0.01 0.2 \n", + "50% 0.01 0.29 \n", + "75% 0.02 0.4 \n", + "90% 0.06 0.51 \n", + "95% 0.18 0.57 \n", + "99% 0.53 0.72 \n", + "max 1.0 1.0 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df2 = prep_data.drop_outliers(\n", + " daily_df, prep_data.MIN_ERROR_SEC, prep_data.MAX_ERROR_SEC\n", + ")\n", + "\n", + "daily_df2[prep_data.PREDICTION_ERROR_COLS].describe(\n", + " percentiles = prep_data.PERCENTILE_LIST\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "5b586779-d3ce-4619-8d30-dac51c46127f", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.119" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Look at observations with high pct late\n", + "round(len(daily_df2[(daily_df2.pct_tu_predictions_late >= 0.5)]) / len(daily_df2), 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a2fc1e1e-b771-44e8-82b7-7dde0ffa15b6", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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GTOUn59vLrvdbqWkpCgjI0N2uz2II2sdvF6vnE6nRo8ercjIyGAPp80K9T73LwzcvWq2cENzhtbrqQ/C5akP0/5CLjG3lFA/rwOFPp/XcAXlWvy+hHSh+Ph4fetb39Jf/vIXjR49WrW1taqpqfGZhamurjbvmUlKStLu3bt99tHwlNKFNRc/uVRdXS273X7VkGSz2WSz2S5ZHxkZGdInwsXoR2CEap89dWGB/571YfLUhYVkvwMtVM/rQAv1Pjf22K/r98B8/fXX+p//+R917dpVaWlpioyM1KZNm8zthw4d0pEjR+RwOCRJDodD+/bt07Fjx8wap9Mpu92ufv36mTUX7qOhpmEfAAAAfgWY//zP/9TWrVv12WefaceOHbr33nsVERGhBx54QHFxccrJyVF+fr7ee+89VVRU6JFHHpHD4dCIESMkSRkZGerXr58eeughffjhh9q4caNmzpyp3Nxcc/bkiSee0Keffqpp06bp448/1tKlS7V69WpNmTKl+Y8eAABYkl+XkP72t7/pgQce0D/+8Q/deOONuvXWW7Vz507deOONkqQFCxYoPDxc2dnZ8ng8yszM1NKlS83XR0REaO3atZo0aZIcDofat2+vCRMmaPbs2WZNamqq1q1bpylTpmjRokXq1q2bXnnlFR6hBgAAJr8CzOuvv37V7dHR0SopKVFJSckVa3r06HHNpwVGjhypvXv3+jM0AAAQQvgsJAAAYDkEGAAAYDnX9Rg1gNDVc/q6YA/Bx+XG89ncrCCMBEAgMAMDAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAshwADAAAsp12wBwDAGnpOXxfsIQCAiRkYAABgOQQYAABgOdcVYObOnauwsDDl5eWZ686ePavc3Fx16dJFHTp0UHZ2tqqrq31ed+TIEWVlZSk2NlYJCQmaOnWqzp0751OzZcsWDRkyRDabTb169VJpaen1DBUAALQhTQ4we/bs0S9/+UsNHDjQZ/2UKVP0zjvvaM2aNdq6dauOHj2q++67z9xeV1enrKws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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "daily_df2[(daily_df2.pct_tu_predictions_late >= 0.5)].avg_prediction_error_sec.hist(bins=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "70a6b694-3676-40a3-97f8-28c04d1754b4", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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o8rKSr+63bt36/7771dkZKTi4uKUm5tba1tr165Vr169FBkZqb59+2r9+vWB2o1m4aWXXtK9996rqKioa37o5JEjR5SamqqoqChFR0drxowZunTpkl/Npk2bNGjQINlsNvXs2VMFBQVNP/lmLi8vTz169FBkZKSSkpK0Y8eOYE+pWdmyZYsefvhhdenSRSEhIfrggw/81huGoezsbHXu3FmtWrVScnKy/va3v/nVnDhxQuPHj5fdblf79u01adIknT17NoB7cfNbsGCBfvSjH6lt27aKjo7WmDFjdPDgQb+aixcvKj09XZ06dVKbNm00duzYWh+CW5/3kZaKkNPCHDhwQNXV1Xr99de1b98+LVmyRPn5+frlL39p1ni9XqWkpKh79+4qLS3Vyy+/rJycHL3xxhtmzdatW/Xkk09q0qRJ2rVrl8aMGaMxY8Zo7969wditm1JlZaUef/xxTZ069arrq6qqlJqaqsrKSm3dulVvv/22CgoKlJ2dbdYcOnRIqampGj58uMrKyjRt2jQ9++yzKioqCtRuNDurV69WZmam5syZo88++0z9+/eX0+nU8ePHgz21ZuPcuXPq37+/8vLyrro+NzdXv/3tb5Wfn6/t27erdevWcjqdunjxolkzfvx47du3Ty6XS+vWrdOWLVv03HPPBWoXmoXNmzcrPT1d27Ztk8vlks/nU0pKis6dO2fWTJ8+XR9++KHWrl2rzZs36+jRo3rsscfM9fV5H2nRDLR4ubm5Rnx8vLn86quvGh06dDAqKirMsRdeeMG4++67zeX//M//NFJTU/22k5SUZPzsZz9r+gk3MytXrjTatWtXa3z9+vVGaGio4fF4zLHXXnvNsNvtZu9nzpxp3HPPPX6PGzdunOF0Opt0zs3ZkCFDjPT0dHO5qqrK6NKli7FgwYIgzqr5kmS8//775nJ1dbURGxtrvPzyy+bYqVOnDJvNZvzud78zDMMw9u/fb0gyPv30U7PmT3/6kxESEmL885//DNjcm5vjx48bkozNmzcbhnG5r+Hh4cbatWvNms8//9yQZLjdbsMw6vc+0pJxJAc6ffq0OnbsaC673W498MADioiIMMecTqcOHjyokydPmjXJycl+23E6nXK73YGZtAW43W717dvX78MrnU6nvF6v9u3bZ9bQ5/qrrKxUaWmpX89CQ0OVnJxMzxrJoUOH5PF4/Hrcrl07JSUlmT12u91q3769Bg8ebNYkJycrNDRU27dvD/icm4vTp09Lkvl+XFpaKp/P59frXr16qVu3bn69vt77SEtGyGnhvvjiC73yyiv62c9+Zo55PJ5anxpds+zxeOqsqVmP6/shffZ6vbpw4UJgJtqM/Otf/1JVVRWvzSZU08e6euzxeBQdHe23/pZbblHHjh3573AN1dXVmjZtmn784x+rT58+ki73MSIiotY1fd/v9fXeR1oyQo5FzJo1SyEhIXX+HDhwwO8x//znPzVq1Cg9/vjjmjx5cpBm3rzcSJ8B4HrS09O1d+9evffee8GeiqU06++uwnd+8Ytf6Omnn66z5vbbbzf/fvToUQ0fPlz33nuv3wXFkhQbG1vr6v2a5djY2DpratZbVUP7XJfY2Nhad/3Ut892u12tWrWq56xbjltvvVVhYWEt8rUZKDV9LC8vV+fOnc3x8vJyDRgwwKz5/oXely5d0okTJ/jvcBUZGRnmxdldu3Y1x2NjY1VZWalTp075Hc258vVcn/eRlowjORZx2223qVevXnX+1Fxj889//lPDhg1TYmKiVq5cqdBQ/5eBw+HQli1b5PP5zDGXy6W7775bHTp0MGtKSkr8HudyueRwOJp4T4OrIX2+HofDoT179vj9Y+ByuWS325WQkGDWtMQ+36iIiAglJib69ay6ulolJSX0rJHEx8crNjbWr8der1fbt283e+xwOHTq1CmVlpaaNRs3blR1dbWSkpICPueblWEYysjI0Pvvv6+NGzcqPj7eb31iYqLCw8P9en3w4EEdOXLEr9fXex9p0YJ95TMC6+uvvzZ69uxpjBgxwvj666+NY8eOmT81Tp06ZcTExBgTJkww9u7da7z33ntGVFSU8frrr5s1f/nLX4xbbrnF+M1vfmN8/vnnxpw5c4zw8HBjz549wditm9I//vEPY9euXcbcuXONNm3aGLt27TJ27dplnDlzxjAMw7h06ZLRp08fIyUlxSgrKzM2bNhg3HbbbUZWVpa5jb///e9GVFSUMWPGDOPzzz838vLyjLCwMGPDhg3B2q2b3nvvvWfYbDajoKDA2L9/v/Hcc88Z7du397v7BHU7c+aM+XqVZCxevNjYtWuX8Y9//MMwDMNYuHCh0b59e+OPf/yjsXv3buORRx4x4uPjjQsXLpjbGDVqlDFw4EBj+/btxieffGLceeedxpNPPhmsXbopTZ061WjXrp2xadMmv/fi8+fPmzVTpkwxunXrZmzcuNHYuXOn4XA4DIfDYa6vz/tIS0bIaWFWrlxpSLrqz5X++te/Gvfdd59hs9mM//f//p+xcOHCWttas2aNcddddxkRERHGPffcYxQWFgZqN5qFtLS0q/b5448/NmsOHz5sjB492mjVqpVx6623Gr/4xS8Mn8/nt52PP/7YGDBggBEREWHcfvvtxsqVKwO7I83QK6+8YnTr1s2IiIgwhgwZYmzbti3YU2pWPv7446u+dtPS0gzDuHwb+YsvvmjExMQYNpvNGDFihHHw4EG/bXz77bfGk08+abRp08aw2+3GxIkTzYCPy671Xnzl7/iFCxeM//qv/zI6dOhgREVFGY8++qjf/5QaRv3eR1qqEMMwjAAeOAIAAAgIrskBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACWRMgBAACW9P8D8TGWzAuEsEUAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "daily_df2[(daily_df2.pct_tu_predictions_early >= 0.5)].avg_prediction_error_sec.hist(bins=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b313b745-f542-4cda-8a00-c45a762f12df", + "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", + "
pct_tu_accurate_minutespct_tu_predictions_ontime
count942162.0942162.0
mean0.7495860.03902
std0.1727750.107054
min0.00.0
1%0.00.0
5%0.410.0
10%0.560.0
25%0.70.01
50%0.790.01
75%0.850.02
90%0.910.06
95%0.940.18
99%1.00.51
max1.01.0
\n", + "
" + ], + "text/plain": [ + " pct_tu_accurate_minutes pct_tu_predictions_ontime\n", + "count 942162.0 942162.0\n", + "mean 0.749586 0.03902\n", + "std 0.172775 0.107054\n", + "min 0.0 0.0\n", + "1% 0.0 0.0\n", + "5% 0.41 0.0\n", + "10% 0.56 0.0\n", + "25% 0.7 0.01\n", + "50% 0.79 0.01\n", + "75% 0.85 0.02\n", + "90% 0.91 0.06\n", + "95% 0.94 0.18\n", + "99% 1.0 0.51\n", + "max 1.0 1.0" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df[prep_data.ACCURACY_COLS].describe(\n", + " percentiles=prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1e306b29-8b09-4177-998b-97f0c9dd40cd", + "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", + "
pct_tu_accurate_minutespct_tu_predictions_ontime
count914559.0914559.0
mean0.7674590.039625
std0.1351720.108301
min0.00.0
1%0.330.0
5%0.50.0
10%0.590.0
25%0.710.01
50%0.790.01
75%0.860.02
90%0.910.06
95%0.940.18
99%1.00.53
max1.01.0
\n", + "
" + ], + "text/plain": [ + " pct_tu_accurate_minutes pct_tu_predictions_ontime\n", + "count 914559.0 914559.0\n", + "mean 0.767459 0.039625\n", + "std 0.135172 0.108301\n", + "min 0.0 0.0\n", + "1% 0.33 0.0\n", + "5% 0.5 0.0\n", + "10% 0.59 0.0\n", + "25% 0.71 0.01\n", + "50% 0.79 0.01\n", + "75% 0.86 0.02\n", + "90% 0.91 0.06\n", + "95% 0.94 0.18\n", + "99% 1.0 0.53\n", + "max 1.0 1.0" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# These behave in the normal range, so we're only dropping outliers on avg_prediction_error_sec\n", + "# not much difference in these distributions\n", + "daily_df2[prep_data.ACCURACY_COLS].describe(percentiles=prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "markdown", + "id": "f8d0c6e0-7aac-4876-bd44-4e6133474a98", + "metadata": {}, + "source": [ + "## Stops Aggregated by Day Type\n", + "### Avg prediction error seconds is positive for early arrivals" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "8274ca17-5874-4ff6-b9f8-8ff214f6f4bb", + "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", + "
avg_prediction_error_secpct_tu_predictions_earlypct_tu_predictions_ontimepct_tu_predictions_late
count1.742386e+061.764792e+061.764792e+061.764792e+06
mean4.732094e+016.312258e-013.748932e-023.073510e-01
std1.203496e+021.711195e-019.187022e-021.366724e-01
min-2.097112e+040.000000e+000.000000e+000.000000e+00
1%-1.613084e+020.000000e+000.000000e+000.000000e+00
5%-3.716826e+013.000000e-010.000000e+001.000000e-01
10%-7.003360e+004.200000e-011.000000e-021.500000e-01
25%2.773828e+015.600000e-011.000000e-022.200000e-01
50%5.419504e+016.700000e-011.000000e-023.000000e-01
75%7.792475e+017.400000e-012.000000e-023.800000e-01
90%1.014436e+028.000000e-016.000000e-024.800000e-01
95%1.198483e+028.400000e-011.900000e-015.400000e-01
99%1.726551e+029.000000e-014.100000e-017.100000e-01
max1.188624e+031.000000e+001.000000e+001.000000e+00
\n", + "
" + ], + "text/plain": [ + " avg_prediction_error_sec pct_tu_predictions_early \\\n", + "count 1.742386e+06 1.764792e+06 \n", + "mean 4.732094e+01 6.312258e-01 \n", + "std 1.203496e+02 1.711195e-01 \n", + "min -2.097112e+04 0.000000e+00 \n", + "1% -1.613084e+02 0.000000e+00 \n", + "5% -3.716826e+01 3.000000e-01 \n", + "10% -7.003360e+00 4.200000e-01 \n", + "25% 2.773828e+01 5.600000e-01 \n", + "50% 5.419504e+01 6.700000e-01 \n", + "75% 7.792475e+01 7.400000e-01 \n", + "90% 1.014436e+02 8.000000e-01 \n", + "95% 1.198483e+02 8.400000e-01 \n", + "99% 1.726551e+02 9.000000e-01 \n", + "max 1.188624e+03 1.000000e+00 \n", + "\n", + " pct_tu_predictions_ontime pct_tu_predictions_late \n", + "count 1.764792e+06 1.764792e+06 \n", + "mean 3.748932e-02 3.073510e-01 \n", + "std 9.187022e-02 1.366724e-01 \n", + "min 0.000000e+00 0.000000e+00 \n", + "1% 0.000000e+00 0.000000e+00 \n", + "5% 0.000000e+00 1.000000e-01 \n", + "10% 1.000000e-02 1.500000e-01 \n", + "25% 1.000000e-02 2.200000e-01 \n", + "50% 1.000000e-02 3.000000e-01 \n", + "75% 2.000000e-02 3.800000e-01 \n", + "90% 6.000000e-02 4.800000e-01 \n", + "95% 1.900000e-01 5.400000e-01 \n", + "99% 4.100000e-01 7.100000e-01 \n", + "max 1.000000e+00 1.000000e+00 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "FILE = RT_MSA_DICT.rt_schedule_models.weekday_stop_grain\n", + "\n", + "daytype_df = pd.read_parquet(\n", + " f\"{PREDICTIONS_GCS}{FILE}.parquet\", \n", + ")\n", + "\n", + "daytype_df[prep_data.PREDICTION_ERROR_COLS].describe(\n", + " percentiles=prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ca4701a3-ab51-447d-89a8-3b2c75862593", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(-20971.125, 1188.6239734933854)" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daytype_df.avg_prediction_error_sec.min(), daytype_df.avg_prediction_error_sec.max()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "75bf72c2-1c28-42b7-ab18-da12314fd81b", + "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", + "
avg_prediction_error_secpct_tu_predictions_earlypct_tu_predictions_ontimepct_tu_predictions_late
count1.727213e+061.727213e+061.727213e+061.727213e+06
mean4.989460e+016.410566e-013.796528e-023.096397e-01
std4.924638e+011.533830e-019.267598e-021.289014e-01
min-2.499416e+020.000000e+000.000000e+000.000000e+00
1%-1.184392e+021.100000e-010.000000e+002.000000e-02
5%-3.224838e+013.500000e-010.000000e+001.200000e-01
10%-5.213724e+004.500000e-011.000000e-021.600000e-01
25%2.826944e+015.700000e-011.000000e-022.200000e-01
50%5.430531e+016.700000e-011.000000e-023.000000e-01
75%7.781720e+017.400000e-012.000000e-023.800000e-01
90%1.008661e+028.000000e-016.000000e-024.800000e-01
95%1.183707e+028.400000e-011.900000e-015.300000e-01
99%1.612898e+029.000000e-014.200000e-016.700000e-01
max2.496432e+021.000000e+001.000000e+001.000000e+00
\n", + "
" + ], + "text/plain": [ + " avg_prediction_error_sec pct_tu_predictions_early \\\n", + "count 1.727213e+06 1.727213e+06 \n", + "mean 4.989460e+01 6.410566e-01 \n", + "std 4.924638e+01 1.533830e-01 \n", + "min -2.499416e+02 0.000000e+00 \n", + "1% -1.184392e+02 1.100000e-01 \n", + "5% -3.224838e+01 3.500000e-01 \n", + "10% -5.213724e+00 4.500000e-01 \n", + "25% 2.826944e+01 5.700000e-01 \n", + "50% 5.430531e+01 6.700000e-01 \n", + "75% 7.781720e+01 7.400000e-01 \n", + "90% 1.008661e+02 8.000000e-01 \n", + "95% 1.183707e+02 8.400000e-01 \n", + "99% 1.612898e+02 9.000000e-01 \n", + "max 2.496432e+02 1.000000e+00 \n", + "\n", + " pct_tu_predictions_ontime pct_tu_predictions_late \n", + "count 1.727213e+06 1.727213e+06 \n", + "mean 3.796528e-02 3.096397e-01 \n", + "std 9.267598e-02 1.289014e-01 \n", + "min 0.000000e+00 0.000000e+00 \n", + "1% 0.000000e+00 2.000000e-02 \n", + "5% 0.000000e+00 1.200000e-01 \n", + "10% 1.000000e-02 1.600000e-01 \n", + "25% 1.000000e-02 2.200000e-01 \n", + "50% 1.000000e-02 3.000000e-01 \n", + "75% 2.000000e-02 3.800000e-01 \n", + "90% 6.000000e-02 4.800000e-01 \n", + "95% 1.900000e-01 5.300000e-01 \n", + "99% 4.200000e-01 6.700000e-01 \n", + "max 1.000000e+00 1.000000e+00 " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daytype_df2 = prep_data.drop_outliers(\n", + " daytype_df, prep_data.MIN_ERROR_SEC, prep_data.MAX_ERROR_SEC\n", + ")\n", + "\n", + "daytype_df2[prep_data.PREDICTION_ERROR_COLS].describe(\n", + " percentiles=prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e508bb82-20be-406b-8293-16dabb9f6f59", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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GIcAAwAAjEOAAQAAxiHARJiDBw+qsLBQWVlZSkhI0Be+8AXNnj1bLS0tQXXvvvuubr31VsXHxyszM1Pl5eXttvXKK6/ommuuUXx8vEaOHKkNGzZ0125EjCeffFI33XSTEhMTz/tgxkOHDik/P1+JiYlKTU3V9OnTdfr06aCaN998UzfeeKMcDoeGDBmiVatWXf7GQ5JUUVGhwYMHKz4+XtnZ2dq+fXu4mxSRtmzZoq997WvKyMhQVFSUXnvttaDllmWprKxM6enpSkhIUG5urt57772gmqNHj6qgoEBOp1PJyckqLCzUJ5980o17gTMRYCLMn//8ZwUCAb344otqaGjQkiVLVFlZqR/96Ed2jc/nU15engYNGqT6+no9/fTTmjNnjlasWGHXbN26Vffdd58KCwu1c+dOTZw4URMnTtSePXvCsVu9VktLi+6991498sgj51ze2tqq/Px8tbS0aOvWrfr5z3+uVatWqayszK45cOCA8vPzdfvtt2vXrl0qKSnRgw8+qE2bNnXXbkSstWvXqrS0VLNnz9Yf//hHXX/99XK73Tpy5Ei4mxZxTpw4oeuvv14VFRXnXF5eXq5ly5apsrJSdXV16tu3r9xut06dOmXXFBQUqKGhQR6PR+vXr9eWLVs0bdq07toFnK1Lvn0RRisvL7eysrLs6Z/85CdW//79rebmZnveD3/4Q2vo0KH29L/9279Z+fn5QdvJzs62Hnroocvf4Ai0cuVKKykpqd38DRs2WNHR0ZbX67XnvfDCC5bT6bT7b8aMGda1114btN43vvENy+12X9Y2w7LGjh1rFRUV2dOtra1WRkaGtWDBgjC2CpKsV1991Z4OBAKWy+Wynn76aXteU1OT5XA4rF/+8peWZVnW3r17LUnWjh077Jrf/va3VlRUlHX48OFuazv+iREY6NixY0pJSbGna2trNX78eMXFxdnz3G639u/fr48//tiuyc3NDdqO2+1WbW1t9zQakj7rh5EjRwY94NHtdsvn86mhocGuoa+6X0tLi+rr64OOfXR0tHJzczn2PcyBAwfk9XqD+iopKUnZ2dl2X9XW1io5OVljxoyxa3JzcxUdHa26urpubzM4hRTx/vrXv2r58uV66KGH7Hler7fdE4/bpr1e7wVr2paje1xKX/l8Pn366afd09AI9H//939qbW3lc2KAtv64UF95vV6lpqYGLe/Tp49SUlLozzAhwPQSM2fOVFRU1AVff/7zn4PWOXz4sO68807de++9mjp1aphaHnk601cAgGA99ruQEJof/OAH+va3v33Bms9//vP23z/88EPdfvvtuummm4IuzpUkl8ulxsbGoHlt0y6X64I1bctxfqH21YW4XK52d7VcbF85nU4lJCRcZKsRqoEDByomJobPiQHa+qOxsVHp6en2/MbGRo0aNcquOfvi69OnT+vo0aP0Z5gQYHqJK6+8UldeeeVF1R4+fFi33367Ro8erZUrVyo6OnggLicnRz/+8Y/l9/sVGxsrSfJ4PBo6dKj69+9v19TU1KikpMRez+PxKCcnp2t2qBcLpa86kpOToyeffFJHjhyxh7c9Ho+cTqeGDx9u15x9izt9dfnFxcVp9OjRqqmp0cSJEyVJgUBANTU1Ki4uDm/jECQrK0sul0s1NTV2YPH5fKqrq7PvAMzJyVFTU5Pq6+s1evRoSdLmzZsVCASUnZ0drqZHtnBfRYzu9fe//90aMmSINWHCBOvvf/+79Y9//MN+tWlqarLS0tKs+++/39qzZ4/18ssvW4mJidaLL75o17zzzjtWnz59rGeeecbat2+fNXv2bCs2NtbavXt3OHar13r//fetnTt3WnPnzrWuuOIKa+fOndbOnTut48ePW5ZlWadPn7ZGjBhh5eXlWbt27bI2btxoXXnlldasWbPsbfztb3+zEhMTrenTp1v79u2zKioqrJiYGGvjxo3h2q2I8fLLL1sOh8NatWqVtXfvXmvatGlWcnJy0F1j6B7Hjx+3Pz+SrMWLF1s7d+603n//fcuyLGvhwoVWcnKy9Zvf/MZ69913rbvvvtvKysqyPv30U3sbd955p3XDDTdYdXV11ttvv239y7/8i3XfffeFa5ciHgEmwqxcudKSdM7Xmf70pz9Zt9xyi+VwOKzPfe5z1sKFC9tta926ddYXv/hFKy4uzrr22mutqqqq7tqNiDFlypRz9tUbb7xh1xw8eND6yle+YiUkJFgDBw60fvCDH1h+vz9oO2+88YY1atQoKy4uzvr85z9vrVy5snt3JIItX77cuvrqq624uDhr7Nix1rZt28LdpIj0xhtvnPOzNGXKFMuyPruV+vHHH7fS0tIsh8NhTZgwwdq/f3/QNj766CPrvvvus6644grL6XRa3/nOd+xfJtD9oizLsrp92AcAAOAScBcSAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMb5f0Ec8p4HTtPBAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "daytype_df2[(daytype_df2.pct_tu_predictions_late >= 0.5)].avg_prediction_error_sec.hist(bins=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "60bf3b84-460e-4d6e-93ef-4bc7ad583e2e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAGdCAYAAAD+JxxnAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAL0hJREFUeJzt3Xt0VOXd9vErCcmEADmAJiEaIa3KWVCQGE9LS8xQY5dRSgV5NMUIHhIrpC8IvpzRAqEgR43WCnY9UpH1vFAlGJgnKFQZAkZQzrWrIFacYIUwCJIMyX7/cGXDEISgk8nh/n7Wyqpz79/sufevk8nFPXvPhFiWZQkAAMBAoY09AQAAgMZCEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGKtVY0+gKaupqdGhQ4fUrl07hYSENPZ0AABAPViWpePHjyspKUmhoRde8yEIXcChQ4eUnJzc2NMAAAA/whdffKErr7zygjWXHIQ2btyo2bNnq6ysTF999ZVWrlyprKwse7tlWZo8ebL+9Kc/qaKiQrfccoteeuklXXPNNXbNkSNH9NRTT+mdd95RaGioBg0apPnz56tt27Z2zaeffqrc3Fxt3bpVl19+uZ566imNHTvWby4rVqzQxIkTdeDAAV1zzTWaNWuW7r777kuay4W0a9dO0veNjI6OvtRWtTg+n0/r1q1TRkaGwsPDG3s6LRZ9Dg76HDz0Ojjo8xler1fJycn23/ELueQgdOLECfXu3VuPPPKI7r///jrbCwoKtGDBAr3++utKSUnRxIkT5XQ6tXv3bkVGRkqShg0bpq+++koul0s+n0/Dhw/XyJEjtWzZMvsAMjIylJ6ersLCQu3YsUOPPPKIYmNjNXLkSEnSpk2bNHToUM2YMUP33HOPli1bpqysLH388cfq2bNnvedyIbVvh0VHRxOE9P0vWVRUlKKjo43/JWtI9Dk46HPw0OvgoM911eu0FusnkGStXLnSvl1TU2MlJiZas2fPtscqKiosh8Nh/fWvf7Usy7J2795tSbK2bt1q17z77rtWSEiI9eWXX1qWZVkvvviiFRcXZ1VWVto1zzzzjNWlSxf79m9+8xsrMzPTbz6pqanWY489Vu+5XMyxY8csSdaxY8fqVd/SVVVVWatWrbKqqqoaeyotGn0ODvocPPQ6OOjzGZfy9zug5wjt379fHo9H6enp9lhMTIxSU1Pldrs1ZMgQud1uxcbGql+/fnZNenq6QkNDVVpaqvvuu09ut1u33367IiIi7Bqn06lZs2bp6NGjiouLk9vtVn5+vt/jO51OrVq1qt5zOVdlZaUqKyvt216vV9L3Kdvn8/205rQAtT2gFw2LPgcHfQ4eeh0c9PmMS+lBQIOQx+ORJCUkJPiNJyQk2Ns8Ho/i4+P9J9Gqldq3b+9Xk5KSUmcftdvi4uLk8Xgu+jgXm8u5ZsyYoalTp9YZX7dunaKion7gqM3jcrkaewpGoM/BQZ+Dh14HB32WTp48We9arho7y/jx4/1WmWpPtsrIyOAcIX2fsF0ul+666y7ef25A9Dk46HPw0OvgoM9n1L6jUx8BDUKJiYmSpPLycnXs2NEeLy8vV58+feyaw4cP+93v9OnTOnLkiH3/xMRElZeX+9XU3r5YzdnbLzaXczkcDjkcjjrj4eHhxj+pzkY/goM+Bwd9Dh56HRz0WZd0/AH9ZOmUlBQlJiaqpKTEHvN6vSotLVVaWpokKS0tTRUVFSorK7Nr1q9fr5qaGqWmpto1Gzdu9HuPz+VyqUuXLoqLi7Nrzn6c2prax6nPXAAAgNkuOQh9++232r59u7Zv3y7p+5OSt2/froMHDyokJESjRo3Sc889p7fffls7duzQww8/rKSkJPuzhrp166aBAwdqxIgR2rJliz788EPl5eVpyJAhSkpKkiQ9+OCDioiIUE5Ojnbt2qXly5dr/vz5fm9bPf300youLtacOXO0d+9eTZkyRR999JHy8vIkqV5zAQAAhrvUS9Lee+89S1Kdn+zsbMuyvr9sfeLEiVZCQoLlcDisAQMGWPv27fPbxzfffGMNHTrUatu2rRUdHW0NHz7cOn78uF/NJ598Yt16662Ww+GwrrjiCmvmzJl15vLWW29Z1157rRUREWH16NHDKioq8tten7lcCJfP++PSzOCgz8FBn4OHXgcHfT7jUv5+h1iWZTViDmvSvF6vYmJidOzYMU6W1vcn4q1Zs0Z333238e8/NyT6HBz0OXjodXDQ5zMu5e833z4PAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYfMUGADQjnccV1Rk7MDOzEWYCtAysCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCxOlgaAFoYTqoH6Y0UIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxuGoMAJq5810lBqB+WBECAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCy+fR4ADHDuN9QfmJnZSDMBmhZWhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLL5rDACasHO/IwxAYLEiBAAAjMWKEAAY6HwrTXwjPUzEihAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjMV3jQFAE8E3zQPBx4oQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjBTwIVVdXa+LEiUpJSVHr1q3185//XNOnT5dlWXaNZVmaNGmSOnbsqNatWys9PV2fffaZ336OHDmiYcOGKTo6WrGxscrJydG3337rV/Ppp5/qtttuU2RkpJKTk1VQUFBnPitWrFDXrl0VGRmpXr16ac2aNYE+ZAAA0EwFPAjNmjVLL730khYtWqQ9e/Zo1qxZKigo0MKFC+2agoICLViwQIWFhSotLVWbNm3kdDp16tQpu2bYsGHatWuXXC6XVq9erY0bN2rkyJH2dq/Xq4yMDHXq1EllZWWaPXu2pkyZoldeecWu2bRpk4YOHaqcnBxt27ZNWVlZysrK0s6dOwN92AAAoBkKeBDatGmT7r33XmVmZqpz58769a9/rYyMDG3ZskXS96tB8+bN04QJE3Tvvffquuuu01/+8hcdOnRIq1atkiTt2bNHxcXFevXVV5Wamqpbb71VCxcu1JtvvqlDhw5Jkt544w1VVVXptddeU48ePTRkyBD97ne/09y5c+25zJ8/XwMHDtSYMWPUrVs3TZ8+XTfccIMWLVoU6MMGAADNUMA/UPHmm2/WK6+8on/84x+69tpr9cknn+iDDz6wA8r+/fvl8XiUnp5u3ycmJkapqalyu90aMmSI3G63YmNj1a9fP7smPT1doaGhKi0t1X333Se3263bb79dERERdo3T6dSsWbN09OhRxcXFye12Kz8/329+TqfTDlznqqysVGVlpX3b6/VKknw+n3w+30/uTXNX2wN60bDoc3A0xT47wqyLFzWghupFU+x1S0Sfz7iUHgQ8CI0bN05er1ddu3ZVWFiYqqur9fzzz2vYsGGSJI/HI0lKSEjwu19CQoK9zePxKD4+3n+irVqpffv2fjUpKSl19lG7LS4uTh6P54KPc64ZM2Zo6tSpdcbXrVunqKioeh2/CVwuV2NPwQj0OTiaUp8L+jfu4zf0OZRNqdctGX2WTp48We/agAeht956S2+88YaWLVumHj16aPv27Ro1apSSkpKUnZ0d6IcLqPHjx/utIHm9XiUnJysjI0PR0dGNOLOmwefzyeVy6a677lJ4eHhjT6fFos/B0RT73HPK2kZ9/J1TnA2y36bY65aIPp9R+45OfQQ8CI0ZM0bjxo3TkCFDJEm9evXS559/rhkzZig7O1uJiYmSpPLycnXs2NG+X3l5ufr06SNJSkxM1OHDh/32e/r0aR05csS+f2JiosrLy/1qam9frKZ2+7kcDoccDked8fDwcOOfVGejH8FBn4OjKfW5sjqkUR+/ofvQlHrdktHnS3suB/xk6ZMnTyo01H+3YWFhqqmpkSSlpKQoMTFRJSUl9nav16vS0lKlpaVJktLS0lRRUaGysjK7Zv369aqpqVFqaqpds3HjRr/3AV0ul7p06aK4uDi75uzHqa2pfRwAAGC2gAehX/3qV3r++edVVFSkAwcOaOXKlZo7d67uu+8+SVJISIhGjRql5557Tm+//bZ27Nihhx9+WElJScrKypIkdevWTQMHDtSIESO0ZcsWffjhh8rLy9OQIUOUlJQkSXrwwQcVERGhnJwc7dq1S8uXL9f8+fP93tp6+umnVVxcrDlz5mjv3r2aMmWKPvroI+Xl5QX6sAEAQDMU8LfGFi5cqIkTJ+rJJ5/U4cOHlZSUpMcee0yTJk2ya8aOHasTJ05o5MiRqqio0K233qri4mJFRkbaNW+88Yby8vI0YMAAhYaGatCgQVqwYIG9PSYmRuvWrVNubq769u2ryy67TJMmTfL7rKGbb75Zy5Yt04QJE/Tss8/qmmuu0apVq9SzZ89AHzYAAGiGAh6E2rVrp3nz5mnevHk/WBMSEqJp06Zp2rRpP1jTvn17LVu27IKPdd111+nvf//7BWsGDx6swYMHX7AGAACYie8aAwAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwVsAvnwcANE+dxxX53T4wM7ORZgIEDytCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABj8TlCANBIzv3cHgDBx4oQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAY7Vq7AkAAJqmzuOK6owdmJnZCDMBGg4rQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsfhARQAIgvN9OCGAxseKEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGCsBglCX375pf7rv/5LHTp0UOvWrdWrVy999NFH9nbLsjRp0iR17NhRrVu3Vnp6uj777DO/fRw5ckTDhg1TdHS0YmNjlZOTo2+//dav5tNPP9Vtt92myMhIJScnq6CgoM5cVqxYoa5duyoyMlK9evXSmjVrGuKQAQBAMxTwIHT06FHdcsstCg8P17vvvqvdu3drzpw5iouLs2sKCgq0YMECFRYWqrS0VG3atJHT6dSpU6fsmmHDhmnXrl1yuVxavXq1Nm7cqJEjR9rbvV6vMjIy1KlTJ5WVlWn27NmaMmWKXnnlFbtm06ZNGjp0qHJycrRt2zZlZWUpKytLO3fuDPRhAwCAZqhVoHc4a9YsJScna8mSJfZYSkqK/d+WZWnevHmaMGGC7r33XknSX/7yFyUkJGjVqlUaMmSI9uzZo+LiYm3dulX9+vWTJC1cuFB33323/vjHPyopKUlvvPGGqqqq9NprrykiIkI9evTQ9u3bNXfuXDswzZ8/XwMHDtSYMWMkSdOnT5fL5dKiRYtUWFgY6EMHAADNTMCD0Ntvvy2n06nBgwdrw4YNuuKKK/Tkk09qxIgRkqT9+/fL4/EoPT3dvk9MTIxSU1Pldrs1ZMgQud1uxcbG2iFIktLT0xUaGqrS0lLdd999crvduv322xUREWHXOJ1OzZo1S0ePHlVcXJzcbrfy8/P95ud0OrVq1arzzr2yslKVlZX2ba/XK0ny+Xzy+Xw/uTfNXW0P6EXDos/BEew+O8KsoDxOQ/sx/eI5HRz0+YxL6UHAg9C//vUvvfTSS8rPz9ezzz6rrVu36ne/+50iIiKUnZ0tj8cjSUpISPC7X0JCgr3N4/EoPj7ef6KtWql9+/Z+NWevNJ29T4/Ho7i4OHk8ngs+zrlmzJihqVOn1hlft26doqKi6tuCFs/lcjX2FIxAn4MjWH0u6B+Uh2lwP+U8S57TwUGfpZMnT9a7NuBBqKamRv369dMf/vAHSdL111+vnTt3qrCwUNnZ2YF+uIAaP3683wqS1+tVcnKyMjIyFB0d3Ygzaxp8Pp9cLpfuuusuhYeHN/Z0Wiz6HBzB7nPPKWsb/DGCYecU5yXfh+d0cNDnM2rf0amPgAehjh07qnv37n5j3bp10//8z/9IkhITEyVJ5eXl6tixo11TXl6uPn362DWHDx/228fp06d15MgR+/6JiYkqLy/3q6m9fbGa2u3ncjgccjgcdcbDw8ONf1KdjX4EB30OjmD1ubI6pMEfIxh+Sq94TgcHfb6052nArxq75ZZbtG/fPr+xf/zjH+rUqZOk70+cTkxMVElJib3d6/WqtLRUaWlpkqS0tDRVVFSorKzMrlm/fr1qamqUmppq12zcuNHvfUCXy6UuXbrYV6ilpaX5PU5tTe3jAAAAswU8CI0ePVqbN2/WH/7wB/3zn//UsmXL9Morryg3N1eSFBISolGjRum5557T22+/rR07dujhhx9WUlKSsrKyJH2/gjRw4ECNGDFCW7Zs0Ycffqi8vDwNGTJESUlJkqQHH3xQERERysnJ0a5du7R8+XLNnz/f762tp59+WsXFxZozZ4727t2rKVOm6KOPPlJeXl6gDxsAADRDAX9r7MYbb9TKlSs1fvx4TZs2TSkpKZo3b56GDRtm14wdO1YnTpzQyJEjVVFRoVtvvVXFxcWKjIy0a9544w3l5eVpwIABCg0N1aBBg7RgwQJ7e0xMjNatW6fc3Fz17dtXl112mSZNmuT3WUM333yzli1bpgkTJujZZ5/VNddco1WrVqlnz56BPmwAANAMBTwISdI999yje+655we3h4SEaNq0aZo2bdoP1rRv317Lli274ONcd911+vvf/37BmsGDB2vw4MEXnjAAoF46jyuqM3ZgZmYjzAQIDL5rDAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsVo19gQAoCXqPK6osacAoB5YEQIAAMZiRQgA8JOcu/p1YGZmI80EuHSsCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABirVWNPAACau87jihp7CgB+JFaEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACM1eBBaObMmQoJCdGoUaPssVOnTik3N1cdOnRQ27ZtNWjQIJWXl/vd7+DBg8rMzFRUVJTi4+M1ZswYnT592q/m/fff1w033CCHw6Grr75aS5curfP4ixcvVufOnRUZGanU1FRt2bKlIQ4TAAA0Qw0ahLZu3aqXX35Z1113nd/46NGj9c4772jFihXasGGDDh06pPvvv9/eXl1drczMTFVVVWnTpk16/fXXtXTpUk2aNMmu2b9/vzIzM3XnnXdq+/btGjVqlB599FGtXbvWrlm+fLny8/M1efJkffzxx+rdu7ecTqcOHz7ckIcNAACaiQYLQt9++62GDRumP/3pT4qLi7PHjx07pj//+c+aO3eufvGLX6hv375asmSJNm3apM2bN0uS1q1bp927d+u///u/1adPH/3yl7/U9OnTtXjxYlVVVUmSCgsLlZKSojlz5qhbt27Ky8vTr3/9a73wwgv2Y82dO1cjRozQ8OHD1b17dxUWFioqKkqvvfZaQx02AABoRhosCOXm5iozM1Pp6el+42VlZfL5fH7jXbt21VVXXSW32y1Jcrvd6tWrlxISEuwap9Mpr9erXbt22TXn7tvpdNr7qKqqUllZmV9NaGio0tPT7RoAAGC2BvmKjTfffFMff/yxtm7dWmebx+NRRESEYmNj/cYTEhLk8XjsmrNDUO322m0XqvF6vfruu+909OhRVVdXn7dm79695513ZWWlKisr7dter1eS5PP55PP5LnbYLV5tD+hFw6LPwRHIPjvCrJ+8j5bk3J7ynA4O+nzGpfQg4EHoiy++0NNPPy2Xy6XIyMhA775BzZgxQ1OnTq0zvm7dOkVFRTXCjJoml8vV2FMwAn0OjkD0uaB/ACbSgqxZs+a84zyng4M+SydPnqx3bcCDUFlZmQ4fPqwbbrjBHquurtbGjRu1aNEirV27VlVVVaqoqPBbFSovL1diYqIkKTExsc7VXbVXlZ1dc+6VZuXl5YqOjlbr1q0VFhamsLCw89bU7uNc48ePV35+vn3b6/UqOTlZGRkZio6OvsROtDw+n08ul0t33XWXwsPDG3s6LRZ9Do5A9rnnlLUXLzKYI9TS9H41PKcbGK8dZ9S+o1MfAQ9CAwYM0I4dO/zGhg8frq5du+qZZ55RcnKywsPDVVJSokGDBkmS9u3bp4MHDyotLU2SlJaWpueff16HDx9WfHy8pO8TbnR0tLp3727XnPuvDpfLZe8jIiJCffv2VUlJibKysiRJNTU1KikpUV5e3nnn7nA45HA46oyHh4cb/6Q6G/0IDvocHIHoc2V1SIBm07LxnA4O+qxLOv6AB6F27dqpZ8+efmNt2rRRhw4d7PGcnBzl5+erffv2io6O1lNPPaW0tDTddNNNkqSMjAx1795dDz30kAoKCuTxeDRhwgTl5ubaQeXxxx/XokWLNHbsWD3yyCNav3693nrrLRUVFdmPm5+fr+zsbPXr10/9+/fXvHnzdOLECQ0fPjzQhw0AAJqhBjlZ+mJeeOEFhYaGatCgQaqsrJTT6dSLL75obw8LC9Pq1av1xBNPKC0tTW3atFF2dramTZtm16SkpKioqEijR4/W/PnzdeWVV+rVV1+V0+m0ax544AF9/fXXmjRpkjwej/r06aPi4uI6J1ADAAAzBSUIvf/++363IyMjtXjxYi1evPgH79OpU6cfPOGu1h133KFt27ZdsCYvL+8H3woDAABm47vGAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGO1auwJAEBz03lcUWNPAUCAsCIEAACMxYoQACAoek5Zq8rqEEnSgZmZjTwb4HusCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGCsVo09AQBoyjqPK2rsKQBoQKwIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMxecIAQCC7nyfz3RgZmYjzASmY0UIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgBD0IzZszQjTfeqHbt2ik+Pl5ZWVnat2+fX82pU6eUm5urDh06qG3btho0aJDKy8v9ag4ePKjMzExFRUUpPj5eY8aM0enTp/1q3n//fd1www1yOBy6+uqrtXTp0jrzWbx4sTp37qzIyEilpqZqy5YtgT5kAADQTAU8CG3YsEG5ubnavHmzXC6XfD6fMjIydOLECbtm9OjReuedd7RixQpt2LBBhw4d0v33329vr66uVmZmpqqqqrRp0ya9/vrrWrp0qSZNmmTX7N+/X5mZmbrzzju1fft2jRo1So8++qjWrl1r1yxfvlz5+fmaPHmyPv74Y/Xu3VtOp1OHDx8O9GEDAH6izuOK/H6AYGgV6B0WFxf73V66dKni4+NVVlam22+/XceOHdOf//xnLVu2TL/4xS8kSUuWLFG3bt20efNm3XTTTVq3bp12796t//3f/1VCQoL69Omj6dOn65lnntGUKVMUERGhwsJCpaSkaM6cOZKkbt266YMPPtALL7wgp9MpSZo7d65GjBih4cOHS5IKCwtVVFSk1157TePGjQv0oQMAgGYm4EHoXMeOHZMktW/fXpJUVlYmn8+n9PR0u6Zr16666qqr5Ha7ddNNN8ntdqtXr15KSEiwa5xOp5544gnt2rVL119/vdxut98+amtGjRolSaqqqlJZWZnGjx9vbw8NDVV6errcbvd551pZWanKykr7ttfrlST5fD75fL6f0IWWobYH9KJh0efg+KE+95yy1u+2IyxoU2qxHKGW3//WF78Dl4bXjjMupQcNGoRqamo0atQo3XLLLerZs6ckyePxKCIiQrGxsX61CQkJ8ng8ds3ZIah2e+22C9V4vV599913Onr0qKqrq89bs3fv3vPOd8aMGZo6dWqd8XXr1ikqKqqeR93yuVyuxp6CEehzcJzb54L+jTQRA0zvV3NJ9WvWrGmgmbRsvHZIJ0+erHdtgwah3Nxc7dy5Ux988EFDPkzAjB8/Xvn5+fZtr9er5ORkZWRkKDo6uhFn1jT4fD65XC7dddddCg8Pb+zptFj0OTh+qM/nrgjhp3OEWprer0YTPwpVZU1Ive+3c4qzAWfV8vDacUbtOzr10WBBKC8vT6tXr9bGjRt15ZVX2uOJiYmqqqpSRUWF36pQeXm5EhMT7Zpzr+6qvars7JpzrzQrLy9XdHS0WrdurbCwMIWFhZ23pnYf53I4HHI4HHXGw8PDjX9SnY1+BAd9Do5z+1xZXf8/1Lg0lTUhl9Rfnv8/Dq8dl/bcCfhVY5ZlKS8vTytXrtT69euVkpLit71v374KDw9XSUmJPbZv3z4dPHhQaWlpkqS0tDTt2LHD7+oul8ul6Ohode/e3a45ex+1NbX7iIiIUN++ff1qampqVFJSYtcAAACzBXxFKDc3V8uWLdPf/vY3tWvXzj6nJyYmRq1bt1ZMTIxycnKUn5+v9u3bKzo6Wk899ZTS0tJ00003SZIyMjLUvXt3PfTQQyooKJDH49GECROUm5trr9g8/vjjWrRokcaOHatHHnlE69ev11tvvaWiojOXXObn5ys7O1v9+vVT//79NW/ePJ04ccK+igwAAJgt4EHopZdekiTdcccdfuNLlizRb3/7W0nSCy+8oNDQUA0aNEiVlZVyOp168cUX7dqwsDCtXr1aTzzxhNLS0tSmTRtlZ2dr2rRpdk1KSoqKioo0evRozZ8/X1deeaVeffVV+9J5SXrggQf09ddfa9KkSfJ4POrTp4+Ki4vrnEANAADMFPAgZFkXvzwyMjJSixcv1uLFi3+wplOnThe9YuCOO+7Qtm3bLliTl5envLy8i84JAACYh+8aAwAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwVoN/+zwAAD9G53FFdcYOzMxshJmgJWNFCAAAGIsgBAAAjEUQAgAAxiIIAQAAY3GyNACj9ZyyVpXVIY09DQCNhBUhAABgLFaEAADNxrmX1HM5PX4qVoQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZfugoAaLbO/RJWiS9ixaVhRQgAABiLIAQAAIzFW2MAjHH22yiOMEsF/RtxMgCaBFaEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMxeXzAIAW5dxPm+aTpnEhBCEAQIvG13DgQghCAFqk8/3xA4BzcY4QAAAwFkEIAAAYiyAEAACMRRACAADG4mRpAIBxuMQetVgRAgAAxmJFCABgPD5ryFwEIQAtAp8bBODH4K0xAABgLIIQAAAwFkEIAAAYiyAEAACMxcnSAJodToxGMPBZQ2ZgRQgAABiLIAQAAIzFW2MAmjzeCgPQUAhCAADUA58+3TIRhAA0Kaz+AAgmghAAAD9SfYI7q0ZNGydLAwAAY7EiBKBR8VYYgMZEEAIQNIQemIgPZmzaCEIAGgzBB6iLq8+aFiOC0OLFizV79mx5PB717t1bCxcuVP/+/Rt7WkCLQugBfjxWjRpPiw9Cy5cvV35+vgoLC5Wamqp58+bJ6XRq3759io+Pb+zpAc0CIQcIrh/zO+cIs1TQX+o5Za0qq0N+sI6Q5a/FB6G5c+dqxIgRGj58uCSpsLBQRUVFeu211zRu3LhGnh0QfIQawGw/5jWgJYenFh2EqqqqVFZWpvHjx9tjoaGhSk9Pl9vtrlNfWVmpyspK+/axY8ckSUeOHJHP52v4CTdxPp9PJ0+e1DfffKPw8PDGnk6TlDqjpM5Y6fgBl3Q/R6ilCdfXqM///X+qrPnhf9X9WC36l/4StKqxdPJkjVr5QlXdAH3GGfQ6OBqyz1f/n7cCur+z1ec18lIdP35ckmRZ1kVrW/Rr4n/+8x9VV1crISHBbzwhIUF79+6tUz9jxgxNnTq1znhKSkqDzREt32VzLv0+DwZ+GjgP+hw89Do4mmOff8xrZH0dP35cMTExF6xp0UHoUo0fP175+fn27ZqaGh05ckQdOnRQSAj/ivF6vUpOTtYXX3yh6Ojoxp5Oi0Wfg4M+Bw+9Dg76fIZlWTp+/LiSkpIuWtuig9Bll12msLAwlZeX+42Xl5crMTGxTr3D4ZDD4fAbi42NbcgpNkvR0dHG/5IFA30ODvocPPQ6OOjz9y62ElSrRX/FRkREhPr27auSkjPnX9TU1KikpERpaWmNODMAANAUtOgVIUnKz89Xdna2+vXrp/79+2vevHk6ceKEfRUZAAAwV4sPQg888IC+/vprTZo0SR6PR3369FFxcXGdE6hxcQ6HQ5MnT67z9iECiz4HB30OHnodHPT5xwmx6nNtGQAAQAvUos8RAgAAuBCCEAAAMBZBCAAAGIsgBAAAjEUQgp8DBw4oJydHKSkpat26tX7+859r8uTJqqqq8qv79NNPddtttykyMlLJyckqKCios68VK1aoa9euioyMVK9evbRmzZpgHUaz8fzzz+vmm29WVFTUD35458GDB5WZmamoqCjFx8drzJgxOn36tF/N+++/rxtuuEEOh0NXX321li5d2vCTb+YWL16szp07KzIyUqmpqdqyZUtjT6lZ2bhxo371q18pKSlJISEhWrVqld92y7I0adIkdezYUa1bt1Z6ero+++wzv5ojR45o2LBhio6OVmxsrHJycvTtt98G8SiavhkzZujGG29Uu3btFB8fr6ysLO3bt8+v5tSpU8rNzVWHDh3Utm1bDRo0qM4HCdfndcRUBCH42bt3r2pqavTyyy9r165deuGFF1RYWKhnn33WrvF6vcrIyFCnTp1UVlam2bNna8qUKXrllVfsmk2bNmno0KHKycnRtm3blJWVpaysLO3cubMxDqvJqqqq0uDBg/XEE0+cd3t1dbUyMzNVVVWlTZs26fXXX9fSpUs1adIku2b//v3KzMzUnXfeqe3bt2vUqFF69NFHtXbt2mAdRrOzfPly5efna/Lkyfr444/Vu3dvOZ1OHT58uLGn1mycOHFCvXv31uLFi8+7vaCgQAsWLFBhYaFKS0vVpk0bOZ1OnTp1yq4ZNmyYdu3aJZfLpdWrV2vjxo0aOXJksA6hWdiwYYNyc3O1efNmuVwu+Xw+ZWRk6MSJE3bN6NGj9c4772jFihXasGGDDh06pPvvv9/eXp/XEaNZwEUUFBRYKSkp9u0XX3zRiouLsyorK+2xZ555xurSpYt9+ze/+Y2VmZnpt5/U1FTrsccea/gJN0NLliyxYmJi6oyvWbPGCg0NtTwejz320ksvWdHR0Xb/x44da/Xo0cPvfg888IDldDobdM7NWf/+/a3c3Fz7dnV1tZWUlGTNmDGjEWfVfEmyVq5cad+uqamxEhMTrdmzZ9tjFRUVlsPhsP76179almVZu3fvtiRZW7dutWveffddKyQkxPryyy+DNvfm5vDhw5Yka8OGDZZlfd/X8PBwa8WKFXbNnj17LEmW2+22LKt+ryMmY0UIF3Xs2DG1b9/evu12u3X77bcrIiLCHnM6ndq3b5+OHj1q16Snp/vtx+l0yu12B2fSLYTb7VavXr38PgDU6XTK6/Vq165ddg29rr+qqiqVlZX59Sw0NFTp6en0LED2798vj8fj1+OYmBilpqbaPXa73YqNjVW/fv3smvT0dIWGhqq0tDToc24ujh07Jkn2a3JZWZl8Pp9fr7t27aqrrrrKr9cXex0xGUEIF/TPf/5TCxcu1GOPPWaPeTyeOp/MXXvb4/FcsKZ2O+rnp/Ta6/Xqu+++C85Em5H//Oc/qq6u5vnZgGr7eKEeezwexcfH+21v1aqV2rdvz/8PP6CmpkajRo3SLbfcop49e0r6vo8RERF1zjE8t9cXex0xGUHIEOPGjVNISMgFf/bu3et3ny+//FIDBw7U4MGDNWLEiEaaefPzY3oNABeTm5urnTt36s0332zsqbQoLf67xvC93//+9/rtb397wZqf/exn9n8fOnRId955p26++Wa/k6AlKTExsc4VCbW3ExMTL1hTu70lu9ReX0hiYmKdq5nq2+vo6Gi1bt26nrM2x2WXXaawsDBjn5/BUNvH8vJydezY0R4vLy9Xnz597JpzT04/ffq0jhw5wv8P55GXl2efUH7llVfa44mJiaqqqlJFRYXfqtDZz+f6vI6YjBUhQ1x++eXq2rXrBX9qz/n58ssvdccdd6hv375asmSJQkP9nyZpaWnauHGjfD6fPeZyudSlSxfFxcXZNSUlJX73c7lcSktLa+AjbXyX0uuLSUtL044dO/z+YLhcLkVHR6t79+52jam9/jEiIiLUt29fv57V1NSopKSEngVISkqKEhMT/Xrs9XpVWlpq9zgtLU0VFRUqKyuza9avX6+amhqlpqYGfc5NlWVZysvL08qVK7V+/XqlpKT4be/bt6/Cw8P9er1v3z4dPHjQr9cXex0xWmOfrY2m5d///rd19dVXWwMGDLD+/e9/W1999ZX9U6uiosJKSEiwHnroIWvnzp3Wm2++aUVFRVkvv/yyXfPhhx9arVq1sv74xz9ae/bssSZPnmyFh4dbO3bsaIzDarI+//xza9u2bdbUqVOttm3bWtu2bbO2bdtmHT9+3LIsyzp9+rTVs2dPKyMjw9q+fbtVXFxsXX755db48ePtffzrX/+yoqKirDFjxlh79uyxFi9ebIWFhVnFxcWNdVhN3ptvvmk5HA5r6dKl1u7du62RI0dasbGxflfV4MKOHz9uP18lWXPnzrW2bdtmff7555ZlWdbMmTOt2NhY629/+5v16aefWvfee6+VkpJifffdd/Y+Bg4caF1//fVWaWmp9cEHH1jXXHONNXTo0MY6pCbpiSeesGJiYqz333/f7/X45MmTds3jjz9uXXXVVdb69eutjz76yEpLS7PS0tLs7fV5HTEZQQh+lixZYkk678/ZPvnkE+vWW2+1HA6HdcUVV1gzZ86ss6+33nrLuvbaa62IiAirR48eVlFRUbAOo9nIzs4+b6/fe+89u+bAgQPWL3/5S6t169bWZZddZv3+97+3fD6f337ee+89q0+fPlZERIT1s5/9zFqyZElwD6QZWrhwoXXVVVdZERERVv/+/a3Nmzc39pSalffee++8z93s7GzLsr6/hH7ixIlWQkKC5XA4rAEDBlj79u3z28c333xjDR061Grbtq0VHR1tDR8+3P5HAL73Q6/HZ/+Of/fdd9aTTz5pxcXFWVFRUdZ9993n949Xy6rf64ipQizLsoK4AAUAANBkcI4QAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMb6/4r6DpsrfxqKAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "daytype_df2[(daytype_df2.pct_tu_predictions_early >= 0.5)].avg_prediction_error_sec.hist(bins=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "db0b4421-3ddf-4384-ba06-a00348929c3b", + "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", + "
pct_tu_accurate_minutespct_tu_predictions_ontime
count1.727213e+061.727213e+06
mean7.699415e-013.796528e-02
std1.205612e-019.267598e-02
min0.000000e+000.000000e+00
1%3.500000e-010.000000e+00
5%5.300000e-010.000000e+00
10%6.300000e-011.000000e-02
25%7.300000e-011.000000e-02
50%7.900000e-011.000000e-02
75%8.500000e-012.000000e-02
90%8.900000e-016.000000e-02
95%9.100000e-011.900000e-01
99%9.700000e-014.200000e-01
max1.000000e+001.000000e+00
\n", + "
" + ], + "text/plain": [ + " pct_tu_accurate_minutes pct_tu_predictions_ontime\n", + "count 1.727213e+06 1.727213e+06\n", + "mean 7.699415e-01 3.796528e-02\n", + "std 1.205612e-01 9.267598e-02\n", + "min 0.000000e+00 0.000000e+00\n", + "1% 3.500000e-01 0.000000e+00\n", + "5% 5.300000e-01 0.000000e+00\n", + "10% 6.300000e-01 1.000000e-02\n", + "25% 7.300000e-01 1.000000e-02\n", + "50% 7.900000e-01 1.000000e-02\n", + "75% 8.500000e-01 2.000000e-02\n", + "90% 8.900000e-01 6.000000e-02\n", + "95% 9.100000e-01 1.900000e-01\n", + "99% 9.700000e-01 4.200000e-01\n", + "max 1.000000e+00 1.000000e+00" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daytype_df2[prep_data.ACCURACY_COLS].describe(\n", + " percentiles=prep_data.PERCENTILE_LIST)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e2cc60fc-e112-4404-87f8-97375dd3071d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/rt_predictions/08_stop_pct_accuracy.ipynb b/rt_predictions/08_stop_pct_accuracy.ipynb new file mode 100644 index 000000000..3d1439dcd --- /dev/null +++ b/rt_predictions/08_stop_pct_accuracy.ipynb @@ -0,0 +1,815 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f964898b-d6a5-45ae-abf7-4b0f0d0b867a", + "metadata": {}, + "source": [ + "# pct_accuracy vs n_predictions_early/ontime/late\n", + "\n", + "1. Make sure that `early/on_time/late` metrics make sense with `pct_accuracy`\n", + "1. Deeper dive into the \"accuracy\" exponential curve. See if we can use this as \"expected wait time\" metric." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c922ce70-f94e-4727-83d5-a8ed2556140c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import altair as alt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "import prep_data\n", + "from rt_msa_utils import PREDICTIONS_GCS, RT_MSA_DICT\n", + "\n", + "alt.data_transformers.enable(\"vegafusion\")\n", + "\n", + "DOWNLOAD_DICT = RT_MSA_DICT.rt_trip_updates_downloads" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9d71bf26-7824-4e08-b391-b89591923c80", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "key object\n", + "stop_key object\n", + "base64_url object\n", + "service_date datetime64[ns]\n", + "stop_id object\n", + "schedule_feed_key object\n", + "avg_prediction_error_sec float64\n", + "n_tu_accurate_minutes Int64\n", + "n_tu_complete_minutes Int64\n", + "n_tu_minutes_available Int64\n", + "avg_prediction_spread_minutes float64\n", + "n_predictions Int64\n", + "n_predictions_early Int64\n", + "n_predictions_ontime Int64\n", + "n_predictions_late Int64\n", + "n_tu_trips Int64\n", + "pct_tu_predictions_early Float64\n", + "pct_tu_predictions_ontime Float64\n", + "pct_tu_predictions_late Float64\n", + "pct_tu_accurate_minutes Float64\n", + "pct_tu_predictions_early_ontime float64\n", + "dtype: object" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "FILE = RT_MSA_DICT.rt_trip_updates_downloads.daily_stop_grain\n", + "\n", + "def group_early_ontime(df: pd.DataFrame):\n", + " # Newmark does group early/ontime together for \"not miss bus\" group\n", + " df = df.assign(\n", + " pct_tu_predictions_early_ontime = df[\n", + " [\"pct_tu_predictions_early\", \"pct_tu_predictions_ontime\"]\n", + " ].sum(axis=1)\n", + " )\n", + " \n", + " return df\n", + "\n", + "\n", + "daily_df = pd.read_parquet(\n", + " f\"{PREDICTIONS_GCS}{FILE}.parquet\"\n", + ").pipe(\n", + " prep_data.calculate_percents\n", + ").pipe(\n", + " prep_data.drop_outliers,\n", + " prep_data.MIN_ERROR_SEC, \n", + " prep_data.MAX_ERROR_SEC\n", + ").pipe(group_early_ontime)\n", + "\n", + "daily_df.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f9d63900-f8ce-48b1-b562-bf9ca6186d50", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def accuracy_bounds(minutes_to_prediction: float) -> tuple[float]:\n", + " \"\"\"\n", + " Based on minutes until arrival, how many seconds difference\n", + " can actual_arrival and predicted_arrival differ.\n", + " \"\"\"\n", + " lower_bound_sec = -60 * np.log(minutes_to_prediction+1.3) \n", + " upper_bound_sec = 60* np.log(minutes_to_prediction+1.5)\n", + " \n", + " lower_bound_min = lower_bound_sec / 60\n", + " upper_bound_min = upper_bound_sec / 60\n", + " \n", + " return round(lower_bound_min, 2), round(upper_bound_min, 2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6c7fa433-15e2-4f51-bee8-cd7adf16ed55", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Minutes to Arrival: 0\n", + "(-0.26, 0.41)\n", + "Minutes to Arrival: 1\n", + "(-0.83, 0.92)\n", + "Minutes to Arrival: 2\n", + "(-1.19, 1.25)\n", + "Minutes to Arrival: 3\n", + "(-1.46, 1.5)\n", + "Minutes to Arrival: 4\n", + "(-1.67, 1.7)\n", + "Minutes to Arrival: 5\n", + "(-1.84, 1.87)\n", + "Minutes to Arrival: 10\n", + "(-2.42, 2.44)\n", + "Minutes to Arrival: 15\n", + "(-2.79, 2.8)\n", + "Minutes to Arrival: 20\n", + "(-3.06, 3.07)\n", + "Minutes to Arrival: 25\n", + "(-3.27, 3.28)\n", + "Minutes to Arrival: 30\n", + "(-3.44, 3.45)\n" + ] + } + ], + "source": [ + "for m in [0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30]:\n", + " print(f\"Minutes to Arrival: {m}\")\n", + " print(accuracy_bounds(m))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4ec14fc2-db36-4d95-9ab5-87d44aa57d2f", + "metadata": {}, + "outputs": [], + "source": [ + "def categorize_prediction_error(prediction_error: float) -> str:\n", + " # early (positive values) mean prediction is earlier than actual arrival\n", + " # bus comes after prediction (which means you will catch bus)\n", + " VERY_EARLY_UPPER = 10*60\n", + " EARLY_UPPER = 5*60\n", + " LITTLE_EARLY_UPPER = 1*60\n", + " LITTLE_LATE_UPPER = -1*60\n", + " LATE_UPPER = -5*60\n", + " VERY_LATE_UPPER = -10*60\n", + " \n", + " if prediction_error > VERY_EARLY_UPPER:\n", + " return \"very_early\"\n", + " elif (prediction_error <= VERY_EARLY_UPPER) and (prediction_error >= EARLY_UPPER):\n", + " return \"early\"\n", + " elif (prediction_error <= EARLY_UPPER) and (prediction_error >= LITTLE_EARLY_UPPER):\n", + " return \"little_early\"\n", + " elif (prediction_error <= LITTLE_EARLY_UPPER) and (prediction_error >= LITTLE_LATE_UPPER):\n", + " return \"ontime\"\n", + " elif (prediction_error <= LITTLE_LATE_UPPER) and (prediction_error >= LATE_UPPER):\n", + " return \"little_late\"\n", + " elif (prediction_error <= LATE_UPPER) and (prediction_error >= VERY_LATE_UPPER):\n", + " return \"little_late\"\n", + " elif (prediction_error < VERY_LATE_UPPER):\n", + " return \"very_late\"\n", + " else:\n", + " return \"unknown\"\n", + "\n", + "daily_df = daily_df.assign(\n", + " prediction_error_category = daily_df.apply(\n", + " lambda x: categorize_prediction_error(x.avg_prediction_error_sec), axis=1)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3002b276-e3e5-407a-94dd-c75a01797f59", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ontime 460518\n", + "little_early 423497\n", + "little_late 30544\n", + "Name: prediction_error_category, dtype: int64" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df.prediction_error_category.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "a417d932-6639-4458-98bd-c7f4215094cd", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ontime 0.503541\n", + "little_early 0.463061\n", + "little_late 0.033398\n", + "Name: prediction_error_category, dtype: float64" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df.prediction_error_category.value_counts(normalize=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d5249a9e-d42a-4549-a50a-3daf86dd20d8", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
keystop_keybase64_urlservice_datestop_idschedule_feed_keyavg_prediction_error_secn_tu_accurate_minutesn_tu_complete_minutesn_tu_minutes_available...n_predictions_earlyn_predictions_ontimen_predictions_laten_tu_tripspct_tu_predictions_earlypct_tu_predictions_ontimepct_tu_predictions_latepct_tu_accurate_minutespct_tu_predictions_early_ontimeprediction_error_category
05fd1b1a829400b57519951e7e54096433b95038c8989c9dcd4871c11fb7081beaHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG...2025-06-0873738d9623a1823a27925b7e2f00e44fc5bb39.183454711391239234...170703159951900.620.010.360.770.63ontime
1eb6c24f24772649fe54ae88566015a8dfff2473a01ee0e1f7f3913e16bba795faHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG...2025-06-0812228d9623a1823a27925b7e2f00e44fc5bb48.85152591921019110302...2130354687091060.70.020.280.890.72ontime
2e763549740cb2e9dcd92e223cded777c4ed1b3a7ad8900a527682cf50cd17862aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG...2025-06-08119098d9623a1823a27925b7e2f00e44fc5bb58.596248663378127935...168934056153850.720.020.260.840.74ontime
33250d0d32752750f0c689e96fa3fed8ca0fb4a11017f532098331c399fd31ca0aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG...2025-06-081761708d9623a1823a27925b7e2f00e44fc5bb60.681358468959616048...124204115049630.690.020.280.780.71little_early
4321d084fe34caf6494c5853b3edfe83720de800adb403d08b883ff758ad00abfaHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG...2025-06-0863728d9623a1823a27925b7e2f00e44fc5bb61.335705286531233159...72931201947330.780.010.210.910.79little_early
..................................................................
91455404e2b18da6d6c95c32c99aedfa47021453394a01951ad335893e06a1e9991654aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG...2025-06-135777680b17fbe1735c5f7c348eda4fb45b99a60.053590106591323013368...27147177123091360.680.00.310.80.68little_early
91455508b8fa793a58da149152da63126706a19dd642a1d82e6702aec1f789aeccbde9aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG...2025-06-138374580b17fbe1735c5f7c348eda4fb45b99a79.29147394681323013416...28023135116041360.70.00.290.710.70little_early
9145561ff00e9ade83e1bbd7403872ece6a21eadbf64adc0d0af82d94a67a78a0eab74aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG...2025-06-135227180b17fbe1735c5f7c348eda4fb45b99a93.003835106651359013746...3285326176441400.810.010.190.780.82little_early
914557d6e1160ae86140b1cbb6a3de3ea288eeffd7ba875d6c61a8f7b55755fd752311aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG...2025-06-136195780b17fbe1735c5f7c348eda4fb45b99a36.92619367861393514130...14415324100591440.340.010.240.480.35ontime
9145586c5d2004f4e703c0b33e3544a628592de42f71ce37e5350d0920167ab248f522aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG...2025-06-135577780b17fbe1735c5f7c348eda4fb45b99a56.467242114991488915081...30264462139441550.680.010.310.760.69ontime
\n", + "

914559 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " key stop_key \\\n", + "0 5fd1b1a829400b57519951e7e5409643 3b95038c8989c9dcd4871c11fb7081be \n", + "1 eb6c24f24772649fe54ae88566015a8d fff2473a01ee0e1f7f3913e16bba795f \n", + "2 e763549740cb2e9dcd92e223cded777c 4ed1b3a7ad8900a527682cf50cd17862 \n", + "3 3250d0d32752750f0c689e96fa3fed8c a0fb4a11017f532098331c399fd31ca0 \n", + "4 321d084fe34caf6494c5853b3edfe837 20de800adb403d08b883ff758ad00abf \n", + "... ... ... \n", + "914554 04e2b18da6d6c95c32c99aedfa470214 53394a01951ad335893e06a1e9991654 \n", + "914555 08b8fa793a58da149152da63126706a1 9dd642a1d82e6702aec1f789aeccbde9 \n", + "914556 1ff00e9ade83e1bbd7403872ece6a21e adbf64adc0d0af82d94a67a78a0eab74 \n", + "914557 d6e1160ae86140b1cbb6a3de3ea288ee ffd7ba875d6c61a8f7b55755fd752311 \n", + "914558 6c5d2004f4e703c0b33e3544a628592d e42f71ce37e5350d0920167ab248f522 \n", + "\n", + " base64_url service_date \\\n", + "0 aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG... 2025-06-08 \n", + "1 aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG... 2025-06-08 \n", + "2 aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG... 2025-06-08 \n", + "3 aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG... 2025-06-08 \n", + "4 aHR0cHM6Ly9hcGkuZ29zd2lmdC5seS9yZWFsLXRpbWUvbG... 2025-06-08 \n", + "... ... ... \n", + "914554 aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG... 2025-06-13 \n", + "914555 aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG... 2025-06-13 \n", + "914556 aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG... 2025-06-13 \n", + "914557 aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG... 2025-06-13 \n", + "914558 aHR0cHM6Ly9hcGkuNTExLm9yZy90cmFuc2l0L3RyaXB1cG... 2025-06-13 \n", + "\n", + " stop_id schedule_feed_key avg_prediction_error_sec \\\n", + "0 7373 8d9623a1823a27925b7e2f00e44fc5bb 39.183454 \n", + "1 1222 8d9623a1823a27925b7e2f00e44fc5bb 48.851525 \n", + "2 11909 8d9623a1823a27925b7e2f00e44fc5bb 58.596248 \n", + "3 176170 8d9623a1823a27925b7e2f00e44fc5bb 60.681358 \n", + "4 6372 8d9623a1823a27925b7e2f00e44fc5bb 61.335705 \n", + "... ... ... ... \n", + "914554 57776 80b17fbe1735c5f7c348eda4fb45b99a 60.053590 \n", + "914555 83745 80b17fbe1735c5f7c348eda4fb45b99a 79.291473 \n", + "914556 52271 80b17fbe1735c5f7c348eda4fb45b99a 93.003835 \n", + "914557 61957 80b17fbe1735c5f7c348eda4fb45b99a 36.926193 \n", + "914558 55777 80b17fbe1735c5f7c348eda4fb45b99a 56.467242 \n", + "\n", + " n_tu_accurate_minutes n_tu_complete_minutes n_tu_minutes_available \\\n", + "0 7113 9123 9234 \n", + "1 9192 10191 10302 \n", + "2 6633 7812 7935 \n", + "3 4689 5961 6048 \n", + "4 2865 3123 3159 \n", + "... ... ... ... \n", + "914554 10659 13230 13368 \n", + "914555 9468 13230 13416 \n", + "914556 10665 13590 13746 \n", + "914557 6786 13935 14130 \n", + "914558 11499 14889 15081 \n", + "\n", + " ... n_predictions_early n_predictions_ontime n_predictions_late \\\n", + "0 ... 17070 315 9951 \n", + "1 ... 21303 546 8709 \n", + "2 ... 16893 405 6153 \n", + "3 ... 12420 411 5049 \n", + "4 ... 7293 120 1947 \n", + "... ... ... ... ... \n", + "914554 ... 27147 177 12309 \n", + "914555 ... 28023 135 11604 \n", + "914556 ... 32853 261 7644 \n", + "914557 ... 14415 324 10059 \n", + "914558 ... 30264 462 13944 \n", + "\n", + " n_tu_trips pct_tu_predictions_early pct_tu_predictions_ontime \\\n", + "0 90 0.62 0.01 \n", + "1 106 0.7 0.02 \n", + "2 85 0.72 0.02 \n", + "3 63 0.69 0.02 \n", + "4 33 0.78 0.01 \n", + "... ... ... ... \n", + "914554 136 0.68 0.0 \n", + "914555 136 0.7 0.0 \n", + "914556 140 0.81 0.01 \n", + "914557 144 0.34 0.01 \n", + "914558 155 0.68 0.01 \n", + "\n", + " pct_tu_predictions_late pct_tu_accurate_minutes \\\n", + "0 0.36 0.77 \n", + "1 0.28 0.89 \n", + "2 0.26 0.84 \n", + "3 0.28 0.78 \n", + "4 0.21 0.91 \n", + "... ... ... \n", + "914554 0.31 0.8 \n", + "914555 0.29 0.71 \n", + "914556 0.19 0.78 \n", + "914557 0.24 0.48 \n", + "914558 0.31 0.76 \n", + "\n", + " pct_tu_predictions_early_ontime prediction_error_category \n", + "0 0.63 ontime \n", + "1 0.72 ontime \n", + "2 0.74 ontime \n", + "3 0.71 little_early \n", + "4 0.79 little_early \n", + "... ... ... \n", + "914554 0.68 little_early \n", + "914555 0.70 little_early \n", + "914556 0.82 little_early \n", + "914557 0.35 ontime \n", + "914558 0.69 ontime \n", + "\n", + "[914559 rows x 22 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daily_df" + ] + }, + { + "cell_type": "markdown", + "id": "7a9bd3b6-4985-4a27-b73f-fc0d8b3ee417", + "metadata": {}, + "source": [ + "Let's align closely to Swiftly contract language for calculations.\n", + "\n", + "Scatterplot leading up to window of arrival." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "df1d04d8-edd5-422d-bb26-230f01db0558", + "metadata": {}, + "outputs": [], + "source": [ + "FILE = RT_MSA_DICT.rt_schedule_models.weekday_stop_grain\n", + "\n", + "daytype_df = pd.read_parquet(\n", + " f\"{PREDICTIONS_GCS}{FILE}.parquet\", \n", + " columns = [\"name\", \"year\", \"month\", \"day_type\", \"stop_id\", \"avg_prediction_error_sec\"]\n", + ").pipe(\n", + " prep_data.drop_outliers,\n", + " prep_data.MIN_ERROR_SEC, \n", + " prep_data.MAX_ERROR_SEC\n", + ")\n", + "\n", + "daytype_df = daytype_df.assign(\n", + " prediction_error_category = daytype_df.apply(\n", + " lambda x: categorize_prediction_error(x.avg_prediction_error_sec), axis=1)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f48328ea-0584-4242-b6ec-3e6f53ad996e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ontime 925778\n", + "little_early 753024\n", + "little_late 48411\n", + "Name: prediction_error_category, dtype: int64" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daytype_df.prediction_error_category.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "41bb7338-eb4b-4a04-a044-ce116af785cd", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ontime 0.535995\n", + "little_early 0.435976\n", + "little_late 0.028028\n", + "Name: prediction_error_category, dtype: float64" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daytype_df.prediction_error_category.value_counts(normalize=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c186dce5-6522-4506-a041-773f5649674e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/rt_predictions/Makefile b/rt_predictions/Makefile index 9b4ea554f..a0e05a375 100644 --- a/rt_predictions/Makefile +++ b/rt_predictions/Makefile @@ -3,4 +3,17 @@ stop_times_poc_cleaned_data: cd ../rt_segment_speed_utils/ && pip install -r requirements.txt && cd .. #query_materialized_tables.py --save outputs in GCS python more_cleaning.py - #python schedule_stop_times_with_geom.py -- do this for easier mapping \ No newline at end of file + #python schedule_stop_times_with_geom.py -- do this for easier mapping + + +rt_msa_stop_report: + python download_warehouse_tables.py + # things that should be done before report is run, but probably can't make it into dbt model + # save it out as parquet + python prep_data.py + python deploy_portfolio_yaml.py rt_msa_stops + cd ../portfolio/ && pip install -r requirements.txt && cd ../ + python portfolio/portfolio.py build rt_trip_updates_stop_metrics + gcloud auth login --login-config=iac/login.json && gcloud config set project cal-itp-data-infra # will need to authenticate this step + python portfolio/portfolio.py build rt_trip_updates_stop_metrics --no-execute-papermill --deploy + python portfolio/portfolio.py index --deploy \ No newline at end of file diff --git a/rt_predictions/README.md b/rt_predictions/README.md index 71653d77f..10e4e7c42 100644 --- a/rt_predictions/README.md +++ b/rt_predictions/README.md @@ -1,7 +1,92 @@ # README +One of the most common transit user behaviors is to consult an app (Google Maps, Apple Maps, NextBus, etc) to find out when the bus or train is going to arrive. + +That widely desired piece of information is powered by GTFS Real-Time Trip Updates, specifically the [Stop Time Updates](https://gtfs.org/documentation/realtime/reference/#message-stoptimeupdate) specification. + GTFS Real Time trip updates performance metrics, specifically the stop time update messages. Accurate and reliable information should be provided to transit users for journey planning. These performance metrics provide insights into: + * availability and completeness of RT - is there information available for users? * prediction inconsistency - how much are predictions changing from minute to minute as the bus approaches time of arrival? * prediction reliability and accuracy - are these predictions accurate (when compared to our estimated actual time of arrival)? + + +## Reliable Prediction Accuracy + +The prediction is considered **accurate** if it falls within the bounds of this equation: `-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time to Prediction+1.5)`. + +As the bus approaches each stop, the software is making predictions for when the bus should arrive. When the bus is 30 min away from arrival, there is a more generous buffer for accuracy; this buffer tightens as the bus is nearing the stop. + +| Minutes Until Bus Arives | Accurate Within Bounds | +|--------------------------|---------------------------------| +| 0 min | -0.26 min early - 0.41 min late | +| 10 min | -2.42 min early - 2.44 min late | +| 30 min | -3.44 min early - 3.45 min late | + +* Positive values = arrival came **after** the prediction. + * actual_arrival = 8:05 am + * predicted arrival = 8:00 am + * actual_arrival - predicted_arrival = +5 seconds + * follow the prediction, you will catch the bus +* Negative values = arrival came **before** the prediction. + * actual_arrival = 8:05 am + * predicted arrival = 8:10 am + * actual_arrival - predicted_arrival = -5 seconds + * follow the prediction, you will **miss** the bus...this is very bad! + * we want fewer of these kinds of predictions, and would much rather wait for the bus than to miss it + +## Availability and Completeness of Predictions + +* This metric is the easiest to achieve. For starters, having information is better than no information. +* For each instance of scheduled stop arrival, there is complete information if there are at least 2 predictions each minute. +* For the 30 minute period before the bus arrives at each stop, each minute is an observation that goes into this calculation (up to 30 observations). +* This ensures that we have fairly equal number of observations for each stop and can compare across stops. + * We want to avoid having 30 minutes of predictions for the 1st stop and 60 minutes of predictions for the last stop and comparing metrics that have different denominators. + +## Prediction Inconsistency + +* This metric (also called jitter or wobble) captures another aspect of transit user experience. Any change in prediction is counted, so this metric **only has positive values**, but smaller positive values are better. + * If the prediction is changing from minute to minute, a large spread would show up. + * If the prediction is fairly consistent, we would see small spread. +* There is [research](https://www.sciencedirect.com/science/article/abs/pii/S0965856416303494) around how transit users perceive wait time, and that users perceive longer wait times than what is actually experienced. Decreasing the perceived wait time by providing real-time information has positive benefits for user experience. + +## Master Services Agreement +Exhibit H definitions (pg 53 on pdf) + +| **Item** | **Report Metric** | **Definition** | **Implementation Notes** | +|---|---|---|---| +| 3. Availability of
Acceptable StopTimeUpdate
Messages | pct_tu_complete_minutes,
n_tu_complete_minutes,
n_tu_minutes_available | Percent of time riders have up-to-date prediction information available, calculated as the percent of one-minute time bins for a given trip and stop during a Trip Time Span where there are two (2) or greater GTFS-RT StopTimeUpdate arrival predictions per minute. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 9. Experienced Wait
Time Delay | prediction_error_label,
avg_prediction_error_minutes | The amount of time a transit rider perceives they have waited after seeing the real-time information in their Journey Planning Application and the arrival of the next vehicle arrives at their stop. This is calculated as the time interval between the next trip to arrive at a stop for a given route_id/shape_id/stop_id combination and the next predicted arrival time from a StopTimeUpdate message for that route_id/shape_id/stop_id combination as sampled for each minute of the day that the route_id/shape_id/stop_id combination is in service. | Use a simpler derived version with average
prediction error.
Current aggregation does not support
route aggregation yet. | +| 23. Measurement Time Windows | | A series of 30 consecutive time windows, each starting one (1) minute apart and lasting two (2) minutes. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 27. Prediction Error | avg_prediction_error_minutes | Actual Trip Stop Arrival Time minus the Predicted Trip Stop Arrival Time in seconds. Note that while Prediction Error is not the final metric in this case, it is useful to retain this value into the future and in archival storage in the event that
the definition of the frontier defined in Reliable Accuracy is changed in the future based on a specific agency’s needs | | +| 28. Prediction
Inconsistency | avg_prediction_spread_minutes | How much the prediction changes in the last thirty (30) minutes before a vehicle arrives at a stop, calculated for a given trip and stop as the average Predicted Trip Stop Arrival Spread of all Measurement Time Windows where a given window has a StopTimeUpdate message for the trip and stop with a timestamp in that window. | | +| 29. Prediction Reliability | pct_tu_accurate_minutes,
n_tu_accurate_minutes,
n_tu_minutes_available,
pct_tu_predictions_early/ontime/late,
n_predictions,
n_predictions_early/ontime/late | The percent of time transit riders are looking at a reliably good prediction – understanding that the closer a vehicle is
to a stop, the better the prediction should be, calculated as the percent of minutes for each stop for each trip where predictions have Reliable Accuracy, starting sixty (60) minutes before the first scheduled stop for the trip. | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | +| 32. Reliable Accuracy | pct_tu_accurate_minutes,
n_tu_accurate_minutes,
n_tu_minutes_available,
pct_tu_predictions_early/ontime/late,
n_predictions,
n_predictions_early/ontime/late | A prediction has reliable accuracy if:
-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time
to Prediction+1.5). | | +| 39. Time to Prediction | | The current time until the Predicted Trip Stop Arrival Time in minutes | | +| 43. Trip Start Time | | Time of the first scheduled stop arrival of the trip per the GTFS Schedule for trips with ScheduleRelationship =
SCHEDULED or CANCELED or the first predicted arrival time for other ScheduleRelationship values. | | +| 44. Trip Time Span | | Time in minutes from the Trip Start Time to the arrival time
at the stop being measured | Each minute for the 30 minute period
before **each** stop's
arrival for equal comparison across stops | + +## References +* Caltrans GTFS RT Master Service Agreement Contract + * Swiftly provides a prediction accuracy exponential equation +* Professor Gregory Newmark's paper: [Assessing GTFS Accuracy](https://transweb.sjsu.edu/sites/default/files/2017-Newmark-Public-Transit-Statistical-Analysis.pdf) + * This project is a work in progress for productionizing and implementing all the ideas presented in this paper. + * This paper provides the basis of policy and planning interpretations around the various metrics. + * We replicate as many of the visualizations and tables as possible. +* Yingling Fan, Andrew Guthrie, David Levinson's paper on [Waiting time perceptions at transit stops and stations](https://www.sciencedirect.com/science/article/abs/pii/S0965856416303494) + +### Data Models and Data Processing Scripts +1. Big Query SQL models (upstream to downstream SQL) + * 2 week [sample](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_stop_time_updates_sample) + * [actual arrivals](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.int_gtfs_rt__trip_updates_trip_stop_day_map_grouping) + * [daily stop time metrics](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_stop_time_metrics) + * [daily stop metrics](https://dbt-docs.dds.dot.ca.gov/index.html#!/model/model.calitp_warehouse.fct_trip_updates_stop_metrics) --> desired future aggregation: move to this stop on a June 2025 weekday instead of this stop on June 1, 2025 + * [GitHub issue](https://github.com/cal-itp/data-infra/issues/4101) + + +2. Python scripts + * [report notebook](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/rt_trip_updates_report.ipynb) + * [Makefile](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/Makefile) + * [download warehouse tables](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/download_warehouse_tables.py) + * [prep data](https://github.com/cal-itp/data-analyses/blob/main/rt_predictions/prep_data.py) \ No newline at end of file diff --git a/rt_predictions/chart_utils.py b/rt_predictions/chart_utils.py index 2654e8df0..32ddd96a5 100644 --- a/rt_predictions/chart_utils.py +++ b/rt_predictions/chart_utils.py @@ -1,278 +1,221 @@ """ -(1a) daily time-series stop df -* % completeness, % accuracy - 2D histogram? -scatterplot is similar, but this groups them -* avg_prediction_error_minutes -layered histogram or several histograms by day_of_week -* avg_prediction_spread_minutes -layered histogram or several histograms by day_of_week -* n_predictions in the 30 min interval - -(1b) aggregated day_type stop df -* % completeness, % accuracy by day_type - 2D histogram? -* avg_prediction_error_minutes -* avg_prediction_spread_minutes -* daily_predictions_per_stop -* can we put the above all in a table, pivoted wide so it's weekday/sat/sun? - -would be nice to merge in trip grain, and trip grain has a column -for an array of stop_ids, so when we aggregate to route-direction, -we can unpack the stops for that and grab it from the stop grain - -(2a) -(2b) +Chart and map functions for report. """ import altair as alt -import folium import geopandas as gpd import pandas as pd -def make_layered_histogram( +TRI_COLORS = ["#ccbb44","#5b8efd","#dd217d"] +FOUR_COLORS = ["#dd217d","#fcb40e","#ccbb44","#5b8efd"] +FOUR_COLORS2 = ["#ee6677","#66ccee","#ccbb44","#4477aa",] +FULL_CATEGORICAL_COLORS = ["#5b8efd", "#765fec", "#fcb40e", "#fc5c04", "#dd217d", "#ccbb44"] + + +def histogram_line_chart_by_date( df: pd.DataFrame, - plot_col:str, - step_size: float -): + metric_column: str, + legend_color_column: str +) -> alt.Chart: """ - Might be useful for distributions of the metrics by day_type - https://altair-viz.github.io/gallery/layered_histogram.html + Distill the results from a histogram (deciles binned) for each day + into 1 chart. + Line chart works better; can't get bar chart to unstack and still select + a date for a legend. - Make a symmetrical distribution, centered on 0. - Find the larger of min and max and use that as bounds. + Purpose of chart is to show daily differences in distribution, so that we are + comfortable with moving towards a day_type aggregation (weekday/Sat/Sun summary). """ - vertical_line = alt.Chart( - pd.DataFrame({'line_x': [0]})).mark_rule( - color='red' - ).encode( - x=alt.X('line_x:Q', title="") - ) - - chart = ( - alt.Chart(df) - .mark_bar( - opacity=0.3, - binSpacing=0 - ).encode( - alt.X(f'{plot_col}:Q', bin=alt.Bin(step=step_size), - #scale=alt.Scale(domain=[bounds * -1, bounds]) - ), - alt.Y('count()', stack=None), - alt.Color( - 'weekday_weekend:N', - scale=alt.Scale( - range=["#ccbb44","#5b8efd","#dd217d"]) # tri_color color_palette - ) - ) + selection = alt.selection_point(fields=[legend_color_column], bind='legend') + + subset_df = df[df.metric==metric_column] + + if "Weekday" in subset_df[legend_color_column].unique(): + sort_order = ["Weekday", "Saturday", "Sunday"] + else: + sort_order = sorted(subset_df[legend_color_column].unique().tolist()) + + chart= ( + alt.Chart(subset_df) + .mark_line(point={"size": 15, "filled": True}) + .encode( + alt.X('decile_bin'), + alt.Y('counts:Q'), + alt.Color( + f'{legend_color_column}:N', + sort = sort_order, + scale=alt.Scale(range=FULL_CATEGORICAL_COLORS + TRI_COLORS + FOUR_COLORS + FOUR_COLORS2), + + ), + opacity=alt.when(selection).then(alt.value(1)).otherwise(alt.value(0.2)), + strokeWidth=alt.when(selection).then(alt.value(2)).otherwise(alt.value(1)), + tooltip = ["decile_bin", "counts", "metric"] + ).add_params( + selection + ).properties( + title = f"{metric_column.replace('pct_tu', '%').replace('_', ' ')}", + width = 220, height = 170 + ).interactive() ) - return chart + vertical_line + return chart -def counts_for_2d_histogram( - df: pd.DataFrame -) -> pd.DataFrame: - """ - Group by the combinations of the 2 percent columns. - Otherwise, each stop is overlaying the other, and we can't actually see. +def boxplot_by_date( + df: pd.DataFrame, + y_col: str +) -> alt.Chart: """ - df2 = ( - df - .groupby(["pct_complete_minutes", "pct_accurate_minutes", "weekday_weekend"]) - .agg({"stop_id": "count"}) - .reset_index() - .rename(columns = {"stop_id": "n_stops"}) - ) - - return df2 + Get a boxplot for each day to look at distribution avg_prediction_error_minutes + and avg_prediction_spread_minutes. + These are more suited to see how "early" or "late" an operator's predictions are. + If it's centered at 0, that's very on-time/accurate! -def make_2d_histogram( - df: pd.DataFrame, - title: str = "", -): - """ - https://altair-viz.github.io/gallery/histogram_scatterplot.html - prefer this one: https://altair-viz.github.io/gallery/histogram_heatmap.html + Couldn't get alt.datum to work from this: + https://altair-viz.github.io/user_guide/encodings/index.html#datum-and-value """ - aggregated_df = counts_for_2d_histogram(df) + df = df.assign(horiz_line = 0) chart = ( - alt.Chart(aggregated_df) - .mark_rect() + alt.Chart(df) + .mark_boxplot() .encode( - x = alt.X( - "pct_complete_minutes:Q", - bin=alt.Bin(maxbins=20), - title = "% complete" - ), - y = alt.Y( - "pct_accurate_minutes:Q", - bin=alt.Bin(maxbins=20), - title = "% accurate" - ), + x=alt.X('service_date:T', axis=alt.Axis(format="%b %e")), + y=f'{y_col}:Q', color=alt.Color( - 'sum(n_stops):Q', - scale=alt.Scale(scheme="greenblue") - #range=["#ccbb44","#5b8efd","#dd217d"] # color_palette - ), - #size='sum(n_stops)', - tooltip=["weekday_weekend", "n_stops", - "pct_complete_minutes", "pct_accurate_minutes"] - ).properties(title=title).interactive() + "day_type:N", + scale=alt.Scale( + domain=["Weekday", "Saturday", "Sunday"], + range=FULL_CATEGORICAL_COLORS) + ), + ) + ) + + #rule = alt.Chart(df).mark_rule(strokeDash=[2, 2]).encode( + # y=alt.datum(0) + #) + rule = alt.Chart(df).mark_rule( + color='black', strokeWidth=1, strokeDash=[2, 2] + ).encode( + y='horiz_line' ) + + combined = (chart + rule).properties( + title=f"{y_col.replace('_', ' ').title()}" + ) - return chart - -def make_boxplot_by_day_type( + return combined + + +def bar_chart_by_date( df: pd.DataFrame, - plot_col: str, - title: str + legend_color_column: str, + is_stacked: bool ) -> alt.Chart: - """ - """ - boxplot = ( - alt.Chart( - df[["weekday_weekend", "service_date", "stop_id", "stop_name", plot_col]] - ).mark_boxplot(size=4, opacity=0.7) + selection = alt.selection_point(fields=[legend_color_column], bind='legend') + + chart = ( + alt.Chart(df) + .mark_bar(size=20) .encode( - x="service_date:T", - y=f"{plot_col}:Q", + x=alt.X("service_date:T", axis=alt.Axis(format='%b %e')), + y=alt.Y("count()"), color=alt.Color( - 'weekday_weekend:N', - scale = alt.Scale(range=["#ccbb44","#5b8efd","#dd217d"]) + f"{legend_color_column}:N", + sort = ["5+ min early", "3-5 min early", "1-3 min early", + "1 min early to 1 min late", + "1-3 min late", "5+ min late", + "unknown"], + scale = alt.Scale(range = FULL_CATEGORICAL_COLORS), ), - tooltip=["stop_id", "stop_name", plot_col] - ).interactive().properties(title = title) - ) - - return boxplot - - -def test_jitter(plot_col): - plot_col = "avg_prediction_error_minutes" - - subset_gdf = gdf1[["weekday_weekend", "service_date", "stop_id", "stop_name", plot_col]] - - jitter = alt.Chart(subset_gdf).mark_circle(size=8).encode( - x="service_date:T", - y=f"{plot_col}:Q", - xOffset="jitter:Q", - yOffset="jitter:Q", - color=alt.Color('weekday_weekend:N', legend=None) - ).transform_calculate( - # Generate Gaussian jitter with a Box-Muller transform - #jitter="sqrt(-2*log(random()))*cos(2*PI*random())" - jitter='random()' + opacity=alt.when(selection).then(alt.value(1)).otherwise(alt.value(0.2)), + tooltip = ["service_date", legend_color_column, "count()"], + ).add_params( + selection + ).properties( + title = f"{legend_color_column.replace('_', ' ').replace('label', '').title()}", + width = 350, height = 300 + ).interactive() ) - return jitter + if is_stacked: + chart = chart.encode( + y=alt.Y("count()", stack="normalize") + ) -def stop_map_of_metric( - gdf: gpd.GeoDataFrame, - plot_col: str -): - subset_gdf = gdf[["stop_id", "stop_name", "weekday_weekend", plot_col, "geometry"]] - weekday_df = subset_gdf[subset_gdf.weekday_weekend=="Weekday"] - sat_df = subset_gdf[subset_gdf.weekday_weekend=="Saturday"] - sun_df = subset_gdf[subset_gdf.weekday_weekend=="Sunday"] + return chart - m = weekday_df.explore( + +def plot_basic_map(gdf: gpd.GeoDataFrame, plot_col: str, colorscale: str): + """ + Function for map arguments. + """ + m = gdf.explore( plot_col, - tiles = "CartoDB Positron", - name="Weekday" + tiles = "CartoDB Positron", + cmap = colorscale, + legend=True, + legend_kwds = { + "caption": f"{plot_col.replace('pct_tu', '%').replace('_', ' ').title()}" + } ) - - if len(sat_df) > 0: - m = sat_df.explore(plot_col, m=m, name="Saturday", legend=False) - - if len(sun_df) > 0: - m = sun_df.explore(plot_col, m=m, name="Sunday", legend=False) - - folium.LayerControl().add_to(m) - + return m -def manual_quartiles( - df: pd.DataFrame -) -> pd.DataFrame: - """ - For percents, start with 0.25, 0.5, 0.75. - For other metrics, divide into 4 groups? - """ - pct_scale_cols = ["pct_accurate_minutes", "pct_complete_minutes"] - other_metric_cols = ["avg_prediction_error_sec", "avg_prediction_spread_minutes", "avg_predictions_per_trip"] - for c in pct_scale_cols: - df[f"{c}_categorized"] = pd.qcut(df[c], q=[0, 0.25, 0.5, 0.75, 1], labels=['< 25%', '25-50%', '50-75%', '> 75%']) +def make_map(gdf: gpd.GeoDataFrame, plot_col: str): + """ + Make map for metric. + The map gets cluttered with the tooltip, + so keep only a small set of columns. + """ + keep_cols = [ + "month", "year", "day_type", + "stop_id", "stop_name", + "pct_tu_predictions_early", "pct_tu_predictions_ontime", "pct_tu_predictions_late", + "avg_prediction_error_minutes", "avg_prediction_spread_minutes", + "prediction_error_label", "n_predictions", + "geometry" + ] + categorical_cols = ["prediction_error_label"] + + if plot_col in categorical_cols: + colorscale = FULL_CATEGORICAL_COLORS + else: + colorscale = "viridis" + + subset_weekday_gdf = gdf[ + gdf.day_type == "Weekday" + ][keep_cols].dropna(subset="geometry") + + subset_weekend_gdf = gdf[ + gdf.day_type != "Weekday" + ][keep_cols].dropna(subset="geometry") + + # try to plot weekday where we can + if len(subset_weekday_gdf) > 0: + + m = plot_basic_map(subset_weekday_gdf, plot_col, colorscale) - for c in other_metric_cols: - df[f"{c}_categorized"] = pd.qcut(df[c], q=4) - - return df + # if there are no weekday rows, then let's plot weekend + elif len(subset_weekday_gdf) == 0 and len(subset_weekend_gdf) > 0: + print(f"Weekday map could not be plotted. Plot weekend map.") + m = plot_basic_map(subset_weekend_gdf, plot_col, colorscale) -def make_bar_chart(df: pd.DataFrame, plot_col: str): - """ - Put a daily chart, x=service_date, y=metric, - see if we can merge in the avg for the day_type - """ - chart = ( - alt.Chart(df) - .mark_bar() - .encode( - x=alt.X( - "yearmonthdate(service_date):O", - title="Date", - axis=alt.Axis(labelAngle=-45) - ), - y=alt.Y(plot_col), - column=alt.Column("day_type:N") - ) - ) - - return chart - -#make_layered_histogram(df, "avg_prediction_spread_minutes") -#make_layered_histogram(df, "avg_prediction_error_sec") -#make_layered_histogram(df, "pct_accurate_minutes") -#make_layered_histogram(df, "n_predictions") # this covers the period that's 30 minutes before arrival - + else: + m = "No map could be plotted. Debug error related to schedule + RT data." + + return m -def base_facet_line_chart( - df: pd.DataFrame, - y_col: str, - facet_col: str, - ruler_col: str -) -> alt.Chart: - # Create the ruler chart - ruler = ( - alt.Chart(df) - .mark_rule(color="red", strokeDash=[10, 7]) - .encode(y=f"{ruler_col}:Q") - ) - - chart = ( - alt.Chart(df) - .mark_line() - .encode( - x=alt.X( - "stop_name:O", - title="Stop", - order = "stop_sequence", - axis=alt.Axis(labelAngle=-45), - ), - ) - ) - # Add ruler plus main chart - chart = (chart + ruler).properties(width=200, height=250) - chart = chart.facet( - column=alt.Column("{facet_col}:N"), - ).properties( - #title={ - # "text": [title], - # "subtitle": [subtitle], - #} - ) - - return chart +''' +Double check that we have different values for each date +daily_df2[daily_df2.metric=="pct_tu_accurate_minutes"].groupby( + ["decile_bin"] +).agg({ + "service_date": lambda x: list(x), + "counts": lambda x: list(x)} +).reset_index() +''' \ No newline at end of file diff --git a/rt_predictions/deploy_portfolio_yaml.py b/rt_predictions/deploy_portfolio_yaml.py new file mode 100644 index 000000000..2f286a77c --- /dev/null +++ b/rt_predictions/deploy_portfolio_yaml.py @@ -0,0 +1,73 @@ +""" +Create the yamls for parameterized reports. + +Since these yamls do not use sections, we can +generate them similarly using Makefile commands. + +Try out typer to make CLI a little easier to use, since +this only takes 1 argument with 2 possible values. +Base it off of this tutorial: +https://typer.tiangolo.com/tutorial/options/required/ +""" +import pandas as pd +import typer + +from pathlib import Path + +from shared_utils import portfolio_utils +from rt_msa_utils import PREDICTIONS_GCS, RT_MSA_DICT + +RT_TRIP_UPDATES_STOP_YAML = Path("../portfolio/sites/rt_trip_updates_stop_metrics.yml") +RT_TRIP_UPDATES_ROUTE_YAML = Path("../portfolio/sites/rt_trip_updates_route_metrics.yml") + +app = typer.Typer() + +excluded_operators = [ + "Bay Area 511 Regional Schedule" +] + +@app.command() +def overwrite_yaml( + name: str = typer.Argument(default="rt_msa") +): + """ + Create yamls for portfolio. + """ + if name == "rt_msa_stops": + FILE = RT_MSA_DICT.rt_schedule_models.weekday_stop_grain + + df = pd.read_parquet( + f"{PREDICTIONS_GCS}{FILE}.parquet", + columns = ["schedule_name"], + filters = [[ ("schedule_name", "not in", excluded_operators)]] + ).drop_duplicates().dropna( + subset="schedule_name" + # there shouldn't be occurrences of this, but there are, so check why + ).rename(columns = {"schedule_name": "name"}) + + portfolio_utils.create_portfolio_yaml_chapters_no_sections( + RT_TRIP_UPDATES_STOP_YAML, + chapter_name = "name", + chapter_values = sorted(list(df.name)) + ) + + elif name == "rt_msa_trips": + FILE = RT_MSA_DICT.rt_trip_updates_models.weekday_route_direction_grain + + df = pd.read_parquet( + f"{PREDICTIONS_GCS}{FILE}.parquet", + columns = ["name"], + filters = [[("name", "notin", excluded_operators)]] + ).drop_duplicates() + + portfolio_utils.create_portfolio_yaml_chapters_no_sections( + RT_TRIP_UPDATES_ROUTE_YAML, + chapter_name = "name", + chapter_values = sorted(list(df.name)) + ) + + return + + +if __name__ == "__main__": + app() diff --git a/rt_predictions/download_warehouse_tables.py b/rt_predictions/download_warehouse_tables.py new file mode 100644 index 000000000..461c3dff7 --- /dev/null +++ b/rt_predictions/download_warehouse_tables.py @@ -0,0 +1,214 @@ +""" +Download sample tables (2 weeks worth) that were created. +Benchmark times, get intuitive feel for how much we +can comfortably work with. + +Exploratory work around aggregations, make sure metrics make sense. +Visualize these. +Go back to tables and tweak data models. +""" +import datetime +import geopandas as gpd +import pandas as pd +import google.auth +import shapely +import sys + +from loguru import logger + +import warehouse_utils +from rt_msa_utils import PREDICTIONS_GCS +credentials, project = google.auth.default() + +''' +from functools import cache +from calitp_data_analysis import get_fs +from calitp_data_analysis.gcs_geopandas import GCSGeoPandas +gcsgp = GCSGeoPandas() + +@cache +def gcs_geopandas(): + return GCSGeoPandas() +''' +PRODUCTION_PROJECT = "cal-itp-data-infra" +STAGING_PROJECT = "cal-itp-data-infra-staging" +PRODUCTION_MART_GTFS = "mart_gtfs" +TIFFANY_MART = "tiffany_mart_gtfs" + +def download_daily_metrics( + table_name: str, + start_date: str, + end_date: str, +) -> pd.DataFrame: + """ + Download daily stop or trip metrics. + """ + t0 = datetime.datetime.now() + + if table_name == "fct_trip_updates_stop_metrics": + sql_query = f""" + SELECT + * EXCEPT(prediction_error_by_minute_array, minutes_until_arrival_array) + FROM `{PRODUCTION_PROJECT}.{PRODUCTION_MART_GTFS}.{table_name}` + """ + else: + sql_query = warehouse_utils.basic_sql_query( + PRODUCTION_PROJECT, PRODUCTION_MART_GTFS, table_name + ) + + where_condition = warehouse_utils.add_sql_date_filter("service_date", start_date, end_date) + + df = warehouse_utils.download_table_with_date( + f"{sql_query} {where_condition}", + date_col = "service_date" + ) + + df.to_parquet( + f"{PREDICTIONS_GCS}{table_name}_{start_date}_{end_date}.parquet", + engine = "pyarrow" + ) + + t1 = datetime.datetime.now() + logger.info(f"download {table_name}: {start_date}-{end_date}: {t1 - t0}") + + return + + +def download_staging_table( + project_name: str = STAGING_PROJECT, + dataset_name = TIFFANY_MART, + table_name: str = "", + date_col: str = "", + start_date: str = "", + end_date: str = "", + get_df: bool = False +) -> pd.DataFrame: + """ + Download staging table + """ + t0 = datetime.datetime.now() + + sql_query = warehouse_utils.basic_sql_query(project_name, dataset_name, table_name) + where_condition = warehouse_utils.add_sql_date_filter(date_col, start_date, end_date) + + df = warehouse_utils.download_table_with_date( + f"{sql_query} {where_condition}", + date_col = date_col + ) + + if get_df: + return df + else: + df.to_parquet( + f"{PREDICTIONS_GCS}{table_name}_{start_date}_{end_date}.parquet" + ) + t1 = datetime.datetime.now() + logger.info(f"download {table_name}: {start_date}-{end_date}: {t1 - t0}") + + return + +def download_staging_table_with_geom( + project_name: str = STAGING_PROJECT, + dataset_name = TIFFANY_MART, + table_name: str = "", + date_col: str = "", + start_date: str = "", + end_date: str = "", + geom_col: str = "", + geom_type: str = "" +): + """ + Download table with geom, save out as gdf + """ + t0 = datetime.datetime.now() + + sql_query = warehouse_utils.basic_sql_query(project_name, dataset_name, table_name) + where_condition = warehouse_utils.add_sql_date_filter(date_col, start_date, end_date) + + gdf = warehouse_utils.download_table_with_date_geom( + f"{sql_query} {where_condition}", + date_col = date_col, + geom_col = geom_col, + geom_type = geom_type + ) + + warehouse_utils.geoparquet_gcs_export( + gdf, + f"{PREDICTIONS_GCS}", + table_name + ) + + t1 = datetime.datetime.now() + logger.info(f"download {table_name}: {start_date}-{end_date}: {t1 - t0}") + return + +def download_staging_table_no_dates( + project_name: str = STAGING_PROJECT, + dataset_name = TIFFANY_MART, + table_name: str = "", +): + """ + These are staging tables in tiffany_mart_gtfs that don't have a service_date column. + """ + t0 = datetime.datetime.now() + + sql_query = warehouse_utils.basic_sql_query(project_name, dataset_name, table_name) + + df = warehouse_utils.download_table_no_date( + sql_query + ) + + df.to_parquet( + f"{PREDICTIONS_GCS}{table_name}.parquet" + ) + + t1 = datetime.datetime.now() + logger.info(f"download {table_name}: {t1 - t0}") + + return + + +if __name__ == "__main__": + + LOG_FILE = "./logs/download_warehouse.log" + logger.add(LOG_FILE, retention="2 months") + logger.add(sys.stderr, + format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}", + level="INFO") + + + ## (1) Download the production ready tables + for t in ["fct_trip_updates_stop_metrics", "fct_trip_updates_trip_metrics"]: + download_daily_metrics( + table_name = t, + start_date = "2025-06-01", + end_date = "2025-06-15", + ) + + + ## (2) Download aggregations on trip metrics + for t in [ + "test_schedule_rt_trip_metrics", + "test_schedule_rt_route_direction_metrics", + "test_schedule_rt_route_metrics", + "crosswalk_stop_times_route_dir", + ]: + download_staging_table_no_dates( + project_name = STAGING_PROJECT, + dataset_name = TIFFANY_MART, + table_name = t, + ) + + + ## (3) Download aggregations on stop metrics + download_staging_table_with_geom( + project_name = STAGING_PROJECT, + dataset_name = TIFFANY_MART, + table_name = "test_monthly_schedule_rt_stop_metrics", + date_col = "month_first_day", + start_date = "2025-06-01", + end_date = "2025-06-01", + geom_col = "pt_geom", + geom_type = "point" + ) + \ No newline at end of file diff --git a/rt_predictions/prep_data.py b/rt_predictions/prep_data.py new file mode 100644 index 000000000..8ce8cd17f --- /dev/null +++ b/rt_predictions/prep_data.py @@ -0,0 +1,369 @@ +""" +Data prep related to removing outliers, adding new columns, rounding values, +renaming columns. +Minimal data processing, move as much into dbt models, but +what shouldn't be done there should be handled here. +""" +import datetime +import geopandas as gpd +import pandas as pd +import google.auth +import sys + +from loguru import logger + +from rt_msa_utils import PREDICTIONS_GCS, RT_MSA_DICT + +credentials, project = google.auth.default() + +PREDICTION_CATEGORIES = ["early", "ontime", "late"] + +MIN_ERROR_SEC = -250 +MAX_ERROR_SEC = 250 +MIN_ERROR_SEC_5MIN = -60 * 5 +MAX_ERROR_SEC_5MIN = 60 * 5 + +PREDICTION_ERROR_COLS = [ + "avg_prediction_error_sec", + "pct_tu_predictions_early", "pct_tu_predictions_ontime", "pct_tu_predictions_late" +] + +ACCURACY_COLS = [ + "pct_tu_accurate_minutes", "pct_tu_predictions_ontime" +] + +# Drop a bunch of stuff for data wrangling we want to do for analysis or exploration +PERCENTILE_LIST = [0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99] + +def drop_outliers( + df: pd.DataFrame, + min_cutoff: int, + max_cutoff: int +) -> pd.DataFrame: + """ + Drop outliers based on avg_prediction_error_sec for now. + Use 250 seconds on either end, this is roughly 1% of either tail. + In the future, we might expand to other columns. + """ + return df[ + (df.avg_prediction_error_sec >= min_cutoff) & + (df.avg_prediction_error_sec <= max_cutoff) + ].reset_index(drop=True) + + +def round_columns(df: pd.DataFrame) -> pd.DataFrame: + """ + Rounding numeric columns, convert seconds to minutes for charts. + TODO: added rounding to dbt models, those have been rounded to 2 decimal places, we + want 3 decimal places + """ + df = df.assign( + avg_prediction_error_minutes = df.avg_prediction_error_sec.divide( + 60).round(3), + avg_prediction_spread_minutes = df.avg_prediction_spread_minutes.round(2), + ) + return df + + +def calculate_percents(df: pd.DataFrame): + """ + Calculate percents for the daily stop df. + In the aggregated one, these will be pre-calculated in dbt model. + """ + df = df.assign( + pct_tu_predictions_early = df.n_predictions_early.divide( + df.n_predictions).round(3), + pct_tu_predictions_ontime = df.n_predictions_ontime.divide( + df.n_predictions).round(3), + pct_tu_predictions_late = df.n_predictions_late.divide( + df.n_predictions).round(3), + pct_tu_accurate_minutes = df.n_tu_accurate_minutes.divide( + df.n_tu_minutes_available).round(3), + pct_tu_complete_minutes = df.n_tu_complete_minutes.divide( + df.n_tu_minutes_available).round(3), + avg_predictions_per_trip = df.n_predictions.divide( + df.n_tu_trips).round(3), + ) + + return df + + +def prediction_count_sanity_check(df: pd.DataFrame) -> pd.DataFrame: + """ + Noticed that there are some rows where predictions (when aggregated + to stop) do not line up to 100%. + Why? + - Does this have to do with losing stop_sequence (stop_time grain -> stop grain)? + - Are these all on-time ones that fall between/exactly on "actual" arrival and departure? + - small % of these, need to go back to dbt models to check + """ + pct_cols = [ + f"pct_tu_predictions_{i}" for i in PREDICTION_CATEGORIES + ] + count_cols = [f"n_predictions_{i}" for i in PREDICTION_CATEGORIES] + + df = df.assign( + n_predictions2 = df[count_cols].sum(axis=1), + pct_predictions2 = df[pct_cols].sum(axis=1) + ) + + return df + + +def remove_rows_where_needing_investigation(df: pd.DataFrame) -> pd.DataFrame: + """ + Perhaps some are due to rounding of rounding to 1 decimal place. + Allow those to be pretty close to be included. + + Otherwise, for now, let's remove the ones where counts + do not fall within the boundaries of rounding errors. + """ + df2 = df[ + (df.pct_predictions2 >= 0.98) & + (df.pct_predictions2 <= 1.02 ) + ].reset_index(drop=True).drop( + columns = ["pct_predictions2", "n_predictions2"] + ) + + return df2 + + +def pct_rows_need_investigation(df: pd.DataFrame): + """ + Quick descriptive to understand how many rows are off, + even after accounting for rounding errors. + """ + denominator = len(df) + numerator = len(df[(df.pct_predictions2 >= 0.98) & (df.pct_predictions2 <= 1.02 )]) + + # account for rounding error + print(numerator/denominator) + return + + +def categorize_day_type(df: pd.DataFrame) -> pd.DataFrame: + """ + This is already done for aggregated dfs. + Add this so we can color altair charts more easily. + """ + category_dict = { + **{k: "Weekday" for k in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]}, + **{k: k for k in ["Saturday", "Sunday"]}, + } + + df = df.assign( + day_type = df.service_date.dt.day_name().map(category_dict) + ) + + return df + +def import_stop_df( + is_daily: bool, + filters: tuple, +) -> gpd.GeoDataFrame: + """ + """ + if is_daily: + subset_operators = pd.read_parquet( + f"{PREDICTIONS_GCS}{RT_MSA_DICT.rt_schedule_models.weekday_stop_grain}.parquet", + columns = ["tu_base64_url", "schedule_name"], + filters = filters + ).drop_duplicates().rename( + columns = {"tu_base64_url": "base64_url"} + ) + + df = pd.read_parquet( + f"{PREDICTIONS_GCS}{RT_MSA_DICT.rt_trip_updates_downloads.daily_stop_grain}.parquet", + filters = [[("base64_url", "in", subset_operators.base64_url.tolist())]] + ).merge( + subset_operators, + on = "base64_url", + how = "inner" + ).pipe( + calculate_percents + ).pipe( + round_columns + ).pipe( + prediction_count_sanity_check + ).pipe( + drop_outliers, + MIN_ERROR_SEC, MAX_ERROR_SEC + ).pipe( + remove_rows_where_needing_investigation + ).pipe( + categorize_day_type + ).pipe( + categorize_prediction_error, + "avg_prediction_error_minutes" + ) + + + else: + df = gpd.read_parquet( + f"{PREDICTIONS_GCS}{RT_MSA_DICT.rt_schedule_models.weekday_stop_grain}.parquet", + filters = filters, + storage_options={"token": credentials.token} + ).pipe( + round_columns + ).pipe( + prediction_count_sanity_check + ).pipe( + drop_outliers, + MIN_ERROR_SEC_5MIN, MAX_ERROR_SEC_5MIN + # use 5 minute cutoffs, this is also < 1% on either tail + ).pipe( + remove_rows_where_needing_investigation + ).pipe( + categorize_prediction_error, + "avg_prediction_error_minutes" + ) + + return df + + +def daily_binned_counts_by_deciles( + df: pd.DataFrame, + percentile_columns: list +): + """ + Create side-by-side chart that will show distributions (deciles) for + pct_tu_predictions_early/ontime/late (compare daily vs daytype aggregation). + Might need to pre-aggregate or the notebook will not produce portfolio for + larger operators (4 sec timeout for autosave). + """ + bins = pd.IntervalIndex.from_tuples([ + (0, 0.1), (0.101, 0.2), (0.201, 0.3), + (0.301, 0.4), (0.401, 0.5), (0.501, 0.6), + (0.601, 0.7), (0.701, 0.8), (0.801, 0.9), (0.901, 1.0) + ]) + + for c in percentile_columns: + # For a column, categorize it into a decile + df[f"{c}_bin"] = pd.cut(df[c], bins) + + return df + + +def summary_counts_by_bins( + df: pd.DataFrame, + group_cols: list, + percentile_columns: list +): + """ + Get daily counts for each decile bin. + These will be concatenated into a long df so that the altair line chart + can share the same x-axis (decile bins) and legend can select a + particular service_date to highlight. + + df coming in looks like: + stop1 decile1 + stop2 decile1 + stop3 decile2 + + post aggregation df: + decile1 2 stops metric1 + decile2 1 stop metric1 + """ + summary_dfs = [] + + for col in percentile_columns: + + binned_column = f"{col}_bin" + + df2 = ( + df + .groupby(group_cols + [binned_column]) + .agg({"stop_key": "count"}) + .reset_index() + .rename(columns = { + binned_column: "decile_bin", + "stop_key": "counts" + }) + ) + + df2 = df2.assign( + metric = col + ) + + summary_dfs.append(df2) + + + # Concatenate and create a long df, where each row is service_date-operator-decile-metric. + # day1-operator-1st_decile-pct_early, day1-operator-1st_decile-pct_ontime + summary_df = pd.concat( + summary_dfs, + axis=0, ignore_index=True + ).astype( + {"decile_bin": "str"} + ) + + return summary_df + + +def categorize_prediction_error( + df: pd.DataFrame, + prediction_error_col: str +) -> pd.DataFrame: + """ + Using exponential equation to determine accuracy means it is + fairly assertive. + However, we can convert that to minutes and get a better understanding + of how far out operators are doing. + """ + UPPER = 5 # 5 minutes + MIDDLE = 3 + LOWER = 1 + + PREDICTION_ERROR_LABELS = { + "very_early": "5+ min early", + "early": "3-5 min early", + "little_early": "1-3 min early", + "ontime": "1 min early to 1 min late", + "little_late": "1-3 min late", + "late": "3-5 min late", + "very_late": "5+ min late", + "unknown": "unknown" + } + + df["prediction_error_category"] = df.apply( + lambda x: set_error_cutoffs( + x[prediction_error_col], UPPER, MIDDLE, LOWER), + axis=1 + ) + df["prediction_error_label"] = df.prediction_error_category.map(PREDICTION_ERROR_LABELS) + + return df + + +def set_error_cutoffs( + prediction_error: float, + upper_cutoff: int, + middle_cutoff: int, + lower_cutoff: int, +) -> str: + """ + early (positive values) mean prediction is earlier than actual arrival + bus comes after prediction (which means you will catch bus) + highest end, > 5 minutes + second highest: 3.01 minutes to 5.0 minutes + second lowest: -3.01 minutes (late) to -5.0 minutes (late) + lowest end < -5 minutes (late) + """ + if prediction_error > upper_cutoff: + return "very_early" + elif (prediction_error <= upper_cutoff) and (prediction_error > middle_cutoff): + return "early" + elif (prediction_error <= middle_cutoff) and (prediction_error > lower_cutoff): + return "little_early" + elif (prediction_error <= lower_cutoff) and (prediction_error >= -1 * lower_cutoff): + return "ontime" + elif (prediction_error < -1 * lower_cutoff) and (prediction_error >= -1 * middle_cutoff): + return "little_late" + elif (prediction_error < -1 * middle_cutoff) and (prediction_error >= -1 * upper_cutoff): + return "late" + elif (prediction_error < -1 * upper_cutoff): + return "very_late" + else: + return "unknown" + + diff --git a/rt_predictions/rt_msa_catalog.yml b/rt_predictions/rt_msa_catalog.yml new file mode 100644 index 000000000..759dd7876 --- /dev/null +++ b/rt_predictions/rt_msa_catalog.yml @@ -0,0 +1,21 @@ +# GTFS RT MSA catalog +gcs_paths: + GCS: gs://calitp-analytics-data/data-analyses/ + PREDICTIONS_GCS: ${.GCS}rt_predictions/ + +# Existing dbt models or tweaks to existing dbt models +rt_trip_updates_downloads: + dir: ${gcs_paths.PREDICTIONS_GCS} + daily_trip_grain: "fct_trip_updates_trip_metrics_2025-06-01_2025-06-15" + daily_stop_grain: "fct_trip_updates_stop_metrics_2025-06-01_2025-06-15" + daily_schedule_rt_trip_grain: "test_schedule_rt_trip_metrics" + + +# Stage future dbt models that are aggregations or joins across quartet +rt_schedule_models: + dir: ${gcs_paths.PREDICTIONS_GCS} + weekday_route_direction_grain: "test_schedule_rt_route_direction_metrics" + weekday_route_grain: "test_schedule_rt_route_metrics" + weekday_stop_grain: "test_monthly_schedule_rt_stop_metrics" + crosswalk_stops_route_dir: "crosswalk_stop_times_route_dir" + crosswalk_stops_route_dir2: "crosswalk_stop_times_route_dir2_2025-06-01_2025-06-01" \ No newline at end of file diff --git a/rt_predictions/rt_msa_utils.py b/rt_predictions/rt_msa_utils.py new file mode 100644 index 000000000..f86172808 --- /dev/null +++ b/rt_predictions/rt_msa_utils.py @@ -0,0 +1,14 @@ +from omegaconf import OmegaConf +from pathlib import Path + +PREDICTIONS_GCS = "gs://calitp-analytics-data/data-analyses/rt_predictions/" + +def get_catalog(catalog_name = "rt_msa_catalog") -> Path: + """ + Grab GTFS RT MSA catalog (uses OmegaConf yaml parser). + """ + catalog_path = Path.cwd().joinpath(f"{catalog_name}.yml") + + return OmegaConf.load(catalog_path) + +RT_MSA_DICT = get_catalog("rt_msa_catalog") \ No newline at end of file diff --git a/rt_predictions/rt_trip_updates_report.ipynb b/rt_predictions/rt_trip_updates_report.ipynb index e59df0423..ad0a0b4c1 100644 --- a/rt_predictions/rt_trip_updates_report.ipynb +++ b/rt_predictions/rt_trip_updates_report.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "df299e42-ab1c-428e-b292-443a15bf08c2", + "id": "827cc662-3fca-4d05-926d-aa21224a8034", "metadata": { "tags": [] }, @@ -15,13 +15,12 @@ "warnings.filterwarnings(\"ignore\")\n", "\n", "import altair as alt\n", - "import geopandas as gpd\n", "import pandas as pd\n", "\n", "import calitp_data_analysis.magics\n", "from great_tables import GT\n", "\n", - "import viz_stop_metrics\n", + "import prep_data\n", "import chart_utils\n", "\n", "alt.data_transformers.enable(\"vegafusion\")" @@ -30,7 +29,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6ddc53c0-44ac-4894-a13f-92f93e69f444", + "id": "b898ae0b-54d3-4909-bfcc-b9bee2615217", "metadata": { "tags": [ "parameters" @@ -45,368 +44,555 @@ { "cell_type": "code", "execution_count": null, - "id": "39c971f8-0d82-4eb0-a718-7672e3afa25e", - "metadata": { - "tags": [] - }, + "id": "ceb3c1ed-8c30-4cc0-8883-4d3634087eff", + "metadata": {}, "outputs": [], "source": [ "%%capture_parameters\n", "name" ] }, + { + "cell_type": "markdown", + "id": "625a3901-75f8-4cf8-b694-9e37d669a38e", + "metadata": {}, + "source": [ + "# {name} \n", + "\n", + "One of the most common transit user behaviors is to consult an app (Google Maps, Apple Maps, NextBus, etc) to find out when the bus or train is going to arrive.\n", + "\n", + "That widely desired piece of information is powered by GTFS Real-Time Trip Updates, specifically the [Stop Time Updates](https://gtfs.org/documentation/realtime/reference/#message-stoptimeupdate) specification. The underlying data produced here is huge. Imagine every instance a bus arrives at a stop in California. Multiply that by 30 for the 30 minutes before the bus arrives, and that's the dataset we're working to distill into usable performance metrics for all transit operators.\n", + "\n", + "Generally, we want better transit user experience. Specifically, the performance metrics we can derive from GTFS RT Trip Updates distills into the following objectives:\n", + "1. Increase prediction reliability and accuracy\n", + "2. Increase the availability and completeness of GTFS RT\n", + "3. Decrease the inconsistency and fluctuations of predictions " + ] + }, { "cell_type": "code", "execution_count": null, - "id": "7dd9d12f-b63e-481b-b937-a16d33a757a6", + "id": "e6ba44e0-16e8-45a8-8c8d-789170560709", "metadata": { "tags": [] }, "outputs": [], "source": [ - "gdf1 = viz_stop_metrics.import_stop_df(\n", - " is_daily = True, filters = [[(\"name\", \"==\", name)]]\n", + "daily_df = prep_data.import_stop_df(\n", + " is_daily = True,\n", + " filters = [[(\"schedule_name\", \"==\", name)]]\n", + ")\n", + "\n", + "daytype_df = prep_data.import_stop_df(\n", + " is_daily = False, \n", + " filters = [[(\"schedule_name\", \"==\", name)]]\n", ")" ] }, { - "cell_type": "markdown", - "id": "52bf3b76-d29f-4956-a010-29d297f5e638", + "cell_type": "code", + "execution_count": null, + "id": "10560041-a5a7-4dca-a8c9-f41d8cad60be", "metadata": { "tags": [] }, + "outputs": [], "source": [ - "# {name} \n", - "## Time-Series\n", - "### Availability and Reliability of Acceptable StopTimeUpdate Messages\n", + "# Create aggregated binned dataset \n", + "# replicate what altair does with count() for histogram\n", + "# do this to avoid the autosave timeout that seems to happen after 4 seconds\n", + "percentile_columns = [\n", + " \"pct_tu_predictions_early\", \n", + " \"pct_tu_predictions_ontime\", \n", + " \"pct_tu_predictions_late\",\n", + " \"pct_tu_accurate_minutes\", \n", + " \"pct_tu_complete_minutes\"\n", + "]\n", + "\n", + "daily_df2 = prep_data.daily_binned_counts_by_deciles(\n", + " daily_df, percentile_columns\n", + ").pipe(\n", + " prep_data.summary_counts_by_bins,\n", + " group_cols = [\"service_date\", \"base64_url\"],\n", + " percentile_columns = percentile_columns\n", + ").astype({\"service_date\": \"str\"}) # make date string for altair legend\n", + "\n", + "daytype_df2 = prep_data.daily_binned_counts_by_deciles(\n", + " daytype_df, percentile_columns\n", + ").pipe(\n", + " prep_data.summary_counts_by_bins,\n", + " group_cols = [\"year\", \"month\", \"month_first_day\", \n", + " \"day_type\", \"schedule_base64_url\", \"tu_base64_url\"],\n", + " percentile_columns = percentile_columns\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0e692c06-d072-437d-a685-68ec0a1c4aa8", + "metadata": {}, + "source": [ + "## Reliable Prediction Accuracy\n", + "\n", + "We can measure progress on this large objective with several metrics:\n", + "\n", + "* Share of predictions that are early / on-time / late\n", + "* Prediction error (difference between `predicted_arrival` and `actual_arrival`)\n", + "* Share predictions that are accurate (prediction error categorized as boolean of accurate or not depending an exponential equation)\n", + " * The prediction is accurate if it falls within the bounds of `-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time\n", + "to Prediction+1.5)`, the further out before arrival, the more generous the buffer. \n", + "* Time period: 30 minutes before the arrival at stop \n", + "\n", + "### Percent Predictions Early / On-Time / Late \n", + "\n", + "* column used `pct_tu_predictions_early`, `pct_tu_predictions_ontime`, `pct_tu_predictions_late`\n", + "* For transit users, **higher proportions of `% predictions early / on-time` mean you are more likely to catch the bus** if you follow the prediction exactly.\n", + "* **Goal:** increase the share of early / on-time predictions and lower share of late predictions.We would rather have transit users follow the predictions and wait for the bus." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4b04152-49e6-43fb-816f-16af078c7081", + "metadata": {}, + "outputs": [], + "source": [ + "chart_list = [\n", + " chart_utils.histogram_line_chart_by_date(\n", + " daily_df2, \n", + " metric_column = f\"pct_tu_predictions_{c}\",\n", + " legend_color_column = \"service_date\"\n", + " ) for c in [\"early\", \"ontime\", \"late\"]\n", + "]\n", "\n", - "* 2+ trip updates with stop arrival information in each minute interval\n", - "* higher accuracy (prediction is accurate if it falls within the bounds of `-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time\n", - "to Prediction+1.5)`, the further out before arrival, the more generous the buffer.\n", - "* Time period: 30 minutes before the arrival at stop" + "combined_percent_daily_chart = alt.hconcat(*chart_list).resolve_scale(y='shared')\n", + "combined_percent_daily_chart" ] }, { "cell_type": "code", "execution_count": null, - "id": "5df2251d-d688-4134-8ee9-8aaad5470895", + "id": "733a524b-3c1b-41d0-be52-c57366b675bf", "metadata": { "tags": [] }, "outputs": [], "source": [ - "stop_grouping_cols = [\"name\", \"weekday_weekend\", \"stop_id\"]\n", - "plot_cols = [\n", - " \"pct_accurate_minutes\", \"pct_complete_minutes\"\n", + "chart_list = [\n", + " chart_utils.histogram_line_chart_by_date(\n", + " daytype_df2, \n", + " metric_column = f\"pct_tu_predictions_{c}\",\n", + " legend_color_column = \"day_type\"\n", + " ) for c in [\"early\", \"ontime\", \"late\"]\n", "]\n", "\n", - "d = \"Weekday\"\n", - "chart = chart_utils.make_2d_histogram(\n", - " gdf1[gdf1.weekday_weekend==d][stop_grouping_cols + plot_cols],\n", - " title = f\"% complete and accurate predictions for {d} trips by stop\"\n", - ")\n", + "combined_percent_daytype_chart = alt.hconcat(*chart_list).resolve_scale(y='shared')\n", + "combined_percent_daytype_chart" + ] + }, + { + "cell_type": "markdown", + "id": "f6561568-885a-4c38-afa2-4f8fb1034d53", + "metadata": {}, + "source": [ + "### High Share of Late Predictions for Weekday Stops Map\n", "\n", - "chart" + "If weekday stops can't be plotted, weekend stops will be used. " ] }, { "cell_type": "code", "execution_count": null, - "id": "a5cf6291-6dd0-4fba-b559-571c89960726", - "metadata": { - "tags": [] - }, + "id": "ccb6e80b-e4f3-481c-ba89-ecffc2685c07", + "metadata": {}, "outputs": [], "source": [ - "d = \"Saturday\"\n", - "chart = chart_utils.make_2d_histogram(\n", - " gdf1[gdf1.weekday_weekend==d][stop_grouping_cols + plot_cols],\n", - " title = f\"% complete and accurate predictions for {d} trips by stop\"\n", + "# These stops have lots of late predictions (that's the type of error we want to avoid)\n", + "m = chart_utils.make_map(\n", + " daytype_df[daytype_df.pct_tu_predictions_late > 0.25], \n", + " \"pct_tu_predictions_late\"\n", ")\n", - "\n", - "chart" + "m" + ] + }, + { + "cell_type": "markdown", + "id": "ce1f2ce9-e4e6-4cda-ac55-a250787e9d61", + "metadata": {}, + "source": [ + "### Average Prediction Error \n", + "* column used `avg_prediction_error_minutes`\n", + "* For transit users, **negative values for `avg_prediction_error` mean you miss the bus** if you follow the prediction exactly.\n", + "* **Goal 1:** minimize occurrences of negative prediction errors.We would rather have transit users follow the predictions and wait for the bus.\n", + "* **Goal 2:** tighten the range of prediction errors and have the range move closer to zero for shorter expected wait times. \n", + " * Large positive prediction error values mean users are expected to wait longer by following the prediction. \n", + " * By tightening the box and centering it on zero, users experience both more reliable predictions and shorter wait times. " ] }, { "cell_type": "code", "execution_count": null, - "id": "0ae063b7-2fc7-4bd8-b639-5f2be4c703be", + "id": "81ffc91c-a010-42f4-a3eb-8981e0a7440a", "metadata": { "tags": [] }, "outputs": [], "source": [ - "d = \"Sunday\"\n", - "chart = chart_utils.make_2d_histogram(\n", - " gdf1[gdf1.weekday_weekend==d][stop_grouping_cols + plot_cols],\n", - " title = f\"% complete and accurate predictions for {d} trips by stop\"\n", - ")\n", - "\n", - "chart" + "chart_utils.boxplot_by_date(daily_df, \"avg_prediction_error_minutes\")" + ] + }, + { + "cell_type": "markdown", + "id": "2e16d67d-f49f-4f44-a313-26a86af7743d", + "metadata": { + "tags": [] + }, + "source": [ + "### % of minutes with accurate predictions\n", + "* column used: `pct_accurate_minutes`\n", + "* For transit users, **a higher proportion of `% accurate minutes` means you are getting reliable predictions for longer stretches of time before the bus arrives**.\n", + "* **Goal:** increase the share of accurate minutes.\n", + "* Note: this metric does depend on the exponential curve, which means that anything outside this fairly assertive curve means low performance on this metric." ] }, { "cell_type": "code", "execution_count": null, - "id": "6cc5c3b6-2d45-4a3b-984d-037d2892c595", + "id": "456fe18d-5620-4af1-877f-9c1f83efb7be", "metadata": { "tags": [] }, "outputs": [], "source": [ - "metric_cols = [\n", - " \"avg_prediction_spread_minutes\",\n", - " \"avg_prediction_error_minutes\",\n", - " \"pct_accurate_minutes\",\n", - " \"pct_complete_minutes\",\n", - " \"avg_predictions_per_trip\",\n", - "]" + "chart_utils.histogram_line_chart_by_date(\n", + " daily_df2, \n", + " metric_column = \"pct_tu_accurate_minutes\",\n", + " legend_color_column = \"service_date\"\n", + ") " ] }, { "cell_type": "code", "execution_count": null, - "id": "40eee46e-1b52-45f4-8c93-71f23a7e9984", + "id": "551dd8f8-2778-417b-bccd-7ce49a319322", + "metadata": {}, + "outputs": [], + "source": [ + "chart_utils.histogram_line_chart_by_date(\n", + " daytype_df2, \n", + " metric_column = \"pct_tu_accurate_minutes\",\n", + " legend_color_column = \"day_type\"\n", + ") " + ] + }, + { + "cell_type": "markdown", + "id": "5a4572b3-d2f3-4efc-90ef-ced018bf3587", + "metadata": {}, + "source": [ + "## Availability of Acceptable StopTimeUpdate Messages \n", + "### % of minutes with available predictions \n", + "* column used: `pct_tu_complete_minutes`\n", + "* This metric is the easiest to achieve. For starters, having information is better than no information.\n", + "* For transit users, **a higher proportion of `% complete minutes` means you are getting predictions for longer stretches of time before the bus arrives**.\n", + "* **Goal:** increase the share of complete minutes.\n", + "* Note: Newmark paper shows that among four CA operators, this metric is fairly easy to reach and operators can even reach up to 90% completeness." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3113197e-d9ca-4ec7-8728-0cbd831410c5", "metadata": { "tags": [] }, "outputs": [], "source": [ - "def format_table(df, title):\n", - " table = (\n", - " GT(df.describe().reset_index())\n", - " .fmt_percent(\n", - " columns=[\"pct_accurate_minutes\", \"pct_complete_minutes\"], \n", - " decimals=1\n", - " ).fmt_number(\n", - " columns = [\n", - " \"avg_prediction_spread_minutes\", \n", - " \"avg_prediction_error_minutes\", \n", - " \"avg_predictions_per_trip\"\n", - " ], decimals=2)\n", - " .cols_label(\n", - " avg_prediction_error_minutes = \"Prediction Error (minutes)\",\n", - " avg_prediction_spread_minutes = \"Prediction Spread / Wobble (minutes)\",\n", - " pct_accurate_minutes = \"% Minutes with Accurate Prediction\",\n", - " pct_complete_minutes = \"% Minutes with Trip Updates\",\n", - " avg_predictions_per_trip = \"# Predictions in 30 Minutes Before Arrival\",\n", - " )\n", - " .tab_options(table_font_size=\"12px\")\n", - " .tab_header(title = title)\n", - " )\n", - " \n", - " return table" + "chart_utils.histogram_line_chart_by_date(\n", + " daily_df2, \n", + " metric_column = \"pct_tu_complete_minutes\",\n", + " legend_color_column = \"service_date\"\n", + ") " ] }, { "cell_type": "code", "execution_count": null, - "id": "f8480f6e-fb7a-4546-8ef5-721d60f52606", + "id": "2f29d438-c0d7-4a82-affc-421702265f07", "metadata": { "tags": [] }, "outputs": [], "source": [ - "d = \"Weekday\"\n", - "format_table(\n", - " gdf1[gdf1.weekday_weekend==d][metric_cols], f\"{d} Descriptives\"\n", - ")" + "chart_utils.histogram_line_chart_by_date(\n", + " daytype_df2, \n", + " metric_column = \"pct_tu_complete_minutes\",\n", + " legend_color_column = \"day_type\"\n", + ") " + ] + }, + { + "cell_type": "markdown", + "id": "46b28310-643a-49ab-a54e-89da1523694b", + "metadata": {}, + "source": [ + "## Simpler Expected Wait Time \n", + "* column used: `avg_prediction_error_minutes`, `prediction_error_label`\n", + "* For transit users, **shorter wait times (lower positive values) without missing the bus (few negative values)** result in more pleasant transit journeys.\n", + "* **Goal:** decrease expected wait time and decrease late predictions.\n", + "* This metric attempts a more generous approach towards determining accuracy, by categorizing `avg_prediction_error_minutes` with the 1-3 min, 3-5 min, and 5+ min thresholds.\n", + " * ontime is between 1 min early to 1 min late" ] }, { "cell_type": "code", "execution_count": null, - "id": "0ece2e2f-4e8b-48c8-94cc-e256edc5a4f1", + "id": "f5d21dfa-98f9-4096-92bc-82d7517d100f", "metadata": { "tags": [] }, "outputs": [], "source": [ - "d = \"Saturday\"\n", - "format_table(\n", - " gdf1[gdf1.weekday_weekend==d][metric_cols], f\"{d} Descriptives\"\n", + "chart_utils.bar_chart_by_date(\n", + " daily_df, \"prediction_error_label\", \n", + " is_stacked=False\n", ")" ] }, { "cell_type": "code", "execution_count": null, - "id": "b32bf05a-2a50-4263-9305-4cac7c720a09", + "id": "90ac6f09-f494-43c3-976d-deb2ddb6d145", "metadata": { "tags": [] }, "outputs": [], "source": [ - "d = \"Sunday\"\n", - "format_table(\n", - " gdf1[gdf1.weekday_weekend==d][metric_cols], f\"{d} Descriptives\"\n", + "chart_utils.bar_chart_by_date(\n", + " daily_df, \"prediction_error_label\", \n", + " is_stacked=True\n", ")" ] }, { "cell_type": "markdown", - "id": "1123ea17-9610-4335-b6e7-014a844aebe9", + "id": "822e608e-4a0e-460b-8831-6b2d31fbb648", "metadata": {}, "source": [ - "### Prediction Accuracy \n", - "\n", - "* Find how \"accurate\" the prediction is, based on whether it falls within the bounds of `-60ln(Time to Prediction+1.3) < Prediction Error < 60ln(Time\n", - "to Prediction+1.5)`, the further out before arrival, the more generous the buffer.\n", - "* In contrast to the `True/False` of whether a prediction is deemed accurate or not, this metric finds the \"error\" in minutes.### Weekday Descriptives\n", - "* Positive values = arrival came **after** the prediction. \n", - "* Time period: 30 minutes before the arrival at stop" + "### Prediction Error for Weekday Stops Map" ] }, { "cell_type": "code", "execution_count": null, - "id": "14dc22a6-1834-47d7-b89f-8b670b3f31bf", - "metadata": { - "tags": [] - }, + "id": "e276cfcf-cecc-42f8-96cc-832f5ee5d527", + "metadata": {}, "outputs": [], "source": [ - "plot_col = \"avg_prediction_error_minutes\"\n", - "\n", - "boxplot = chart_utils.make_boxplot_by_day_type(\n", - " gdf1, plot_col, \"Avg Prediction Error (minutes)\")\n", - "\n", - "boxplot" + "chart_utils.make_map(daytype_df, \"prediction_error_label\")" ] }, { "cell_type": "markdown", - "id": "083e4039-4644-433b-9d9f-fe7191f35050", + "id": "11b3a832-b531-48d2-868a-c91906b33876", "metadata": {}, "source": [ - "### Availability of StopTimeUpdate Messages \n", + "## Prediction Inconsistency \n", "\n", - "* How many predictions are we getting for each stop (per trip, to normalize) in the 30 minute period before arrival?\n", - "* Similar to the `True/False` whether there were at least 2 predictions per minute, this gets the counts (3 predictions per minute, for 30 minutes, yields 90 predictions).\n", - "* Time period: 30 minutes before the arrival at stop" + "* column used: `avg_prediction_spread_minutes`\n", + "* This metric wants to **distinguish between consistent but inaccurate and inconsistent but accurate** prediction patterns.\n", + " * Consistent predictions contribute to low user trust in the information generally.\n", + " * Inconsistent but accurate predictions fluctuate, making it difficult for trip planning ahead of time. However, the up-to-date information can alleviate the discomfort. [Research](https://www.sciencedirect.com/science/article/abs/pii/S0965856416303494) has shown that waiting time is negatively perceived, but having real-time information communicated reduces that perceived waiting time. \n", + "* For transit users, **less inconsistency (lower positive values)** mean fewer fluctuations in predictions.\n", + "* **Goal:** Tighten the box with values closer to zero." ] }, { "cell_type": "code", "execution_count": null, - "id": "e3254f92-e8d7-46bb-9be6-03248a8f4283", + "id": "6e321226-07b9-4041-8402-4d501e96df98", "metadata": { "tags": [] }, "outputs": [], "source": [ - "plot_col = \"avg_predictions_per_trip\"\n", - "# in the 30 minute period before arrival\n", - "\n", - "boxplot = chart_utils.make_boxplot_by_day_type(\n", - " gdf1, plot_col, f\"# Predictions 30 min before Arrival\")\n", - "\n", - "boxplot" + "chart_utils.boxplot_by_date(daily_df, \"avg_prediction_spread_minutes\")" ] }, { "cell_type": "markdown", - "id": "c6da2140-c819-4619-a098-fbde87cdf9d7", + "id": "aeb6a835-1ba8-4a7e-9729-258f7612b868", "metadata": {}, "source": [ - "## Aggregated Stops by Day Type \n", + "## Descriptives Table with Detailed Percentiles\n", "\n", - "Maps show the metrics by only **weekday** so far." + "Take a look at percentiles for the metrics we have, so we can be comfortable moving towards a day type aggregation (weekday/Sat/Sunday) in the future." ] }, { "cell_type": "code", "execution_count": null, - "id": "9bea753c-d402-4585-9c45-f6b3d52a7d91", - "metadata": {}, + "id": "6cc5c3b6-2d45-4a3b-984d-037d2892c595", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "#del gdf1\n", - "gdf2 = viz_stop_metrics.import_stop_df(\n", - " is_daily = False, filters = [[(\"name\", \"==\", name)]]\n", - ")" + "metric_cols = [\n", + " \"avg_prediction_error_minutes\",\n", + " \"pct_tu_accurate_minutes\",\n", + " \"pct_tu_predictions_early\",\n", + " \"pct_tu_predictions_ontime\", \n", + " \"pct_tu_predictions_late\",\n", + " \"n_predictions\",\n", + " \"avg_prediction_spread_minutes\",\n", + " \"pct_tu_complete_minutes\",\n", + "]" ] }, { - "cell_type": "markdown", - "id": "5de8c0f0-515c-49de-9703-95e1a09ae2b5", - "metadata": {}, + "cell_type": "code", + "execution_count": null, + "id": "40eee46e-1b52-45f4-8c93-71f23a7e9984", + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ - "### Prediction Inconsistency (Wobble)\n", - "* If the prediction is changing from minute to minute, a large spread would show up.\n", - "* If the prediction is fairly consistent, we would see small spread.\n", - "* It is possible for the predicted stop arrival to be **consistent, yet inaccurate** or **inconsistent, yet fairly accurate as it approaches the stop**.\n", - "* These touch on different transit user experiences.\n", - " * Inconsistent predictions are difficult for trip planning in real-time, though keeping customers up-to-date with reliable stop arrivals can alleviate the experience.\n", - " * Consistently inaccurate predictions are difficult to plan around and can result in low trust." + "def format_table(\n", + " df: pd.DataFrame, title: str\n", + ") -> GT:\n", + " \"\"\"\n", + " Quickly format table of descriptives\n", + " \"\"\"\n", + " table = (\n", + " GT(df)\n", + " .fmt_percent(\n", + " columns=[\"pct_tu_accurate_minutes\", \"pct_tu_complete_minutes\",\n", + " \"pct_tu_predictions_early\", \"pct_tu_predictions_ontime\",\n", + " \"pct_tu_predictions_late\"\n", + " ], \n", + " decimals=1\n", + " ).fmt_number(\n", + " columns = [\n", + " \"avg_prediction_spread_minutes\", \n", + " \"avg_prediction_error_minutes\", \n", + " ], decimals=2\n", + " ).fmt_number(\n", + " columns = [\"n_predictions\"], \n", + " decimals=0,\n", + " )\n", + " .cols_label(\n", + " avg_prediction_error_minutes = \"Prediction Error (minutes)\",\n", + " avg_prediction_spread_minutes = \"Prediction Spread / Wobble (minutes)\",\n", + " pct_tu_accurate_minutes = \"% Minutes with Accurate Prediction\",\n", + " pct_tu_complete_minutes = \"% Minutes with Trip Updates\",\n", + " pct_tu_predictions_early = \"% Early Predictions\",\n", + " pct_tu_predictions_ontime = \"% OnTime Predictions\",\n", + " pct_tu_predictions_late = \"% Late Predictions\",\n", + " n_predictions = \"Total Predictions\",\n", + " )\n", + " .tab_options(table_font_size=\"12px\")\n", + " .tab_header(title = title)\n", + "\n", + " )\n", + " \n", + " return table" ] }, { "cell_type": "code", "execution_count": null, - "id": "d62267f5-1b1a-4641-917c-7f2dc6826a41", - "metadata": {}, + "id": "f8480f6e-fb7a-4546-8ef5-721d60f52606", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "stop_grouping_cols = [\"name\", \"weekday_weekend\", \"stop_id\", \"stop_name\"]\n", - "\n", - "plot_col = \"avg_prediction_error_minutes\"\n", - "\n", - "chart_utils.make_layered_histogram(\n", - " gdf2[stop_grouping_cols + [plot_col]],\n", - " plot_col,\n", - " step_size=0.25 # 15 sec\n", - ").properties(\n", - " title = \"Avg Prediction Error (minutes)\",\n", + "# get all the percentiles, except counts, because we need to format separately\n", + "format_table(\n", + " daytype_df[\n", + " daytype_df.day_type==\"Weekday\"\n", + " ][metric_cols].describe(\n", + " prep_data.PERCENTILE_LIST\n", + " ).drop(index=\"count\").reset_index(), \n", + " \"Weekday Descriptives\"\n", ")" ] }, { "cell_type": "code", "execution_count": null, - "id": "c49367da-b726-42c1-bbb4-85a4ebb58a0e", + "id": "e417acd8-0a10-4b42-8a38-bb90242341be", "metadata": { "tags": [] }, "outputs": [], "source": [ - "plot_col = \"pct_accurate_minutes\"\n", - "\n", - "chart_utils.make_layered_histogram(\n", - " gdf2[stop_grouping_cols + [plot_col]],\n", - " plot_col,\n", - " step_size=0.05 \n", - ").properties(\n", - " title = \"% Accurate Predictions\",\n", - ")" + "# format the counts row by making it all numbers\n", + "format_table(\n", + " daytype_df[\n", + " daytype_df.day_type==\"Weekday\"\n", + " ][metric_cols].describe().head(1), \n", + " \"\"\n", + ").fmt_number(decimals=0)" ] }, { "cell_type": "markdown", - "id": "34a3cb6a-ffa7-495e-ac9b-73712277e60d", + "id": "30dc58b8-dbf0-46c4-9b2a-19762f034568", "metadata": {}, "source": [ - "### Accurate Predictions" + "## Priority Stops\n", + "\n", + "These are the weekday stops identified with either:\n", + "* over 25% of predictions late\n", + "* average prediction error of 3 minutes early *or* late\n", + "\n", + "It will be possible for operators to not have any stops that meet this threshold." ] }, { "cell_type": "code", "execution_count": null, - "id": "3d75ec29-f7ee-437e-9177-0998a8cac27a", - "metadata": { - "tags": [] - }, + "id": "eecec474-626c-417c-bd2f-1a414a2a926a", + "metadata": {}, "outputs": [], "source": [ - "plot_col = \"pct_accurate_minutes\"\n", - "m = chart_utils.stop_map_of_metric(gdf2[gdf2.weekday_weekend==\"Weekday\"], plot_col)\n", - "m" + "keep_cols = [\n", + " \"month\", \"year\", \"day_type\", \n", + " \"stop_id\", \"stop_name\",\n", + " \"pct_tu_predictions_early\", \"pct_tu_predictions_ontime\", \"pct_tu_predictions_late\",\n", + " \"avg_prediction_error_minutes\", \"avg_prediction_spread_minutes\",\n", + " \"prediction_error_label\", \"n_predictions\",\n", + " \"geometry\"\n", + "]\n", + "\n", + "priority_df = daytype_df[\n", + " (daytype_df.day_type == \"Weekday\") & ( \n", + " (daytype_df.pct_tu_predictions_late > 0.25) & \n", + " (daytype_df.avg_prediction_error_minutes.abs() > 3) \n", + " )\n", + "][keep_cols]\n", + "\n", + "if len(priority_df) > 0:\n", + "\n", + " m = chart_utils.plot_basic_map(\n", + " priority_df, \n", + " plot_col = \"prediction_error_label\", \n", + " colorscale = chart_utils.FULL_CATEGORICAL_COLORS\n", + " )\n", + " \n", + "else:\n", + " m = \"No stops fit this criteria, and that's a good thing!\"\n", + "\n", + "display(m)" ] }, { "cell_type": "code", "execution_count": null, - "id": "9eefa43c-097f-4fde-aa79-c6e5f1fb2cff", + "id": "bafe6fe3-b98a-48c1-b9bb-6b2d433d1328", "metadata": {}, "outputs": [], "source": []