Headway
2

Code and data line · 02 of 13

Data pipeline

make_data.py downloads one month of New York taxi trips and turns them into a reproducible training set. The sample and every generated instance use seed 42.

Source
NYC TLC, yellow taxi
Period
January 2022, weekdays
Raw trips
2,463,931
Kept
300,000 between the 20 busiest zones
Split
by day: train Jan 3 to 19, validation 20 to 21, test 24 to 31
Seed
42

make_data.py

Also: delivery/data.py delivery/instances.py delivery/config.py

make_data.py
"""Download + preprocess the NYC TLC data and build the generated instance set.

    python make_data.py            # uses cached raw files if present
    python make_data.py --force    # re-download

Outputs: data/processed/* (gitignored), tests/fixtures/* (small, committed),
instances/*.json (generated orders, committed).
"""
import argparse
import json
import shutil

from delivery import config as C
from delivery import data as D
from delivery.instances import generate_instance


def disk_guard(min_free_mb=150):
    free = shutil.disk_usage(C.ROOT).free / 1e6
    print(f"  free disk: {free:,.0f} MB")
    if free < min_free_mb:
        raise SystemExit(f"stopping: less than {min_free_mb} MB free on the project drive")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--force", action="store_true")
    args = ap.parse_args()

    print("[1/5] download"); disk_guard()
    paths = D.download(force=args.force); disk_guard()

    print("[2/5] read + check schema")
    raw = D.load_raw_trips(paths["trips"])
    import pandas as pd
    lookup = pd.read_csv(paths["lookup"])
    cents = D.zone_centroids(paths["shapes"])
    print(f"  {len(raw):,} raw rows, columns OK: {D.NEEDED_COLS}")

    print("[3/5] filter, top zones, sample, split by day")
    trips, zones, stats = D.preprocess(raw, lookup, cents)
    for k, v in stats.items():
        if not isinstance(v, list):
            print(f"  {k:>22}: {v:,}")
    print("  zones:", ", ".join(zones.zone))

    print("[4/5] zone-pair mean distance (train only)")
    dist, cnt, fit = D.pair_distance_matrix(trips, zones)
    stats["pair_distance_fallback"] = fit
    tr = trips[trips.split == "train"]
    g = tr.groupby(["pu", "do", "hour"]).size()
    stats["rare_cells_lt5_train"] = int((g < 5).sum())
    stats["cells_possible"] = len(zones) ** 2 * 24
    stats["cells_seen_train"] = int(len(g))
    night = tr[tr.hour < 6].groupby(["pu", "do"]).size()
    stats["night_pairs_seen_train"] = int(len(night))
    D.save_processed(trips, zones, dist, cnt, stats)
    D.write_fixture(trips, zones, dist)
    print(f"  unseen pairs filled by fit: {fit['unseen_pairs']}; "
          f"(pu,do,hour) cells seen {stats['cells_seen_train']}/{stats['cells_possible']}, "
          f"rare (<5 trips) {stats['rare_cells_lt5_train']}")

    print("[5/5] generated instance set")
    C.INSTANCES.mkdir(exist_ok=True)
    weights = zones.sort_values("idx").n_dropoffs.values
    manifest = []
    for n in (15, 20, 30):
        for seed in range(10):
            inst = generate_instance(n, seed, n_zones=len(zones), zone_weights=weights)
            p = C.INSTANCES / f"{inst.name}.json"
            inst.save(p); manifest.append(p.name)
    (C.INSTANCES / "manifest.json").write_text(json.dumps(manifest, indent=1))
    print(f"  wrote {len(manifest)} instances to instances/")
    disk_guard()


if __name__ == "__main__":
    main()