Skip to content

Commit 8a45718

Browse files
authored
PERF: eliminate redundant sorting (#793)
* PERF: eliminate redundant sorting * remove redundant conversions in build_travel_cost
1 parent 061942b commit 8a45718

File tree

3 files changed

+26
-24
lines changed

3 files changed

+26
-24
lines changed

libpysal/graph/_network.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22

3+
from ._kernel import _kernel_functions
34
from ._utils import _induce_cliques, _validate_geometry_input
45

56

@@ -61,7 +62,7 @@ def pdna_to_adj(origins, network, node_ids, threshold):
6162
return adj
6263

6364

64-
def build_travel_graph(df, network, threshold, mapping_distance):
65+
def build_travel_graph(df, network, threshold, mapping_distance, kernel=None):
6566
"""Compute the shortest path between gdf centroids via a pandana.Network
6667
and return an adjacency list with weight=cost. Note unlike distance_band,
6768
:math:`G_{ij}` and :math:`G_{ji}` are often different because travel networks
@@ -81,6 +82,11 @@ def build_travel_graph(df, network, threshold, mapping_distance):
8182
snapping tolerance passed to ``pandana.Network.get_node_ids`` that defines
8283
the maximum range at which observations are snapped to nearest nodes in the
8384
network. Default is None
85+
kernel : str
86+
kernel transformation applied to the weights. See
87+
libpysal.graph.Graph.build_kernel for more information on kernel
88+
transformation options. Default is None, in which case the Graph weight
89+
is pure distance between focal and neighbor
8490
8591
Returns
8692
-------
@@ -118,4 +124,11 @@ def build_travel_graph(df, network, threshold, mapping_distance):
118124
.reset_index()
119125
)
120126

127+
if callable(kernel):
128+
adj_cliques["weight"] = kernel(adj_cliques["weight"], threshold)
129+
else:
130+
adj_cliques["weight"] = _kernel_functions[kernel](
131+
adj_cliques["weight"], threshold
132+
)
133+
121134
return adj_cliques

libpysal/graph/_utils.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ def _sparse_to_arrays(sparray, ids=None, resolve_isolates=True, return_adjacency
3232
When we know we are dealing with cliques, we don't want to resolve
3333
isolates here but will do that later once cliques are induced.
3434
"""
35-
argsort_kwds = {"stable": True} if NUMPY_GE_2 else {}
3635
sparray = sparray.tocoo(copy=False)
3736
if ids is not None:
3837
ids = np.asarray(ids)
@@ -42,15 +41,13 @@ def _sparse_to_arrays(sparray, ids=None, resolve_isolates=True, return_adjacency
4241
f"the shape of sparse {sparray.shape}."
4342
)
4443

45-
sorter = sparray.row.argsort(**argsort_kwds)
46-
head = ids[sparray.row][sorter]
47-
tail = ids[sparray.col][sorter]
48-
data = sparray.data[sorter]
44+
head = ids[sparray.row]
45+
tail = ids[sparray.col]
46+
data = sparray.data
4947
else:
50-
sorter = sparray.row.argsort(**argsort_kwds)
51-
head = sparray.row[sorter]
52-
tail = sparray.col[sorter]
53-
data = sparray.data[sorter]
48+
head = sparray.row
49+
tail = sparray.col
50+
data = sparray.data
5451
ids = np.arange(sparray.shape[0], dtype=int)
5552

5653
if resolve_isolates:

libpysal/graph/base.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ def build_kernel(
10851085
coplanar=coplanar,
10861086
)
10871087

1088-
return cls.from_arrays(head, tail, weight)
1088+
return cls.from_arrays(head, tail, weight, is_sorted=True)
10891089

10901090
@classmethod
10911091
def build_knn(cls, data, k, metric="euclidean", p=2, coplanar="raise"):
@@ -1529,19 +1529,11 @@ def build_travel_cost(
15291529
117 333.639008
15301530
Name: weight, dtype: float64
15311531
"""
1532-
adj = _build_travel_graph(df, network, threshold, mapping_distance)
1533-
g = cls.from_adjacency(adj)
1534-
if kernel is not None:
1535-
arrays = _kernel(
1536-
g.sparse,
1537-
metric="precomputed",
1538-
kernel=kernel,
1539-
bandwidth=threshold,
1540-
resolve_isolates=False,
1541-
ids=df.index.values,
1542-
)
1543-
return cls.from_arrays(*arrays)
1544-
return g
1532+
adj = _build_travel_graph(
1533+
df, network, threshold, mapping_distance, kernel=kernel
1534+
)
1535+
1536+
return cls.from_adjacency(adj)
15451537

15461538
@cached_property
15471539
def neighbors(self):

0 commit comments

Comments
 (0)