From f727f422de3d610b73ca73c3b8f95288f629a37a Mon Sep 17 00:00:00 2001 From: Giuliani Date: Mon, 7 Sep 2026 14:52:27 +0200 Subject: [PATCH 1/5] Add normalized Moran's I functions documentation, and tests --- DESCRIPTION | 29 ++++++- NAMESPACE | 4 + NEWS.md | 2 + R/normalized.moran.R | 22 +++++ R/normalized.moran.mc.R | 101 +++++++++++++++++++++++ R/normalized.moran.test.R | 91 ++++++++++++++++++++ inst/tinytest/test_normalized.moran_NA.R | 7 ++ man/normalized.moran.Rd | 46 +++++++++++ man/normalized.moran.mc.Rd | 93 +++++++++++++++++++++ man/normalized.moran.test.Rd | 68 +++++++++++++++ 10 files changed, 461 insertions(+), 2 deletions(-) create mode 100644 R/normalized.moran.R create mode 100644 R/normalized.moran.mc.R create mode 100644 R/normalized.moran.test.R create mode 100644 inst/tinytest/test_normalized.moran_NA.R create mode 100644 man/normalized.moran.Rd create mode 100644 man/normalized.moran.mc.Rd create mode 100644 man/normalized.moran.test.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 5e679a5e..4d18d723 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,10 +43,34 @@ Authors@R: c(person("Roger", "Bivand", role = c("cre", "aut"), person("Justyna", "Wilk", role = "ctb", comment = c(ORCID = "0000-0003-1495-2910")), person("Levi", "Wolf", role = "ctb"), - person("Danlin", "Yu", role = "ctb")) + person("Danlin", "Yu", role = "ctb"), + person("Giuliani", "Diego", role = "ctb", + comment = c(ORCID = "0000-0002-7198-6714"))) Depends: R (>= 3.3.0), methods, spData (>= 2.3.1), sf Imports: stats, deldir, boot (>= 1.3-1), graphics, utils, grDevices, units, s2, e1071, sp (>= 1.0) -Suggests: spatialreg (>= 1.2-1), Matrix, parallel, dbscan, RColorBrewer, lattice, xtable, foreign, igraph, RSpectra, knitr, classInt, tmap, spam, ggplot2, rmarkdown, tinytest, rgeoda (>= 0.0.11.1), mipfp, Guerry, codingMatrices +Suggests: + spatialreg (>= 1.2-1), + Matrix, + parallel, + dbscan, + RColorBrewer, + lattice, + xtable, + foreign, + igraph, + RSpectra, + knitr, + classInt, + tmap, + spam, + ggplot2, + rmarkdown, + tinytest, + rgeoda (>= 0.0.11.1), + mipfp, + Guerry, + codingMatrices, + testthat (>= 3.0.0) URL: https://github.com/r-spatial/spdep/, https://r-spatial.github.io/spdep/ BugReports: https://github.com/r-spatial/spdep/issues/ Description: A collection of functions to create spatial weights matrix @@ -95,3 +119,4 @@ Description: A collection of functions to create spatial weights matrix License: GPL (>= 2) VignetteBuilder: knitr RoxygenNote: RoxygenNote: 6.1.1 +Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index 5b26743b..332b1076 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -105,6 +105,10 @@ export(plot_spatialcoords, plot_moran, plot_spatialscree, localdelta, factorial_coordinates, plot_factorialcoords, plot_factorialscree, cornish_fisher) +export(normalized.moran) +export(normalized.moran.mc) +export(normalized.moran.test) + S3method(print, nb) S3method(summary, nb) S3method(print, summary.nb) diff --git a/NEWS.md b/NEWS.md index 6debda01..30a17996 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,8 @@ * add `NO_LEGACY_NONAP` +* add `normalized.moran.test` and `normalized.moran.mc` to compute the I_6 normalized Moran's I index and perform the associated tests by Tillé et al. (2026) + # Version 1.4-2 (2026-02-13) * robustness checks on `licd_multi`, update `hotspot` method for `licd_multi` output diff --git a/R/normalized.moran.R b/R/normalized.moran.R new file mode 100644 index 00000000..e29b3435 --- /dev/null +++ b/R/normalized.moran.R @@ -0,0 +1,22 @@ +normalized.moran <- function (x, listw, zero.policy = attr(listw, "zero.policy"), + NAOK = FALSE) +{ + if (is.null(zero.policy)) + zero.policy <- get.ZeroPolicyOption() + stopifnot(is.logical(zero.policy)) + n1 <- length(listw$neighbours) + x <- c(x) + if (n1 != length(x)) + stop("objects of different length") + xx <- mean(x, na.rm = NAOK) + z <- x - xx + lz <- spdep::lag.listw(listw, z, zero.policy = zero.policy, NAOK = NAOK) + if(NAOK) { + z_lz <- cbind(z,lz) + z_lz <- na.omit(z_lz) + z <- z_lz[,1] + lz <- z_lz[,2] + } + I <- cor(z, lz) + I +} diff --git a/R/normalized.moran.mc.R b/R/normalized.moran.mc.R new file mode 100644 index 00000000..bc5c08dd --- /dev/null +++ b/R/normalized.moran.mc.R @@ -0,0 +1,101 @@ +normalized.moran.mc <- function(x, listw, nsim, zero.policy = attr(listw, "zero.policy"), + alternative = "greater", na.action = na.fail, spChk = NULL, + return_boot = FALSE, adjust.n = TRUE) +{ + alternative <- match.arg(alternative, c("greater", "less", + "two.sided")) + wname <- deparse(substitute(listw)) + if (!inherits(listw, "listw")) + stop(wname, "is not a listw object") + xname <- deparse(substitute(x)) + if (!is.numeric(x)) + stop(xname, "is not a numeric vector") + if (is.null(attr(listw$weights, "W"))) + message(wname, " is not a listw object of style W, then it has been row-standardized") + if (is.null(zero.policy)) + zero.policy <- get.ZeroPolicyOption() + stopifnot(is.logical(zero.policy)) + stopifnot(length(zero.policy) == 1L) + if (missing(nsim)) + stop("nsim must be given") + if (is.null(spChk)) + spChk <- get.spChkOption() + stopifnot(is.logical(spChk)) + stopifnot(length(spChk) == 1L) + if (spChk && !chkIDs(x, listw)) + stop("Check of data and weights ID integrity failed") + cards <- card(listw$neighbours) + if (!zero.policy && any(cards == 0)) + stop("regions with no neighbours found") + stopifnot(length(na.action) == 1L) + if (deparse(substitute(na.action)) == "na.pass") + stop("na.pass not permitted") + x <- na.action(x) + na.act <- attr(x, "na.action") + if (!is.null(na.act)) { + subset <- !(1:length(listw$neighbours) %in% na.act) + listw <- subset(listw, subset, zero.policy = zero.policy) + if (return_boot) + message("NA observations omitted: ", paste(na.act, + collapse = ", ")) + } + n <- length(listw$neighbours) + if (n != length(x)) + stop("objects of different length") + gamres <- suppressWarnings(nsim > gamma(n + 1)) + if (gamres) + stop("nsim too large for this number of observations") + if (nsim < 1) + stop("nsim too small") + if (adjust.n) + n <- n - sum(cards == 0L) + if (is.null(attr(listw$weights, "W"))) { + W <- spdep::listw2mat(listw) + listw <- spdep::mat2listw(W, style="W", zero.policy = zero.policy) + } + if (return_boot) { + moran_boot <- function(var, i, ...) { + var <- var[i] + return(normalized.moran(x = var, ...)) + } + p_setup <- spdep:::parallel_setup(NULL) + parallel <- p_setup$parallel + ncpus <- p_setup$ncpus + cl <- p_setup$cl + res <- boot::boot(x, statistic = moran_boot, R = nsim, sim = "permutation", + listw = listw, zero.policy = zero.policy, + parallel = parallel, ncpus = ncpus, cl = cl) + return(res) + } + res <- numeric(length = nsim + 1) + for (i in 1:nsim) res[i] <- normalized.moran(sample(x), listw, + zero.policy) + res[nsim + 1] <- normalized.moran(x, listw, zero.policy) + rankres <- rank(res) + xrank <- rankres[length(res)] + diff <- nsim - xrank + diff <- ifelse(diff > 0, diff, 0) + if (alternative == "less") + pval <- punif((diff + 1)/(nsim + 1), lower.tail = FALSE) + else if (alternative == "greater") + pval <- punif((diff + 1)/(nsim + 1)) + else pval <- punif(abs(xrank - (nsim + 1)/2)/(nsim + 1), + 0, 0.5, lower.tail = FALSE) + if (!is.finite(pval) || pval < 0 || pval > 1) + warning("Out-of-range p-value: reconsider test arguments") + statistic <- res[nsim + 1] + names(statistic) <- "statistic" + parameter <- xrank + names(parameter) <- "observed rank" + method <- "Monte-Carlo simulation of Normalized Moran I" + data.name <- paste(xname, "\nweights:", wname, ifelse(is.null(na.act), + "", paste("\nomitted:", paste(na.act, collapse = ", "))), + "\nnumber of simulations + 1:", nsim + 1, "\n") + lres <- list(statistic = statistic, parameter = parameter, + p.value = pval, alternative = alternative, method = method, + data.name = data.name, res = res) + if (!is.null(na.act)) + attr(lres, "na.action") <- na.act + class(lres) <- c("htest", "mc.sim") + lres +} diff --git a/R/normalized.moran.test.R b/R/normalized.moran.test.R new file mode 100644 index 00000000..073abe53 --- /dev/null +++ b/R/normalized.moran.test.R @@ -0,0 +1,91 @@ +normalized.moran.test <- function (x, listw, zero.policy = attr(listw, "zero.policy"), alternative = "greater", + na.action = na.fail, + spChk = NULL, adjust.n = TRUE) +{ + alternative <- match.arg(alternative, c("greater", "less", + "two.sided")) + wname <- deparse(substitute(listw)) + if (!inherits(listw, "listw")) + stop(wname, "is not a listw object") + xname <- deparse(substitute(x)) + if (!is.numeric(x)) + stop(xname, " is not a numeric vector") + if (is.null(attr(listw$weights, "W"))) + message(wname, " is not a listw object of style W, then it has been row-standardized") + if (is.null(zero.policy)) + zero.policy <- get.ZeroPolicyOption() + stopifnot(is.logical(zero.policy)) + stopifnot(length(zero.policy) == 1L) + if (is.null(spChk)) + spChk <- get.spChkOption() + stopifnot(is.logical(spChk)) + stopifnot(length(spChk) == 1L) + if (spChk && !chkIDs(x, listw)) + stop("Check of data and weights ID integrity failed") + stopifnot(length(na.action) == 1L) + NAOK <- deparse(substitute(na.action)) == "na.pass" + x <- na.action(x) + na.act <- attr(x, "na.action") + if (!is.null(na.act)) { + subset <- !(1:length(listw$neighbours) %in% na.act) + listw <- subset(listw, subset, zero.policy = zero.policy) + } + n <- length(listw$neighbours) + if (n != length(x)) + stop("objects of different length") + W <- listw2mat(listw) + if (is.null(attr(listw$weights, "W"))) + listw <- spdep::mat2listw(W, style="W", zero.policy = zero.policy) + I <- normalized.moran(x, listw, zero.policy = zero.policy, + NAOK = NAOK) + one <- rep(1,n) + In <- diag(rep(1,n)) + P <- In - one %*% t(one)/n + D <- diag(rowSums(W)) + invD <- solve(D) + B <- P %*% invD %*% W + C <- t(W) %*% invD %*% P %*% invD %*% W + B_tilde <- (B + t(B)) / 2 + + tr <- function(M) sum(diag(M)) + trP <- tr(P) + trC <- tr(C) + trB <- tr(B) + trB2_tilde <- tr(B_tilde %*% B_tilde) + trP2 <- tr(P %*% P) + trC2 <- tr(C %*% C) + trBP <- tr(B_tilde %*% P) + trBC <- tr(B_tilde %*% C) + trPC <- tr(P %*% C) + + EI <- -1/sqrt((n-1)*trC) + VI <- (2/(trP*trC)) * (trB2_tilde + trB^2/(4*trP^2)*trP2 + trB^2/(4*trC^2)*trC2 - + trB/trP*trBP - trB/trC*trBC + + trB^2/(2*trP*trC)*trPC) + if (VI < 0) + warning("Negative variance,\ndistribution of variable does not meet test assumptions") + ZI <- (I - EI)/sqrt(VI) + statistic <- ZI + names(statistic) <- "Normalized Moran I statistic standard deviate" + if (alternative == "two.sided") + PrI <- 2 * pnorm(abs(ZI), lower.tail = FALSE) + else if (alternative == "greater") + PrI <- pnorm(ZI, lower.tail = FALSE) + else PrI <- pnorm(ZI) + if (!is.finite(PrI) || PrI < 0 || PrI > 1) + warning("Out-of-range p-value: reconsider test arguments") + vec <- c(I, EI, VI) + names(vec) <- c("Normalized Moran I statistic", "Expectation", "Variance") + method <- "Normalized Moran I test under normality" + data.name <- paste(xname, "\nweights:", wname, ifelse(is.null(na.act), "", + paste("\nomitted:", paste(na.act, collapse = ", "))), + ifelse(adjust.n && isTRUE(any(sum(card(listw$neighbours) == + 0L))), "\nn reduced by no-neighbour observations", + ""), "", "\n") + res <- list(statistic = statistic, p.value = PrI, estimate = vec, + alternative = alternative, method = method, data.name = data.name) + if (!is.null(na.act)) + attr(res, "na.action") <- na.act + class(res) <- "htest" + res +} diff --git a/inst/tinytest/test_normalized.moran_NA.R b/inst/tinytest/test_normalized.moran_NA.R new file mode 100644 index 00000000..205c420a --- /dev/null +++ b/inst/tinytest/test_normalized.moran_NA.R @@ -0,0 +1,7 @@ +library(spdep) +data(oldcol) +lw <- nb2listw(COL.nb, style="W") +is.na(COL.OLD$CRIME) <- 1 +expect_error(o <- normalized.moran.test(COL.OLD$CRIME, lw)) +expect_warning(o <- normalized.moran.test(COL.OLD$CRIME, lw, na.action=na.pass)) +expect_silent(o <- normalized.moran.test(COL.OLD$CRIME, lw, na.action=na.omit)) diff --git a/man/normalized.moran.Rd b/man/normalized.moran.Rd new file mode 100644 index 00000000..fe98106c --- /dev/null +++ b/man/normalized.moran.Rd @@ -0,0 +1,46 @@ +\name{normalized.moran} +\alias{normalized.moran} +\title{Compute Normalized Moran's \eqn{I}} +\usage{ +normalized.moran( + x, + listw, + zero.policy = attr(listw, "zero.policy"), + NAOK = FALSE +) +} +\arguments{ +\item{x}{a numeric vector the same length as the neighbours list in listw} + +\item{listw}{a \code{listw} object of style 'W' created for example by \code{nb2listw}} + +\item{zero.policy}{default \code{attr(listw, "zero.policy")} as set when \code{listw} was created, if attribute not set, use global option value; if TRUE assign zero to the lagged value of zones without neighbours, if FALSE assign NA} + +\item{NAOK}{if 'TRUE' then any 'NA' or 'NaN' or 'Inf' values in x are passed on to the foreign function. If 'FALSE', the presence of 'NA' or 'NaN' or 'Inf' values is regarded as an error.} +} +\value{ +The normalized "\eqn{I_6}" Moran's \eqn{I} of the values in \code{x} is computed, as a numeric vector of length one. +} +\description{ +A simple function to compute the normalized "\eqn{I_6}" Moran's \eqn{I} statistic proposed by Tillé et al. (2026), called by \code{normalized.moran.test} and \code{normalized.moran.mc}. +} +\section{Author}{ + Diego Giuliani \email{diego.giuliani@unitn.it} +} + +\section{References}{ + Tillé Y., Giuliani D., Dickson M.M., Espa G. (2026) Revisiting the Normalization of the Moran's \eqn{I} index: A Correlation-based Approach with Inference, \emph{International Statistical Review} +} + +\examples{ +library(spdep) +data(oldcol) +col.W <- nb2listw(COL.nb, style="W") +crime <- COL.OLD$CRIME +normalized.moran(crime, col.W) +is.na(crime) <- sample(1:length(crime), 10) +normalized.moran(crime, col.W, NAOK=TRUE) +} +\seealso{ +\link{normalized.moran.test}, \link{normalized.moran.mc} +} diff --git a/man/normalized.moran.mc.Rd b/man/normalized.moran.mc.Rd new file mode 100644 index 00000000..d577419f --- /dev/null +++ b/man/normalized.moran.mc.Rd @@ -0,0 +1,93 @@ +\name{normalized.moran.mc} +\alias{normalized.moran.mc} +\title{Permutation test for normalized Moran's \eqn{I} statistic} +\usage{ +normalized.moran.mc( + x, + listw, + nsim, + zero.policy = attr(listw, "zero.policy"), + alternative = "greater", + na.action = na.fail, + spChk = NULL, + return_boot = FALSE, + adjust.n = TRUE +) +} +\arguments{ +\item{x}{a numeric vector the same length as the neighbours list in \code{listw}} + +\item{listw}{a \code{listw} object created for example by nb2listw} + +\item{nsim}{number of permutations} + +\item{zero.policy}{default \code{attr(listw, "zero.policy")} as set when \code{listw} was created, if attribute not set, use global option value; if TRUE assign zero to the lagged value of zones without neighbours, if FALSE assign NA} + +\item{alternative}{a character string specifying the alternative hypothesis, must be one of \code{greater} (default), \code{less} or \code{two.sided}} + +\item{na.action}{a function (default \code{na.fail}), can also be \code{na.omit} or \code{na.exclude} - in these cases the weights list will be subsetted to remove NAs in the data. It may be necessary to set \code{zero.policy} to TRUE because this subsetting may create no-neighbour observations. Note that only weights lists created without using the \code{glist} argument to \code{nb2listw} may be subsetted. If \code{na.pass} is used, zero is substituted for NA values in calculating the spatial lag} + +\item{spChk}{should the data vector names be checked against the spatial objects for identity integrity, TRUE, or FALSE, default NULL to use \code{get.spChkOption()}} + +\item{return_boot}{return an object of class \code{boot} from the equivalent permutation bootstrap rather than an object of class \code{htest}} + +\item{adjust.n}{default TRUE, if FALSE the number of observations is not adjusted for no-neighbour observations, if TRUE, the number of observations is adjusted} +} +\value{ +A list with class \code{htest} and \code{mc.sim} containing the following components: \describe{ +\item{\code{statistic}}{the value of the observed normalized Moran's I.} +\item{\code{parameter}}{the rank of the observed normalized Moran's I.} +\item{\code{p.value}}{the pseudo p-value of the test.} +\item{\code{alternative}}{a character string describing the alternative hypothesis.} +\item{\code{method}}{a character string giving the method used.} +\item{\code{data.name}}{a character string giving the name(s) of the data.} +\item{\code{res}}{\code{nsim} simulated values of statistic, final value is observed statistic.} +} +} +\description{ +A permutation test for the "\eqn{I_6}" normalized Moran's \eqn{I} statistic by Tillé et al. (2026) calculated by using \code{nsim} random permutations of \code{x} for the given spatial weighting scheme, to establish the rank of the observed statistic in relation to the \code{nsim} simulated values. +} +\section{Author}{ + Diego Giuliani \email{diego.giuliani@unitn.it} +} + +\section{References}{ + Tillé Y., Giuliani D., Dickson M.M., Espa G. (2026) Revisiting the Normalization of the Moran's \eqn{I} index: A Correlation-based Approach with Inference, \emph{International Statistical Review} +} + +\examples{ +library(spdep) +data(oldcol) +colw <- nb2listw(COL.nb, style="W") +nsim <- 99 +set.seed(1234) +sim1 <- normalized.moran.mc(COL.OLD$CRIME, listw=colw, nsim=nsim) +sim1 +mean(sim1$res[1:nsim]) +var(sim1$res[1:nsim]) +summary(sim1$res[1:nsim]) +colold.lags <- nblag(COL.nb, 3) +set.seed(1234) +sim2 <- normalized.moran.mc(COL.OLD$CRIME, nb2listw(colold.lags[[2]], + style="W"), nsim=nsim) +summary(sim2$res[1:nsim]) +sim3 <- normalized.moran.mc(COL.OLD$CRIME, nb2listw(colold.lags[[3]], + style="W"), nsim=nsim) +summary(sim3$res[1:nsim]) +crime <- COL.OLD$CRIME +is.na(crime) <- sample(1:length(crime), 10) +try(normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, + na.action=na.fail)) +normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, zero.policy=TRUE, + na.action=na.omit) +normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, zero.policy=TRUE, + return_boot=TRUE, na.action=na.omit) +normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, zero.policy=TRUE, + na.action=na.exclude) +normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, zero.policy=TRUE, + return_boot=TRUE, na.action=na.exclude) +try(normalized.moran.mc(crime, nb2listw(COL.nb, style="W"), nsim=99, na.action=na.pass)) +} +\seealso{ +\link{normalized.moran}, \link{normalized.moran.test} +} diff --git a/man/normalized.moran.test.Rd b/man/normalized.moran.test.Rd new file mode 100644 index 00000000..c5a3345a --- /dev/null +++ b/man/normalized.moran.test.Rd @@ -0,0 +1,68 @@ +\name{normalized.moran.test} +\alias{normalized.moran.test} +\title{Normalized Moran's \eqn{I} test for spatial autocorrelation} +\usage{ +normalized.moran.test( + x, + listw, + zero.policy = attr(listw, "zero.policy"), + alternative = "greater", + na.action = na.fail, + spChk = NULL, + adjust.n = TRUE +) +} +\arguments{ +\item{x}{a numeric vector the same length as the neighbours list in listw} + +\item{listw}{a \code{listw} object created for example by \code{nb2listw}} + +\item{zero.policy}{default \code{attr(listw, "zero.policy")} as set when \code{listw} was created, if attribute not set, use global option value; if TRUE assign zero to the lagged value of zones without neighbours, if FALSE assign NA} + +\item{alternative}{a character string specifying the alternative hypothesis, must be one of \code{greater} (default), \code{less} or \code{two.sided}} + +\item{na.action}{a function (default \code{na.fail}), can also be \code{na.omit} or \code{na.exclude} - in these cases the weights list will be subsetted to remove NAs in the data. It may be necessary to set \code{zero.policy} to TRUE because this subsetting may create no-neighbour observations. Note that only weights lists created without using the \code{glist} argument to \code{nb2listw} may be subsetted. If \code{na.pass} is used, zero is substituted for NA values in calculating the spatial lag} + +\item{spChk}{should the data vector names be checked against the spatial objects for identity integrity, TRUE, or FALSE, default NULL to use \code{get.spChkOption()}} + +\item{adjust.n}{default TRUE, if FALSE the number of observations is not adjusted for no-neighbour observations, if TRUE, the number of observations is adjusted} +} +\value{ +A list with class \code{htest} containing the following components: \describe{ +\item{\code{statistic}}{the value of the standard deviate of normalized Moran's I.} +\item{\code{p.value}}{the p-value of the test.} +\item{\code{estimate}}{the value of the observed normalized Moran's I, its expectation and variance under normality.} +\item{\code{alternative}}{a character string describing the alternative hypothesis.} +\item{\code{method}}{a character string giving the assumption used for calculating the standard deviate.} +\item{\code{data.name}}{a character string giving the name(s) of the data.} +} +} +\description{ +Normalized "\eqn{I_6}" Moran's test for spatial autocorrelation proposed by Tillé et al. (2026) using a spatial weights matrix in weights list form. The test assumes asymptotic normality, and results may be checked against those of \code{normalized.moran.mc} permutations. +} +\section{Author}{ + Diego Giuliani \email{diego.giuliani@unitn.it} +} + +\section{References}{ + Tillé Y., Giuliani D., Dickson M.M., Espa G. (2026) Revisiting the Normalization of the Moran's \eqn{I} index: A Correlation-based Approach with Inference, \emph{International Statistical Review} +} + +\examples{ +library(spdep) +data(oldcol) +coords.OLD <- cbind(COL.OLD$X, COL.OLD$Y) +normalized.moran.test(COL.OLD$CRIME, nb2listw(COL.nb, style="W")) +crime <- COL.OLD$CRIME +is.na(crime) <- sample(1:length(crime), 10) +res <- try(normalized.moran.test(crime, nb2listw(COL.nb, style="W"), + na.action=na.fail)) +normalized.moran.test(crime, nb2listw(COL.nb, style="W"), zero.policy=TRUE, + na.action=na.omit) +normalized.moran.test(crime, nb2listw(COL.nb, style="W"), zero.policy=TRUE, + na.action=na.exclude) +normalized.moran.test(crime, nb2listw(COL.nb, style="W"), na.action=na.pass) +} +\seealso{ +\link{normalized.moran}, \link{normalized.moran.mc} +} From 82612f11d554fb6f0ec719efb8ff899f33b689f2 Mon Sep 17 00:00:00 2001 From: Giuliani Date: Mon, 7 Sep 2026 14:53:43 +0200 Subject: [PATCH 2/5] Add normalized Moran's I functions, documentation, and tests --- ..Rcheck/00check.log | 13 +++++++++++++ .Rbuildignore | 2 ++ .gitignore | 7 +++++++ spdep.Rproj | 21 +++++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 ..Rcheck/00check.log create mode 100644 .gitignore create mode 100644 spdep.Rproj diff --git a/..Rcheck/00check.log b/..Rcheck/00check.log new file mode 100644 index 00000000..22b16190 --- /dev/null +++ b/..Rcheck/00check.log @@ -0,0 +1,13 @@ +* using log directory 'C:/Users/diego.giuliani/Desktop/assegno_2011/Pacchetto_normalizedMoran_per_spdep/spdep/..Rcheck' +* using R version 4.5.1 (2025-06-13 ucrt) +* using platform: x86_64-w64-mingw32 +* R was compiled by + gcc.exe (GCC) 14.2.0 + GNU Fortran (GCC) 14.2.0 +* running under: Windows 11 x64 (build 26200) +* using session charset: UTF-8 +* checking for file './DESCRIPTION' ... ERROR +Campi richiesti assenti o vuoti: + 'Author' 'Maintainer' +* DONE +Status: 1 ERROR diff --git a/.Rbuildignore b/.Rbuildignore index dafc09aa..a37ab933 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -7,3 +7,5 @@ README.md .github .git _pkgdown.yml +^.*\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..56843bca --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata +src/*.o +src/*.so +src/*.dll diff --git a/spdep.Rproj b/spdep.Rproj new file mode 100644 index 00000000..270314b8 --- /dev/null +++ b/spdep.Rproj @@ -0,0 +1,21 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace From f04277ba60509ca56602e08fcf3d723362b448af Mon Sep 17 00:00:00 2001 From: diegogiuliani-unitn Date: Wed, 9 Sep 2026 21:45:46 +0200 Subject: [PATCH 3/5] Delete spdep.Rproj --- spdep.Rproj | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 spdep.Rproj diff --git a/spdep.Rproj b/spdep.Rproj deleted file mode 100644 index 270314b8..00000000 --- a/spdep.Rproj +++ /dev/null @@ -1,21 +0,0 @@ -Version: 1.0 - -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default - -EnableCodeIndexing: Yes -UseSpacesForTab: Yes -NumSpacesForTab: 2 -Encoding: UTF-8 - -RnwWeave: Sweave -LaTeX: pdfLaTeX - -AutoAppendNewline: Yes -StripTrailingWhitespace: Yes - -BuildType: Package -PackageUseDevtools: Yes -PackageInstallArgs: --no-multiarch --with-keep.source -PackageRoxygenize: rd,collate,namespace From d295aebee9ad795fe9356b789a4704384e89e5f9 Mon Sep 17 00:00:00 2001 From: diegogiuliani-unitn Date: Wed, 9 Sep 2026 21:48:39 +0200 Subject: [PATCH 4/5] Update DESCRIPTION --- DESCRIPTION | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4d18d723..9970860f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -69,8 +69,7 @@ Suggests: rgeoda (>= 0.0.11.1), mipfp, Guerry, - codingMatrices, - testthat (>= 3.0.0) + codingMatrices URL: https://github.com/r-spatial/spdep/, https://r-spatial.github.io/spdep/ BugReports: https://github.com/r-spatial/spdep/issues/ Description: A collection of functions to create spatial weights matrix From 96f30d3a15cf0d9b98a90e8b5c97841f7983add3 Mon Sep 17 00:00:00 2001 From: diegogiuliani-unitn Date: Wed, 9 Sep 2026 21:50:36 +0200 Subject: [PATCH 5/5] Delete ..Rcheck directory --- ..Rcheck/00check.log | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 ..Rcheck/00check.log diff --git a/..Rcheck/00check.log b/..Rcheck/00check.log deleted file mode 100644 index 22b16190..00000000 --- a/..Rcheck/00check.log +++ /dev/null @@ -1,13 +0,0 @@ -* using log directory 'C:/Users/diego.giuliani/Desktop/assegno_2011/Pacchetto_normalizedMoran_per_spdep/spdep/..Rcheck' -* using R version 4.5.1 (2025-06-13 ucrt) -* using platform: x86_64-w64-mingw32 -* R was compiled by - gcc.exe (GCC) 14.2.0 - GNU Fortran (GCC) 14.2.0 -* running under: Windows 11 x64 (build 26200) -* using session charset: UTF-8 -* checking for file './DESCRIPTION' ... ERROR -Campi richiesti assenti o vuoti: - 'Author' 'Maintainer' -* DONE -Status: 1 ERROR