Spatial correlation test of two vectors of values at the same locations
Source:R/spatialCorrelation.R
spatialCorrelation.RdFunction to calculate Pearson's correlation between two spatial datasets. To replace the analytical p-value which results in a high false positive rate for autocorrelated spatial patterns, it calculates empirical p-values from empirical null distributions generated from permuting the datasets and then smoothing to maintain the original degree of autocorrelation
Usage
spatialCorrelation(
X,
Y,
pos,
nPermutations = 100,
deltaX = NULL,
deltaY = NULL,
maxDistPrctile = 0.25,
returnPermutations = FALSE,
nThreads = 1,
BPPARAM = NULL,
seed = 0
)Arguments
- X
numeric: a numeric vector with N observations (a matrix with one row or one column is also accepted)- Y
numeric: a numeric vector with N observations, likeX- pos
matrix: an N x 2 matrix of the spatial x,y coordinates of observations- nPermutations
integerordouble: number of permutations to generate to build the empirical null distribution. This number will determine the precision of the p-value. Default is100, such that the smallest possible p-value is \(1 / 101\), about 0.0099- deltaX
numeric: A single numeric or a numeric vector for controlling the degree of smoothing in permutations of X. Delta is a proportion calculated by dividing k neighbors by N total observations in X, where k is the number of neighbors in the permutation of X that should be within the radius smoothed by the Gaussian kernel to achieve the amount of autocorrelation present in the original X. If a single delta is not known, a sequence of deltas can be inputted and the best delta will be found such that it minimizes the sum of squares of the residuals between the variogram of the permutation generated from the delta and the variogram of the target. Default isNULL. If no value is supplied fordeltaX,seq(0.1,0.9,0.1), the sequence of every 0.1 from 0.1 to 0.9, will be used to find the best delta for X.- deltaY
numeric: A single numeric or numeric vector for controlling the degree of smoothing in permutations of Y.deltaYis likedeltaXbut for observation in Y instead of X. Default isNULL. If no value is supplied fordeltaY,seq(0.1,0.9,0.1), the sequence of every 0.1 from 0.1 to 0.9, will be used to find the best delta for permutations of Y.- maxDistPrctile
numeric: percentile of distances between pixels to use as max distance when calculating variograms. Default = 0.25. At greater distances the variogram is less precise because there are fewer pairs of points with that distance between them. Therefore, since the goal is to minimize the difference between the variogram of X and those of its permutations, the variogram should be subsetted to the percentile that is more robust.- returnPermutations
logical:FALSE(default) indicate whether the outputted dataframe will have a column with the values of the permutations used to calculate the null correlations and the empirical p-value.- nThreads
integer: Number of threads of the compiled code. Default = 1. The permutations are distributed over the threads, and the results do not depend on the number of threads. We recommend the number of cores available (parallel::detectCores(logical = FALSE)).- BPPARAM
BiocParallelParam: Optional. If notNULL, its number of workers (BiocParallel::bpnworkers(BPPARAM)) is used as the number of threads instead ofnThreads. No BiocParallel back-end is started (nothing is forked). Default isNULL.- seed
integer: Seed for the random number generator. Default0. The permutations are drawn afterset.seed(seed)with the session's random number generator kinds (RNGkind()), and the noise of permutation \(b\) afterset.seed(seed + b)with"L'Ecuyer-CMRG". The results depend on the seed only, and the global random number generator state (.Random.seed) is left unchanged.
Value
The output is returned as a data.frame with one row (named
"cor") containing the columns:
correlationCoefPearson's correlation coefficient.
pValueNaivethe analytical p-value naively assuming independent observations
pValuePermuteXthe empirical p-value when creating a null from permutations of observations in X, computed as \((b + 1) / (B + 1)\) where \(b\) is the number of null correlations whose absolute value is at least the absolute value of the observed correlation
pValuePermuteYthe empirical p-value when creating a null from permutations of observations in Y, computed like
pValuePermuteXdeltaStarMedianXthe median delta star (the delta which minimizes the difference between the variogram of the permutation and the variogram of observations) across permutations of X
deltaStarMedianYthe median delta star across permutations of Y
deltaStarXlist of delta star for all permutations of X
deltaStarYlist of delta star for all permutations of Y
nullCorrelationsXlist of a B x 1 matrix: the correlation coefficients for pairing Y and all permutations of X
nullCorrelationsYlist of a B x 1 matrix: the correlation coefficients for pairing X and all permutations of Y
permutationsX(optional) an N x B matrix, where N is the length of X and B is
nPermutations. Each column is the resulting values of a permutation of XpermutationsY(optional) an N x B matrix, where N is the length of Y and B is
nPermutations. Each column is the resulting values of a permutation of Y
Details
The null distribution of the correlation is built twice: by
permuting X while keeping Y fixed, and by permuting Y while keeping X fixed
(see viladomatCorrelation for how a permutation keeps the
autocorrelation). Both directions use the same seed, so they use the same
shuffles of the locations. The empirical p-value of a direction is
\((b + 1) / (B + 1)\), where \(b\) is the number of null correlations
whose absolute value is at least the absolute value of the observed
correlation and \(B\) is nPermutations; it is never 0.
The computation is done by compiled code (C++) that reimplements the
locfit smoother and the geoR variogram of the original R
implementation and gives the same results: the same delta star for every
permutation, and the same null correlations up to floating-point rounding
(about 1e-14 on the published analyses). Results do not depend on the
number of threads, and the global random number generator state is left
unchanged.
If the null cannot be computed in a direction, the columns computed from
permutations are NA (an NA row) and a warning gives the reason.
This happens when X or Y is constant or has missing values, when
\(N \times delta < 2\) for a delta (fewer than 2
locations in the smoothing neighbourhood), when maxDistPrctile is
so small that the variogram has fewer than 2 bins, or with exactly
duplicated coordinates and a delta so small that the neighbourhood holds
no more than the copies of a location. correlationCoef and
pValueNaive are still computed by cor.test() where possible
(on the complete pairs if there are missing values).
Examples
data(quakes)
#remove duplicated positions
quakes_data <- quakes[!duplicated(cbind(quakes$lat, quakes$long)),]
cor <- spatialCorrelation(X = quakes_data$depth,
Y = quakes_data$mag,
pos = cbind(quakes_data$lat, quakes_data$long),
nThreads = 2)
cor
#> correlationCoef pValueNaive pValuePermuteX pValuePermuteY deltaStarMedianX
#> cor -0.230266 1.779041e-13 0.03960396 0.1386139 0.8
#> deltaStarMedianY deltaStarX deltaStarY nullCorrelationsX
#> cor 0.5 0.9, 0.8.... 0.3, 0.7.... -0.15504....
#> nullCorrelationsY
#> cor -0.10144....
# plot the delta star (the delta which minimizes the difference between the
# variogram of the permutation and the variogram of observations) for all
# permutations to see if clear peak found in the range inputted
hist(cor$deltaStarX[[1]])
hist(cor$deltaStarY[[1]])
#plot null distribution of correlations to see if normally distributed
hist(cor$nullCorrelationsX[[1]])
hist(cor$nullCorrelationsY[[1]])
#example of inputting specific range for deltaX and deltaY
cor2 <- spatialCorrelation(X = quakes_data$depth,
Y = quakes_data$mag,
pos = cbind(quakes_data$lat, quakes_data$long),
deltaX = seq(0.05, 0.9, 0.05),
deltaY = seq(0.02, 0.5, 0.02),
nThreads = 2)
cor2
#> correlationCoef pValueNaive pValuePermuteX pValuePermuteY deltaStarMedianX
#> cor -0.230266 1.779041e-13 0.03960396 0.02970297 0.75
#> deltaStarMedianY deltaStarX deltaStarY nullCorrelationsX
#> cor 0.26 0.9, 0.8.... 0.5, 0.1.... -0.15141....
#> nullCorrelationsY
#> cor -0.10726....
hist(cor2$deltaStarX[[1]])
hist(cor2$deltaStarY[[1]])
hist(cor2$nullCorrelationsX[[1]])
hist(cor2$nullCorrelationsY[[1]])
#visualizations of the spatial data to verify negative correlation
library(ggplot2)
p1 <- ggplot2::ggplot(quakes_data,
ggplot2::aes(x = long, y = lat, color = depth)) +
ggplot2::geom_point(size = 2) +
ggplot2::scale_color_gradient(low = "lightblue", high = "blue") +
ggplot2::labs(title = "Locations of Earthquakes off Fiji",
x = "Longitude", y = "Latitude",
color = "Depth (km)") +
ggplot2::theme_minimal() +
ggplot2::coord_quickmap()
p2 <- ggplot2::ggplot(quakes_data,
ggplot2::aes(x = long, y = lat, color = mag)) +
ggplot2::geom_point(size = 2) +
ggplot2::scale_color_gradient(low = "lightblue", high = "blue") +
ggplot2::labs(title = "Locations of Earthquakes off Fiji",
x = "Longitude", y = "Latitude",
color = "Richter Magnitude") +
ggplot2::theme_minimal() +
ggplot2::coord_quickmap()
p1
p2