site_allocation_summary

site.SiteSolutionSet.site_allocation_summary(
    by='demand',
    sort_by=None,
    solution_rank=1,
    site_names=None,
    site_indices=None,
    matrix=None,
    demand=None,
)

Per-site summary of a chosen solution: the share of demand (or of regions) whose closest selected site is each site, and the average travel cost incurred by that group.

Answers “how much work does this site actually do, and how far do the people it serves have to travel?” for one chosen solution – useful both for weighing up whether an additional site earns its cost (a site closest to only a small share of demand is a weak case for opening, even where it visibly lowers the average travel time), and for comparing how consolidating or closing sites changes typical travel distance for the people affected.

Parameters

Name Type Description Default
by (demand, regions) Basis for the proportion and average_travel_cost columns. “demand” weights each region by the demand registered via add_demand(), so average_travel_cost is the demand-weighted mean travel cost among a site’s closest regions – the same weighting as the solution-level weighted_average. “regions” counts every region equally, matching unweighted_average. Follows the same people-vs-places naming rule as the coverage metrics (see EvaluatedCombination.return_solution_metrics): unqualified means demand-weighted. The two coincide when demand is uniform, including when add_demand() was never called. "demand"
sort_by str None
solution_rank int 1
site_names list None
site_indices list Solution selection, as in plot_best_combination. Priority is site_indices > site_names > sort_by/solution_rank. None
matrix str Label of a secondary travel matrix registered via add_secondary_travel_matrix(). Summarises allocation, and computes average_travel_cost, under that matrix’s own selected_site__<label> / min_cost__<label> columns instead of the primary matrix’s. None
demand str Label of a secondary demand scenario registered via add_secondary_demand(). Computes allocated_demand and (for by="demand") proportion / average_travel_cost under that scenario’s demand instead of the primary demand data. Combines freely with matrix=. None

Returns

Name Type Description
pandas.DataFrame One row per site in the chosen solution, indexed by site name (“site”) in canonical site-index order. Columns: n_regions, allocated_demand (omitted when no demand data is registered), proportion (sums to 1.0 across the frame, UNLESS the solution has unreachable demand – see Notes), and average_travel_cost (in the travel matrix’s registered unit – e.g. minutes, or miles if the matrix was built from distances rather than times).

Raises

Name Type Description
ValueError If by is not “demand” or “regions”, or if by="demand" but no demand column is registered on the problem (see Notes).

Notes

Every selected site appears, including any that is closest to no region at all – it gets an explicit 0 row in n_regions and proportion rather than being dropped. That case is usually the finding being looked for, so silently losing it would defeat the point of the method. average_travel_cost is NaN for such a site rather than 0: there is no travel cost to average over zero regions, and 0 would misleadingly read as “instant to reach”.

Regions exactly equidistant from two selected sites are assigned to one of them, not split: the underlying allocation uses DataFrame.idxmin, and its candidate columns are ordered by canonical site index, so exact ties go to the lowest-indexed site. Deterministic across runs, but arbitrary – exact ties are rare on real travel matrices and common on synthetic ones.

average_travel_cost was inspired by work from Gill Baker, who used average travel distance per patient – split by which site was closest – to show that centralising services onto fewer sites would roughly double typical travel distance for patients, while adding a third site offered only limited benefit over the existing two.

A demand location with no feasible journey to any selected site (add_travel_matrix(allow_missing=True)) has a missing (selected_site is not a value) rather than a real site, so it cannot appear in any site’s row – it is excluded from n_regions/allocated_demand/proportion entirely rather than attributed to whichever site happens to be nearest-but- unreachable. proportion then sums to less than 1.0 by exactly that share; the solution’s own regions_unreachable/demand_ unreachable/proportion_demand_unreachable (return_solution_ metrics()) account for what’s missing. 0 for every problem that never opts into allow_missing.

Back to top