From 7902cb96643575fb1643211faa3c1926db2c2c17 Mon Sep 17 00:00:00 2001 From: Martin Fleischmann Date: Thu, 9 Nov 2023 15:54:31 +0100 Subject: [PATCH 1/2] ENH: Graph.eliminate_zeros, refactor isolates --- libpysal/graph/base.py | 26 ++++++++++++++++++++++++-- libpysal/graph/tests/test_base.py | 8 ++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libpysal/graph/base.py b/libpysal/graph/base.py index b576365b3..0465e324a 100644 --- a/libpysal/graph/base.py +++ b/libpysal/graph/base.py @@ -972,9 +972,13 @@ def isolates(self): pandas.Index Index with a subset of observations that do not have any neighbor """ - nulls = self._adjacency[self._adjacency == 0].reset_index(level=1) + nulls = self._adjacency[self._adjacency == 0] # since not all zeros are necessarily isolates, do the focal == neighbor check - return nulls[nulls.index == nulls.neighbor].index.unique() + return ( + nulls[nulls.index.codes[0] == nulls.index.codes[1]] + .index.get_level_values(0) + .unique() + ) @cached_property def unique_ids(self): @@ -1337,6 +1341,24 @@ def explore( **kwargs, ) + def eliminate_zeros(self): + """Remove graph edges with zero weight + + Eliminates edges with weight == 0 that do not encode an + isolate. This is useful to clean-up edges that will make + no effect in operations like :meth:`lag`. + + Returns + ------- + Graph + subset of Graph with zero-weight edges eliminated + """ + # get a mask for isolates + isolates = self._adjacency.index.codes[0] == self._adjacency.index.codes[1] + # substract isolates from mask of zeros + zeros = (self._adjacency == 0) != isolates + return Graph(self._adjacency[~zeros]) + def _arrange_arrays(heads, tails, weights, ids=None): """ diff --git a/libpysal/graph/tests/test_base.py b/libpysal/graph/tests/test_base.py index e521eaf56..f7f783e94 100644 --- a/libpysal/graph/tests/test_base.py +++ b/libpysal/graph/tests/test_base.py @@ -941,3 +941,11 @@ def test_component_labels(self): pd.testing.assert_series_equal( expected, nybb.component_labels, check_dtype=False ) + + def test_eliminate_zeros(self): + adj = self.adjacency_str_binary.copy() + adj["Bronx", "Queens"] = 0 + adj["Queens", "Manhattan"] = 0 + with_zero = graph.Graph(adj) + expected = adj.drop([("Bronx", "Queens"), ("Queens", "Manhattan")]) + pd.testing.assert_series_equal(with_zero.eliminate_zeros()._adjacency, expected) From afc14abead7bc7ea0ffc3a2215649f0b3e925cf2 Mon Sep 17 00:00:00 2001 From: Martin Fleischmann Date: Sun, 19 Nov 2023 10:29:57 +0100 Subject: [PATCH 2/2] is_sorted --- libpysal/graph/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpysal/graph/base.py b/libpysal/graph/base.py index ee1b2727e..821806414 100644 --- a/libpysal/graph/base.py +++ b/libpysal/graph/base.py @@ -1417,7 +1417,7 @@ def eliminate_zeros(self): isolates = self._adjacency.index.codes[0] == self._adjacency.index.codes[1] # substract isolates from mask of zeros zeros = (self._adjacency == 0) != isolates - return Graph(self._adjacency[~zeros]) + return Graph(self._adjacency[~zeros], is_sorted=True) def _arrange_arrays(heads, tails, weights, ids=None):