Skip to content
Open
20 changes: 18 additions & 2 deletions esda/crand.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def crand(
w,
observed,
permutations,
permutations_array,
keep,
n_jobs,
stat_func,
Expand All @@ -91,6 +92,8 @@ def crand(
(N,) array with observed values
permutations : int
Number of permutations for conditional randomisation
permutations_array : ndarray
(permutations, ) array with indices of permuted
keep : Boolean
If True, store simulation; else do not return randomised statistics
n_jobs : int
Expand Down Expand Up @@ -170,8 +173,21 @@ def crand(
# self neighbor, since conditional randomization conditions on site i.
cardinalities = np.array((adj_matrix != 0).sum(1)).flatten()
max_card = cardinalities.max()
permuted_ids = vec_permutations(max_card, n, permutations, seed)


if permutations_array is None:
# Random permutation array
permuted_ids = vec_permutations(max_card, n, permutations, seed)
else:
# User defined permutation array
permuted_ids = permutations_array
if permuted_ids.shape[0] != permutations:
permutations = permuted_ids.shape[0]
warnings.warn(
f"Number of permutations has been adjusted to match the length of the "
f"permutations array. New value of 'permutations' is {permutations}.",
stacklevel=2,
)

if n_jobs != 1:
try:
import joblib # noqa: F401
Expand Down
1 change: 1 addition & 0 deletions esda/join_counts_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def fit(self, y, n_jobs=1, permutations=999):
w=self.w,
observed=self.LJC,
permutations=permutations,
permutations_array=None,
keep=keep_simulations,
n_jobs=n_jobs,
stat_func=_ljc_uni,
Expand Down
6 changes: 6 additions & 0 deletions esda/moran.py
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,8 @@ class Moran_Local: # noqa: N801
permutations : int
number of random permutations for calculation of pseudo
p_values
permutations_array: array
user specified permutations
geoda_quads : boolean
(default=False)
If True use GeoDa scheme: HH=1, LL=2, LH=3, HL=4
Expand Down Expand Up @@ -1027,6 +1029,7 @@ def __init__(
w,
transformation="r",
permutations=PERMUTATIONS,
permutations_array=None,
geoda_quads=False,
n_jobs=1,
keep_simulations=True,
Expand Down Expand Up @@ -1064,6 +1067,7 @@ def __init__(
w,
self.Is,
permutations,
permutations_array,
keep_simulations,
n_jobs=n_jobs,
stat_func=_moran_local_crand,
Expand Down Expand Up @@ -1406,6 +1410,7 @@ def __init__(
w,
self.Is,
permutations,
None,
keep_simulations,
n_jobs=n_jobs,
stat_func=_moran_local_bv_crand,
Expand Down Expand Up @@ -1650,6 +1655,7 @@ def __init__(
w,
transformation=transformation,
permutations=permutations,
permutations_array=None,
geoda_quads=geoda_quads,
n_jobs=n_jobs,
keep_simulations=keep_simulations,
Expand Down
25 changes: 25 additions & 0 deletions esda/tests/test_moran.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def setup_method(self):
f = libpysal.io.open(libpysal.examples.get_path("desmith.txt"))
self.y = np.array(f.by_col["z"])


@parametrize_desmith
def test_Moran_Local(self, w):
lm = moran.Moran_Local(
Expand All @@ -174,6 +175,30 @@ def test_Moran_Local(self, w):
)
np.testing.assert_allclose(lm.z_sim[0], -0.6990291160835514)
np.testing.assert_allclose(lm.p_z_sim[0], 0.24226691753791396)

@parametrize_desmith
def test_Moran_Local_custom_perms(self, w):
np.random.seed(SEED)
cardinalities = np.array((w.sparse != 0).sum(1)).flatten()
max_card = cardinalities.max()
original_array = np.arange(len(self.y))
permutations_array = np.zeros((99, max_card), dtype=np.int32)

for i in range(99):
random_number = np.random.randint(0, len(self.y) - max_card)
permutations_array[i] = original_array[random_number:random_number + max_card]

lm = moran.Moran_Local(
self.y,
w,
transformation="r",
permutations=99,
permutations_array=permutations_array,
keep_simulations=True,
seed=SEED,
)
np.testing.assert_allclose(lm.z_sim[0], -0.49229215590070813)
np.testing.assert_allclose(lm.p_z_sim[0], 0.311256412279757)

@parametrize_sac
def test_Moran_Local_labels(self, w):
Expand Down