population_impact_summary

site_solutions.SolutionComparator.population_impact_summary(
    matrix=None,
    demand=None,
    meaningful_change_threshold=0.0,
    config_a=None,
    config_b=None,
    return_per_region=False,
    as_dict=False,
)

How many people’s journey actually changed between set_a and set_b, and by how much – a per-demand-location diff, rather than only the region-wide shift in weighted_average. A weighted_average shift dilutes a real, large, local effect across everyone else who is unaffected by it; this answers “how many people are better/worse off, and by how much” directly.

self.set_a is treated as the reference/baseline and self.set_b as the candidate – e.g. SolutionComparator(baseline, candidate), where baseline is typically built with SiteProblem.evaluate_baseline(). This is unlike get_metric_summary()/compare_site_allocation()’s difference column, which is set_a - set_b with no particular baseline/ candidate relationship implied – but it does not conflict with it: every value returned here is a positive magnitude, with direction carried by the bucket name (_improved/_worsened) rather than by sign, so there is no ambiguous sign convention to reconcile.

Parameters

Name Type Description Default
matrix str Label of a secondary travel matrix registered via add_secondary_travel_matrix(). Diffs that matrix’s own min_cost__<label> column instead of the primary matrix’s. None
demand str Label of a secondary demand scenario registered via add_secondary_demand(). Weights the diff by that scenario’s demand instead of the primary demand data. None
meaningful_change_threshold float A region’s cost must move by strictly more than max(meaningful_change_threshold, 1e-9) to count as improved or worsened; anything smaller (including floating-point noise at the default 0.0) is unchanged. 0.0
config_a dict Keyword arguments forwarded to _select_solution() for set_a/set_b respectively (e.g. {"solution_rank": 2}), selecting which solution from each set to compare. Default to {"solution_rank": 1}, matching compare_site_allocation(). None
config_b dict Keyword arguments forwarded to _select_solution() for set_a/set_b respectively (e.g. {"solution_rank": 2}), selecting which solution from each set to compare. Default to {"solution_rank": 1}, matching compare_site_allocation(). None
return_per_region bool If True, also return a per-region DataFrame (baseline_cost, current_cost, demand if available, delta, bucket, previous_site/new_site – that region’s closest site under set_a/set_b respectively, omitted if selected_site isn’t on both sides for some reason) for drill-down, indexed by demand-location ID. False
as_dict bool If False (the default), the summary is returned as a single- column pandas.DataFrame (index = metric name, column = "value") – pandas’ own display formatting keeps this readable in a notebook, unlike a bare dict (numpy >=2.0 reprs its float scalars as e.g. np.float64(46907.0), which shows through verbatim on a plain dict). Pass as_dict=True for the original dict, e.g. to pull out a single value with impact["demand_improved"] for further computation. False

Returns

Name Type Description
pandas.DataFrame (or dict if as_dict=True), or a 2-tuple of
(summary, per-region DataFrame) if return_per_region=True regions_improved/regions_worsened/regions_unchanged (counts); demand_improved/demand_worsened/ demand_unchanged (NaN if no demand data is registered); proportion_demand_improved/proportion_demand_worsened; total_demand; mean_reduction_among_improved/ mean_increase_among_worsened (demand-weighted, positive magnitudes); max_reduction/max_increase (positive). See lokigi.utils._population_impact_metrics for the full definition – this method is a thin wrapper around it that handles solution selection and demand-location alignment. Also, whenever a coverage threshold was assessed on both set_a and set_b (i.e. within_threshold isn’t all-NaN on either side): demand_newly_covered/demand_newly_uncovered and regions_newly_covered/regions_newly_uncovered – the GROSS number of people/regions crossing the coverage threshold in each direction (not the net change in proportion_within_coverage_threshold, which can mask simultaneous gains and losses). demand_* are NaN if no demand data is registered; the whole group of four keys is simply absent (not NaN) if no coverage threshold was ever assessed.

Raises

Name Type Description
ValueError If demand names an unregistered secondary demand scenario, or if set_a and set_b’s selected solutions were evaluated against different demand locations (their problem_dfs must share the exact same demand-location ID set).
Back to top