Measures spatial autocorrelation in a variable measured on areas: whether neighbouring areas tend to have similar values (positive I), dissimilar values (negative I), or neither. The p-value comes from randomly permuting the values over the areas. You must supply the neighbour structure (a list or a weight matrix); none is invented, because an administrative extract keyed on a region ships no geometry, and guessing adjacency would make the answer a property of the guess.
Usage
morani(x, nbrs, style = c("W", "B"), nperm = 9999L)Arguments
- x
Numeric vector, one value per area, no missing values.
- nbrs
Either a list with one integer vector of neighbour indices per area (in the order of
x), or a square \(n \times n\) weight matrix.- style
"W"(the default) row-standardises the weights, so each area's neighbours carry a total weight of one;"B"leaves them as given (binary for a list). Row standardisation is the usual choice, and stops an area with many neighbours from dominating.- nperm
Integer, default
9999: the number of random permutations for the null distribution.
Value
A list with I (the statistic), expectation
(\(-1/(n-1)\)), nullmean and nullsd (mean and standard
deviation of the permuted values), z ((I - nullmean) /
nullsd), p_value, W (the total weight), n (number
of areas), nperm (permutations used) and style.
Details
With weights \(w_{ij}\), total \(W = \sum_{ij} w_{ij}\) and \(z_i = x_i - \bar x\), $$I = \frac{n}{W}\,\frac{\sum_{i}\sum_{j} w_{ij} z_i z_j}{\sum_i z_i^2}.$$ The expectation of I under the null is \(-1/(n - 1)\), not zero, so a small negative I is what independence looks like in a small set of areas. The p-value comes from permuting the values over the areas, which needs no distributional assumption – and with a handful of regions no distributional assumption is safe. It is two-sided around \(-1/(n - 1)\), \((1 + \mathrm{count}(|I^* - E| \ge |I - E|))/(1 + B)\) over the \(B\) finite permuted values, so it is never exactly zero.
A neighbour list is binary; a weight matrix keeps its magnitudes (for
example inverse distances). Self-neighbours and the diagonal are dropped.
style = "W" divides each area's weights by their total. The
permutations use R's random number generator, so call
set.seed() first for a reproducible p-value. The work is done in
compiled code.
Errors: fewer than three areas; missing values in x; a constant
x; a neighbour index outside 1..n; a list of the wrong
length; a weight matrix that is not \(n \times n\), not finite, or has
negative weights; no area with any neighbour.
References
Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika 37(1/2), 17-23. Laniyonu (2017), on policing practices in gentrifying neighbourhoods, uses the statistic as here, to establish that areal residuals are spatially dependent.
Examples
# Six areas in a line, each adjacent to the next.
nb <- list(2L, c(1L, 3L), c(2L, 4L), c(3L, 5L), c(4L, 6L), 5L)
# A smooth gradient is strongly positively autocorrelated.
set.seed(1)
morani(c(1, 2, 3, 4, 5, 6), nb, nperm = 999L)[c("I", "p_value")]
#> $I
#> [1] 0.7142857
#>
#> $p_value
#> [1] 0.011
#>
# An alternating pattern is negatively autocorrelated.
set.seed(1)
morani(c(1, 6, 1, 6, 1, 6), nb, nperm = 999L)[c("I", "p_value")]
#> $I
#> [1] -1
#>
#> $p_value
#> [1] 0.199
#>
# And the null expectation is not zero.
-1 / (6 - 1)
#> [1] -0.2
# the same line as a binary weight matrix, unstandardised
w <- matrix(0, 6, 6)
for (i in 1:5) w[i, i + 1] <- w[i + 1, i] <- 1
set.seed(1)
morani(c(1, 2, 3, 4, 5, 6), w, style = "B", nperm = 999L)$I
#> [1] 0.6
# a constant variable has no autocorrelation to measure
try(morani(c(2, 2, 2), list(2L, c(1L, 3L), 2L)))
#> Error : `x` is constant: Moran's I is undefined (no variance to autocorrelate)
