Skip to content

Extract Tours

Extract hierarchical tour structures from linked trip data.

Builds tour and subtour structures from linked trip sequences using spatial and temporal patterns. See module docstring for complete algorithm description.

Example

Example
- name: extract_tours
  params:
    spatial_gap_threshold_meters: 1000.0
    buffer_meters: 300  # how near a trip end must be to a habitual location to match it

Settings

extraction

Key Type Default Meaning
mode_hierarchy list built in Ordered list of mode types by priority - later in list = higher priority
purpose_priority_by_personcat mapping built in Priority order for determining tour purpose by person category (lower = higher priority). All non-HOME purposes must be explicitly defined. Used only when tour_purpose_method='hierarchy'.
tour_purpose_method score or hierarchy score How to pick a tour's purpose from its trips: 'score' (duration-weighted, highest score wins) or 'hierarchy' (priority rank, duration as tie-breaker only).
purpose_score_weights mapping built in Purpose ceiling weight W by person category for the scoring method (higher = more important as a tour anchor). Sets the purpose ranking; the one hand-tuned knob.
purpose_score_halfmax mapping built in Half-saturation duration h in minutes by purpose for the scoring method: the duration at which a purpose reaches half its ceiling W. Discretionary purposes use their BATS-2023 typical activity duration; mandatory purposes use a low establishment threshold; escort is set high so it only wins a pure escort tour.
check_multiday_gaps true / false false If True, reset tour boundaries when day_gap > 1 between trips.
detect_usual_workplace true / false false If True, only detect work-based subtours from 'usual workplace' (coordinate match to work_lat/work_lon).
spatial_gap_threshold_meters number required A tour is flagged SPATIAL_GAP when any internal junction has a gap greater than this (meters) between one trip's destination and the next trip's origin - i.e. a missing leg the tour extractor would otherwise silently weld into one 'survey_complete' tour. BATS uses 1 km, which catches genuine teleports while ignoring same-place geocoding jitter.
default_activity_duration_minutes number 240.0 Default activity duration in minutes for last trip of day when calculating duration tie-breaker (legacy: 4 hours).

habitual_match

Key Type Default Meaning
at_address_meters number, > 0 100.0 Distance in metres within which a trip end is at the person's own primary home whatever its purpose. At their doorstep the purpose describes what they are doing -- exercising, working from home, dropping someone off -- not a different place, and refusing it welds two tours into one. Further out the purpose has to agree, because that is where the corner shop is. Homes only: a lunch place can be metres from the office door.
buffer_meters number, > 0 required Distance in metres within which two points are the same place. It groups stops into one location, decides a found place is a reported one, decides a trip end is at a location, and decides a tour came back to its primary destination. Reported locations are geocoded from what the respondent typed while trip ends are GPS, and people walk about a site, so it is a few hundred metres rather than a building's width. Set it to suit the survey's location noise.

A block's keys may also sit flat under params:; see Configuring a step.

Determining tour purpose

A tour visits several places; the extractor picks which one is the tour (home → work → lunch → work → home is a work tour). The purpose is chosen from the non-final destinations, using their purpose and activity duration (time spent before the next trip). Two methods, set by tour_purpose_method.

Hierarchy ("hierarchy")

Each purpose has a fixed priority rank by person category (purpose_priority_by_personcat); the highest-ranked purpose present wins, duration only breaks ties within a rank. Predictable, but priority is absolute: a 2-minute work stop outranks a 4-hour shop.

Scoring ("score", default)

Duration and purpose trade off, so a long activity can outweigh a brief higher-priority one. Each candidate scores

score = W · x / (x + h)

x = activity duration (min); W = ceiling weight; h = half-saturation duration (score = W/2 at x = h, rising toward W). Highest score wins.

Tour purpose scoring functions

  • W (purpose_score_weights) = the priority order, with escort demoted to the bottom. Only ratios matter, and it stays per person category (a work+school day resolves to work for a worker, school for a student).
  • h (purpose_score_halfmax) = the median dwell for discretionary purposes; a fixed threshold for the rest.
purpose W h (min) h source
Work, School 10 / 8 20 fixed low threshold — a real visit is sticky; below it is a drive-by. Not the ~5 h median, which would demote short real visits.
Shop, Meal, Social, Errand 4 18, 26, 56, 29 BATS-2023 median dwell — duration picks the primary discretionary activity
Escort 2 200 fixed high — suppressed; only wins a pure drop-off-then-home tour
Overnight 0 — never wins

h must differ by purpose: with a shared h, scores become constant multiples and duration cancels, collapsing back to the hierarchy.

The scoring-function figure is regenerated from the config defaults by scripts/plot_purpose_scoring.py.

Effect vs the hierarchy

Switching BATS-2023 from hierarchy to scoring leaves work and school almost unchanged (the sticky mandatory h), collapses escort (drop-off-then-activity tours move to the real activity), and re-sorts discretionary tours by duration.

Tour purpose under hierarchy vs scoring, BATS-2023

This figure is a BATS-2023 snapshot, regenerated from the committed counts in docs/assets/data/ by scripts/plot_purpose_reclassification.py.

Code: processing.tours