Flow measures and comparisons¶
These functions use the weights chosen when the network was built. With the
default weight="n_trips", strengths and flow changes are measured in trips.
For examples with expected results, see Network examples.
node_strengths(): flow sent and received by each zone.compare_networks(): similarity, edge overlap and overall flow changes.edge_changes(): weights and signed changes for individual OD pairs.destination_similarity(): similarity of each origin’s destination profile.
Flow by zone¶
- pyspainmobility.network.metrics.node_strengths(network: SparseMobilityNetwork) DataFrame[source]¶
Calculate the flow sent and received by each zone.
- Parameters:
network (SparseMobilityNetwork) – Network whose edge weights will be summed. With
weight='n_trips', the resulting strengths are measured in trips.- Returns:
One row per node in matrix order, including isolates:
node_id: zone identifier.out_strength: sum of outgoing weights (matrix row sum).in_strength: sum of incoming weights (matrix column sum).total_strength: outgoing plus incoming strength for directed networks; incident weight for undirected networks.
- Return type:
polars.DataFrame
Notes
A directed self-loop contributes once to each of in- and out-strength.
For undirected networks
total_strengthcounts a self-loop once, as one mobility flow incident on that zone. NetworkX’s weighted graph degree counts an undirected self-loop twice; callers needing that graph-theoretic convention should use the NetworkX adapter explicitly.Examples
>>> import polars as pl >>> from pyspainmobility import build_network, node_strengths >>> od = pl.DataFrame({ ... "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0], ... }) >>> node_strengths(build_network(od)).rows() [('A', 5.0, 0.0, 5.0), ('B', 0.0, 5.0, 5.0)]
Whole-network comparison¶
- pyspainmobility.network.metrics.compare_networks(left: SparseMobilityNetwork, right: SparseMobilityNetwork, *, left_label: object | None = None, right_label: object | None = None) NetworkComparison[source]¶
Summarize overlap, similarity and flow changes between two networks.
- Parameters:
left (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
right (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
left_label (object, optional) – Labels recorded in the result, such as the dates being compared.
right_label (object, optional) – Labels recorded in the result, such as the dates being compared.
- Returns:
Connection counts, edge and weighted Jaccard similarity, cosine similarity, and increases/decreases in flow.
audit()returns a serializable dictionary. See the flow-measures reference for definitions.- Return type:
Examples
>>> import polars as pl >>> from pyspainmobility import build_network, compare_networks >>> od = pl.DataFrame({ ... "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0], ... }) >>> first = build_network(od) >>> second = build_network(od.with_columns(pl.lit(7.0).alias("n_trips"))) >>> result = compare_networks(first, second) >>> result.flow_increase, result.flow_decrease (2.0, 0.0) >>> result.shared_edge_count 1 >>> round(result.weighted_jaccard, 2) 0.71 >>> result.cosine_similarity 1.0
Field |
Definition |
|---|---|
|
Total logical edge weight in the first and second networks. |
|
Number of non-zero connections in each network. |
|
Connections present in both networks. |
|
Connections appearing or disappearing in the second network. |
|
Shared connection count divided by the union connection count. |
|
|
|
Sum of pairwise minimum and maximum edge weights, respectively. |
|
|
|
Cosine of the vectors of edge weights; compares their relative pattern. |
|
Sums of positive and negative weight changes, reported as positive totals. |
Both Jaccard measures and cosine similarity are 1 when both networks are empty, and 0 when only one is empty. Undirected connections are counted once, including each self-loop. Comparisons align node order and reject incompatible node universes, zoning metadata, directions, weight fields or normalizations.
- class pyspainmobility.network.metrics.NetworkComparison(node_index: NodeIndex, weight: str, weight_normalization: str | None, left_label: str | None, right_label: str | None, left_edge_count: int, right_edge_count: int, shared_edge_count: int, added_edge_count: int, removed_edge_count: int, edge_jaccard: float, weighted_jaccard: float, cosine_similarity: float, left_weight: float, right_weight: float, shared_weight: float, union_weight: float, flow_increase: float, flow_decrease: float)[source]¶
Summary of a pairwise comparison on one aligned node index.
flow_increaseandflow_decreasemeasure the total positive and negative changes in edge weights. They include changes on persistent edges as well as edges that appeared or disappeared.
Changes by connection¶
- pyspainmobility.network.metrics.edge_changes(left: SparseMobilityNetwork, right: SparseMobilityNetwork) DataFrame[source]¶
Inspect weight changes for individual origin-destination connections.
- Parameters:
left (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
right (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
- Returns:
One row for each connection present in either network, sorted by IDs:
id_origin,id_destination: endpoint zone IDs.left_weight,right_weight: weights, with absent edges set to zero.delta_weight:right_weight - left_weight.change:'added','removed','increased','decreased'or'unchanged'.
Unchanged connections are included. Undirected pairs appear once; zero-to-zero pairs are omitted.
- Return type:
polars.DataFrame
Examples
>>> import polars as pl >>> from pyspainmobility import build_network, edge_changes >>> od = pl.DataFrame({ ... "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0], ... }) >>> first = build_network(od) >>> second = build_network(od.with_columns(pl.lit(7.0).alias("n_trips"))) >>> edge_changes(first, second).select("delta_weight", "change").rows() [(2.0, 'increased')]
Destination profiles by origin¶
- pyspainmobility.network.metrics.destination_similarity(left: SparseMobilityNetwork, right: SparseMobilityNetwork) DataFrame[source]¶
Return per-origin cosine similarity between destination flow profiles.
A node with no outgoing flow in either network has similarity 1.0; a node that is inactive in only one network has similarity 0.0.
- Parameters:
left (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
right (SparseMobilityNetwork) – Networks with compatible node universes, zoning metadata, direction, weight field and normalization. Their node order is aligned automatically.
- Returns:
One row per origin in the first network’s node order:
node_id: origin zone identifier.destination_cosine_similarity: cosine of the two outgoing weight profiles, accounting for the empty-profile conventions above.
- Return type:
polars.DataFrame
Examples
>>> import polars as pl >>> from pyspainmobility import build_network, destination_similarity >>> od = pl.DataFrame({ ... "id_origin": ["A"], "id_destination": ["B"], "n_trips": [5.0], ... }) >>> network = build_network(od) >>> destination_similarity(network, network).rows() [('A', 1.0), ('B', 1.0)]