Spatial network aggregation

Aggregate flows using a mapping that assigns every source zone to exactly one target group. Zones provides validated territorial mappings; Mobility can produce derived provincial OD tables directly. For a small example preserving internal flows, see Network examples.

  • aggregate_od_network() groups an OD table before creating its sparse matrix.

  • aggregate_network() groups an existing sparse network.

  • Flows within the same target group become self-loops and are retained by default.

  • The audit records internalized flow and any self-loop weight removed.

  • Fractional zone splitting and automatic conversion between zoning versions are not supported.

Aggregate an OD table

pyspainmobility.network.spatial.aggregate_od_network(data: str | Path | DataFrame | DataFrame | LazyFrame, mapping: Mapping[object, object] | DataFrame | DataFrame | Path | str, *, spec: NetworkSpec | None = None, source_column: str = 'source_id', target_column: str = 'target_id', target_node_ids: Sequence[object] | None = None, target_node_index: NodeIndex | None = None, self_loops: str = 'keep') → SparseMobilityNetwork[source]

Aggregate processed OD data spatially in Polars before CSR creation.

This is the preferred route when the OD table is still available: joins and aggregation happen in the tabular engine, avoiding an intermediate fine-resolution adjacency matrix. It has the same mapping and flow-audit guarantees as aggregate_network().

Parameters:
  • data (str, pathlib.Path, pandas.DataFrame, polars.DataFrame or polars.LazyFrame) – Processed OD table or Parquet input, as in build_network().

  • mapping (mapping, pandas.DataFrame, polars.DataFrame or Parquet path) – One source-to-target pair per source zone, covering every OD endpoint.

  • spec (NetworkSpec, optional) – Source columns, weight field and source-zone self-loop policy.

  • source_column (str) – Mapping columns. Defaults are 'source_id' and 'target_id'.

  • target_column (str) – Mapping columns. Defaults are 'source_id' and 'target_id'.

  • target_node_ids (sequence, optional) – Complete target-node order, including any target isolates.

  • target_node_index (NodeIndex, optional) – Target-node order and zoning identity; replaces target_node_ids.

  • self_loops ({'keep', 'drop'}) – Policy for flows within target groups after mapping. Default is 'keep'.

Returns:

Directed network of target groups, with spatial flow accounting in audit()['provenance']['spatial'].

Return type:

SparseMobilityNetwork

Examples

>>> import polars as pl
>>> from pyspainmobility import aggregate_od_network
>>> od = pl.DataFrame({
...     "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0],
... })
>>> grouped = aggregate_od_network(od, {"A": "P", "B": "P"})
>>> grouped.to_edge_table().rows()
[('P', 'P', 5.0)]

Aggregate an existing network

pyspainmobility.network.spatial.aggregate_network(network: SparseMobilityNetwork, mapping: Mapping[object, object] | DataFrame | DataFrame | Path | str, *, source_column: str = 'source_id', target_column: str = 'target_id', target_node_ids: Sequence[object] | None = None, target_node_index: NodeIndex | None = None, self_loops: str = 'keep') → SparseMobilityNetwork[source]

Aggregate a CSR network with the exact projection P.T @ A @ P.

The mapping must assign every source node to exactly one target node. Many-to-one mappings turn between-source flows into target self-loops; these are retained by default and reported as internalized_weight in network.audit()['provenance']['spatial']. Set self_loops='drop' only when that loss is intentional and auditable.

Parameters:
  • network (SparseMobilityNetwork) – Existing network to aggregate.

  • mapping (mapping, pandas.DataFrame, polars.DataFrame or Parquet path) – One source-to-target pair per source node. A dictionary maps IDs directly; a table uses the columns named below. Every network node must be covered.

  • source_column (str) – Mapping columns. Defaults are 'source_id' and 'target_id'.

  • target_column (str) – Mapping columns. Defaults are 'source_id' and 'target_id'.

  • target_node_ids (sequence, optional) – Complete target-node order, including any target isolates.

  • target_node_index (NodeIndex, optional) – Target-node order and zoning identity; replaces target_node_ids.

  • self_loops ({'keep', 'drop'}) – Policy for flows within target groups. Default is 'keep'.

Returns:

Aggregated network retaining the source weight units and direction, with spatial flow accounting in audit()['provenance']['spatial'].

Return type:

SparseMobilityNetwork

Examples

>>> import polars as pl
>>> from pyspainmobility import build_network, aggregate_network
>>> od = pl.DataFrame({
...     "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0],
... })
>>> grouped = aggregate_network(build_network(od), {"A": "P", "B": "P"})
>>> grouped.to_edge_table().rows()
[('P', 'P', 5.0)]