testSpatialAutocorrelation | R Documentation |
This function performs a Moran's I test for distance-based spatial (or similar type) autocorrelation on the calculated quantile residuals.
testSpatialAutocorrelation(simulationOutput, x = NULL, y = NULL,
distMat = NULL, alternative = c("two.sided", "greater", "less"),
plot = TRUE)
simulationOutput |
An object of class DHARMa, either created via simulateResiduals for supported models or via createDHARMa for simulations created outside DHARMa, or a supported model. Providing a supported model directly is discouraged, because simulation settings cannot be changed in this case. |
x |
The x coordinate, in the same order as the data points. Must be specified unless distMat is provided. |
y |
The y coordinate, in the same order as the data points. Must be specified unless distMat is provided. |
distMat |
Optional distance matrix. If not provided, euclidean distances based on x and y will be calculated. See details for explanation. |
alternative |
A character string specifying whether the test should test if observations are "greater", "less" or "two.sided" compared to the simulated null hypothesis. |
plot |
If T, and if x and y is provided, plot the output (see Details). |
The function performs Moran.I test from the package ape on the DHARMa residuals. If a distance matrix (distMat) is provided, calculations will be based on this distance matrix, and x,y coordinates will only used for the plotting (if provided). If distMat is not provided, the function will calculate the euclidean distances between x,y coordinates, and test Moran.I based on these distances.
If plot = T, a plot will be produced showing each residual with at its x,y position, colored according to the residual value. Residuals with 0.5 are colored white, everything below 0.5 is colored increasinly red, everything above 0.5 is colored increasingly blue.
Testing for spatial autocorrelation requires unique x,y values - if you have several observations per location, either use the recalculateResiduals function to aggregate residuals per location, or extract the residuals from the fitted object, and plot / test each of them independently for spatially repeated subgroups (a typical scenario would repeated spatial observation, in which case one could plot / test each time step separately for temporal autocorrelation). Note that the latter must be done by hand, outside testSpatialAutocorrelation.
Standard DHARMa simulations from models with (temporal / spatial / phylogenetic) conditional autoregressive terms will still have the respective temporal / spatial / phylogenetic correlation in the DHARMa residuals, unless the package you are using is modelling the autoregressive terms as explicit REs and is able to simulate conditional on the fitted REs. This has two consequences:
If you check the residuals for such a model, they will still show significant autocorrelation, even if the model fully accounts for this structure.
Because the DHARMa residuals for such a model are not statistically independent any more, other tests (e.g. dispersion, uniformity) may have inflated type I error, i.e. you will have a higher likelihood of spurious residual problems.
There are three (non-exclusive) routes to address these issues when working with spatial / temporal / phylogenetic / other autoregressive models:
Simulate conditional on the fitted CAR structures (see conditional simulations in the help of simulateResiduals).
Rotate simulations prior to residual calculations (see parameter rotation in simulateResiduals).
Use custom tests / plots that explicitly compare the correlation structure in the simulated data to the correlation structure in the observed data.
Florian Hartig
testResiduals, testUniformity, testOutliers, testDispersion, testZeroInflation, testGeneric, testTemporalAutocorrelation, testSpatialAutocorrelation, testQuantiles, testCategorical
testData = createData(sampleSize = 40, family = gaussian())
fittedModel <- lm(observedResponse ~ Environment1, data = testData)
res = simulateResiduals(fittedModel)
# Standard use
testSpatialAutocorrelation(res, x = testData$x, y = testData$y)
# Alternatively, one can provide a distance matrix
dM = as.matrix(dist(cbind(testData$x, testData$y)))
testSpatialAutocorrelation(res, distMat = dM)
# You could add a spatial variogram via
# library(gstat)
# dat = data.frame(res = residuals(res), x = testData$x, y = testData$y)
# coordinates(dat) = ~x+y
# vario = variogram(res~1, data = dat, alpha=c(0,45,90,135))
# plot(vario, ylim = c(-1,1))
# if there are multiple observations with the same x values,
# create first ar group with unique values for each location
# then aggregate the residuals per location, and calculate
# spatial autocorrelation on the new group
# modifying x, y, so that we have the same location per group
# just for completeness
testData$x = as.numeric(testData$group)
testData$y = as.numeric(testData$group)
# calculating x, y positions per group
groupLocations = aggregate(testData[, 6:7], list(testData$group), mean)
# calculating residuals per group
res2 = recalculateResiduals(res, group = testData$group)
# running the spatial test on grouped residuals
testSpatialAutocorrelation(res2, groupLocations$x, groupLocations$y)
# careful when using REs to account for spatially clustered (but not grouped)
# data. this originates from https://github.com/florianhartig/DHARMa/issues/81
# Assume our data is divided into clusters, where observations are close together
# but not at the same point, and we suspect that observations in clusters are
# autocorrelated
clusters = 100
subsamples = 10
size = clusters * subsamples
testData = createData(sampleSize = size, family = gaussian(), numGroups = clusters )
testData$x = rnorm(clusters)[testData$group] + rnorm(size, sd = 0.01)
testData$y = rnorm(clusters)[testData$group] + rnorm(size, sd = 0.01)
# It's a good idea to use a RE to take out the cluster effects. This accounts
# for the autocorrelation within clusters
library(lme4)
fittedModel <- lmer(observedResponse ~ Environment1 + (1|group), data = testData)
# DHARMa default is to re-simulate REs - this means spatial pattern remains
# because residuals are still clustered
res = simulateResiduals(fittedModel)
testSpatialAutocorrelation(res, x = testData$x, y = testData$y)
# However, it should disappear if you just calculate an aggregate residuals per cluster
# Because at least how the data are simulated, cluster are spatially independent
res2 = recalculateResiduals(res, group = testData$group)
testSpatialAutocorrelation(res2,
x = aggregate(testData$x, list(testData$group), mean)$x,
y = aggregate(testData$y, list(testData$group), mean)$x)
# For lme4, it's also possible to simulated residuals conditional on fitted
# REs (re.form). Conditional on the fitted REs (i.e. accounting for the clusters)
# the residuals should now be indepdendent. The remaining RSA we see here is
# probably due to the RE shrinkage
res = simulateResiduals(fittedModel, re.form = NULL)
testSpatialAutocorrelation(res, x = testData$x, y = testData$y)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.