Skip to content

Detect Joint Trips

Detect joint trips among household members using similarity matching.

Identifies trips where multiple household members traveled together by comparing origin-destination-time similarity using either strict buffer thresholds or Mahalanobis distance.

Algorithm

Phase 1: Household Pre-filtering

  1. Filter to households with 2+ members who took trips
  2. Reduces search space to only households where joint trips are possible

Phase 2: Pairwise Distance Calculation

  1. Within each multi-person household, compute pairwise distances between all trip combinations using 4D space:
    • Origin coordinates (o_lon, o_lat)
    • Destination coordinates (d_lon, d_lat)
    • Departure time
    • Arrival time
  2. Store distances in condensed matrix format for efficiency

Phase 3: Similarity Filtering

Buffer Method:

  • Filter trip pairs where:
    • Spatial distance (haversine) ≤ space_threshold_meters for both origin AND destination
    • Absolute time difference ≤ time_threshold_minutes for both departure AND arrival
  • Simple, interpretable thresholds

Mahalanobis Method:

  • Calculate statistical distance using covariance matrix:
    • Accounts for correlated variations in space/time
    • Keeps pairs whose distance is below a cutoff set by confidence_level (see JointTripConfig.get_distance_threshold)
  • More sophisticated, calibrated to actual joint trip patterns
  • Can capture joint trips more flexibly than fixed thresholds

Phase 4: Clique Detection

  1. Build graph where nodes = trips, edges = similar trip pairs
  2. Detect maximal cliques (groups of mutually-similar trips)
  3. Handle overlapping cliques by selecting disjoint set with maximum coverage
  4. Each clique represents one joint trip event
  5. Ensures transitivity: if A travels with B, and B with C, then A,B,C form one joint trip

Phase 5: Joint Trip Aggregation

  1. Assign unique joint_trip_id to each clique
  2. Create joint_trips table, one row per joint trip:
    • joint_trip_id, hh_id, travel_date
    • num_joint_travelers: number of member linked trips
    • survey_complete: true only if every member trip is complete
  3. Mark each member linked trip with its joint_trip_id
  4. Validate against reported num_travelers field if available
Notes
  • Only compares trips within one household date (joint trips across households, or across the survey's day boundary, not detected)
  • Mahalanobis method requires calibrated covariance matrix (see scripts/calibrate_joint_trip_covariance.py)
  • Clique detection prevents false positives from partial or coincidental matches
  • Handles survey reporting errors where respondents over/under-report number of travelers
  • Non-joint trips retain joint_trip_id = NULL

Example

Example
- name: detect_joint_trips
  params:
    method: mahalanobis
    covariance: [10000, 10000, 100, 100]  # 100 m, 100 m, 10 min, 10 min std devs
    confidence_level: 0.90

Settings

Key Type Default Meaning
method buffer or mahalanobis required Detection method: buffer (strict) or mahalanobis (statistical)
time_threshold_minutes number, ≥ 0 15.0 Maximum time difference in minutes for buffer method
space_threshold_meters number, ≥ 0 100.0 Maximum spatial distance in meters for buffer method
covariance list or null required Diagonal (4 values) or full (4x4) covariance matrix in units [origin_m^2, dest_m^2, depart_min^2, arrive_min^2]. Required for mahalanobis; null for buffer. The empirical variance of BATS 2023 household joint trips is about diagonal [7000, 7000, 20, 20]: origin ~84m std dev (7142 m² var), dest ~84m (7089 m²), depart ~4.7min (22 min²), arrive ~4.6min (21 min²).
confidence_level number, > 0, < 1 required Strictness of the mahalanobis cutoff (mahalanobis method only). Higher = stricter. It reads backward from the usual meaning of confidence and is not the share of joint pairs kept. See get_distance_threshold.
log_discrepancies true / false false If True, log DEBUG-level details when detected joint trip size differs from reported num_travelers

Configuration models and calibration utilities for joint trip detection.

ALGORITHM DESIGN NOTES:

This module implements joint trip detection using two methods:

  1. BUFFER METHOD (debugging/calibration): Strict AND across four dimensions: origin distance, destination distance, departure time, arrival time. Uses Haversine for spatial matching and absolute time differences. All four must pass thresholds.

  2. MAHALANOBIS METHOD (production): Statistical distance on 4D vector [Δorigin_m, Δdest_m, Δdepart_min, Δarrive_min]. Supports diagonal covariance (assumes independence) or full covariance matrix (captures correlations). More robust to GPS noise via compensation.

CALIBRATION WORKFLOW:

  1. Run detection with method='buffer' to find high-confidence joint trips
  2. Use estimate_covariance_from_detected_pairs() to analyze buffer results
  3. Helper scans threshold range and recommends optimal distance_threshold
  4. Copy diagonal or full covariance to config for production runs
  5. Run detection with method='mahalanobis' using calibrated parameters

TEMPORAL OVERLAP:

Trips must have overlapping time windows to be joint (travelers physically together). Pre-filter: max(depart_A, depart_B) <= min(arrive_A, arrive_B)

Code: processing.joint_trips