two_step_floating_catchment

site.SiteProblem.two_step_floating_catchment(
    supply_col,
    catchment_size=None,
    distance_decay=None,
    site_names=None,
    site_indices=None,
    matrix=None,
    demand=None,
    per_capita=1,
    return_site_ratios=False,
)

Two-step floating catchment area (2SFCA) accessibility score.

Unlike binary threshold coverage, 2SFCA accounts for competition: a demand region near a site that is also the closest option for many other regions gets less credit for that site than a region near an uncontested one. Scores an arbitrary set of sites directly – no solve() is required, so it can describe any subset of candidate_sites as a baseline, e.g. only the sites that are already open, via site_names/site_indices. With neither argument, every registered candidate site is scored – the right default when the candidate pool is the current network, but not when it also includes not-yet-built proposals, in which case pass the currently-open subset explicitly.

Parameters

Name Type Description Default
supply_col str Column in candidate_sites holding each site’s supply quantity (e.g. number of GPs, beds, weekly appointment slots). Named at call time rather than registered via add_sites(), so the same problem can be scored under different supply definitions without re-adding sites. required
catchment_size float Classic 2SFCA’s hard catchment threshold d0, in the travel matrix’s registered units. A site is “in catchment” for a demand region if the travel cost between them is <= catchment_size, with weight 1; beyond it, weight 0. Mutually exclusive with distance_decay – exactly one of the two must be given. None
distance_decay list of (float, float) or dict A softer catchment than a single hard cutoff. Two forms: - A list of (upper_bound, weight) pairs – Enhanced 2SFCA (E2SFCA, Luo & Qi 2009) step-decay bands, e.g. [(10, 1.0), (20, 0.68), (30, 0.22)] – this is not just an illustrative example: it is Luo & Qi’s own published “weight set 1” for 0-10/10-20/20-30 minute zones (their sharper “weight set 2” is [(10, 1.0), (20, 0.42), (30, 0.09)]). Need not be pre-sorted; a cost beyond the largest upper_bound gets weight 0. catchment_size=<upper_bound> with a single band of weight 1 is exactly equivalent to classic 2SFCA. - A dict describing a continuous decay kernel. Two forms: {"method": "gaussian", "catchment_size": d0, "bandwidth": sigma} – Dai (2010)’s truncated Gaussian: weight 1 at distance 0, weight 0 at catchment_size (the truncation radius), decaying continuously in between; or {"method": "power", "catchment_size": d0, "scale": s, "alpha": a, "min_dist": m=0} – the classic gravity-model decay, weight(d) = (max(d, min_dist)/scale)**alpha, truncated to 0 beyond catchment_size (alpha is not implicitly negative; pass a negative value for decay). Parameterisation matches pysal/access’s weights.gravity(scale, alpha, min_dist). None
site_names list of str None
site_indices list of int The site set to score. At most one may be given. If neither is given, every candidate site is scored. None
matrix str Label of a secondary travel matrix registered via add_secondary_travel_matrix(). Scores accessibility under that matrix’s travel costs instead of the primary matrix’s. None
demand str Label of a secondary demand scenario registered via add_secondary_demand(). Scores accessibility under that scenario’s demand instead of the primary demand data (both catchment_demand and demand in the returned frames reflect the chosen scenario). Combines freely with matrix=. None
per_capita float Multiplier applied to the accessibility column, e.g. 1_000 to express supply per 1,000 head instead of raw supply units per head. Does not affect site_frame. Must be a positive number. 1
return_site_ratios bool If True, also return the step-1 per-site table – useful for finding which site is driving an implausible regional score. False

Returns

Name Type Description
pandas.DataFrame Per demand region, indexed by demand location ID: accessibility (supply units per head, x per_capita), n_sites_in_catchment, demand.
pandas.DataFrame Only if return_site_ratios=True. Per site, indexed by site name: supply, catchment_demand, n_regions_in_catchment, ratio.

Raises

Name Type Description
ValueError If both site_names and site_indices are given, if per_capita is not a positive number, if neither or both of catchment_size/distance_decay are given, if no demand data is registered, if supply_col is missing or contains a null/negative value for a scored site, if matrix is not a registered secondary travel matrix label, if demand is not a registered secondary demand scenario label, or if distance_decay fails its own validation (see above).
TypeError If supply_col is not numeric.
IndexError If site_indices are out of range.
KeyError If site_names are not found in the travel matrix or candidate_sites.

Notes

A site with no demand within its catchment has an undefined (NaN) supply-to-demand ratio and is excluded from every region’s accessibility score, with a warning naming it. A demand region with no site in its catchment correctly scores accessibility == 0 (a real “no supply available” result, not a missing value) – these two zero-like cases are deliberately kept distinguishable. n_regions_in_catchment/n_sites_in_catchment count non-zero-weight membership, so this holds under distance_decay too.

accessibility obeys sum(demand * accessibility) == sum(supply) (before per_capita scaling) whenever every scored site has at least one region in its catchment, since the sum of demand-weighted ratios is exactly the supply that produced them – true regardless of whether catchment_size or distance_decay was used.

Back to top