Thanks Roger for the ideas! Finally the problem was with the input for the glm.nb function. I copy bellow the modified function ME() for negative binomial models. It is possible that gives some warnings because with some eigenvectors the nb model might not converge.
ME.nb <- function (formula, data, weights,listw, alpha = 0.05, nsim = 99, verbose = TRUE, stdev = FALSE) { #Moran's Index MoraneI.boot <- function(var, i, ...) { var <- var[i] I <- (n/S0) * (crossprod(sW %*% var, var))/cpvar return(c(as(I, "matrix"))) } #Test Moran's Index MIR_a <- function(resids, sW, n, cpvar, S0, nsim, stdev = TRUE) { boot1 <- boot(resids, statistic = MoraneI.boot, R = nsim, sim = "permutation", sW = sW, n = n, S0 = S0, cpvar = cpvar) mi <- boot1$t0 if (stdev) { zi <- (boot1$t0 - mean(boot1$t))/sqrt(var(boot1$t)) pri <- pnorm(abs(zi), lower.tail = FALSE) } else { zi <- NA pri <- (sum(boot1$t >= mi) + 1)/(nsim + 1) } res <- list(estimate = mi, statistic = zi, p.value = pri) res } if (is.null(verbose)) verbose <- get("verbose", env = .spdepOptions) stopifnot(is.logical(verbose)) listw <- listw2U(listw) sW <- as_dgRMatrix_listw(listw) sW <- as(sW, "CsparseMatrix") Wmat <- listw2mat(listw) n <- ncol(Wmat) S0 <- Szero(listw) if (missing(data)) data <- environment(formula) mf <- match.call(expand.dots = FALSE) m <- match(c("formula", "data", "weights", "offset"), names(mf),0) mf <- mf[c(1, m)] mf$drop.unused.levels <- TRUE mf[[1]] <- as.name("model.frame") mf <- eval(mf, parent.frame()) mt <- attr(mf, "terms") X <- model.matrix(mt, mf) Y <- model.extract(mf, "response") weights <- model.weights(mf) if (!is.null(weights) && any(weights < 0)) stop("negative weights not allowed") offset <- model.offset(mf) if (!is.null(offset) && length(offset) != NROW(Y)) stop("number of offsets should equal number of observations") #Fit model glm_fit0 <- glm.nb(formula,data=data) glm_res <- glm_fit0$y - glm_fit0$fitted.values cpvar <- crossprod(glm_res) mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, S0 = S0,nsim = nsim, stdev = stdev) pIZ <- mRES$p.value tres <- c(NA, mRES$statistic, pIZ) if (pIZ > alpha) stop("base correlation larger than alpha") Cent <- diag(n) - (matrix(1, n, n)/n) eV <- eigen(Cent %*% Wmat %*% Cent, EISPACK = TRUE)$vectors rm(Cent, Wmat) iZ <- numeric(n) # Select eigenvectors that reduce Moran's Index for (i in 1:n) { iX <- cbind(X, eV[, i]) i_glm <- glm.nb(Y~iX) glm_res <- i_glm$y - i_glm$fitted.values cpvar <- crossprod(glm_res) iZ[i] <- c(as((n/S0) * (crossprod(sW %*% glm_res, glm_res))/cpvar,"matrix")) } min_iZ <- which.min(abs(iZ)) X <- cbind(X, eV[, min_iZ]) glm_fit <- glm.nb(Y~X) glm_res <- glm_fit$y - glm_fit$fitted.values cpvar <- crossprod(glm_res) mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, S0 = S0, nsim = nsim, stdev = stdev) pIZ <- mRES$p.value used <- rep(FALSE, n) used[min_iZ] <- TRUE min_v <- min_iZ if (verbose) cat("eV[,", min_iZ, "], I: ", mRES$estimate, " ZI: ",mRES$statistic, ", pr(ZI): ", pIZ, "\n", sep = "") tres <- rbind(tres, c(min_iZ, mRES$statistic, pIZ)) # Try rest eigenvectors till Moran's index is not significant while (pIZ <= alpha) { for (i in 1:n) { if (!used[i]) { iX <- cbind(X, eV[, i]) i_glm <- glm.nb(Y~iX) glm_res <- i_glm$y - i_glm$fitted.values cpvar <- crossprod(glm_res) iZ[i] <- c(as((n/S0) * (crossprod(sW %*% glm_res,glm_res))/cpvar, "matrix")) } else iZ[i] <- NA } min_iZ <- which.min(abs(iZ)) X <- cbind(X, eV[, min_iZ]) glm_fit <- glm.nb(Y~X) glm_res <- glm_fit$y - glm_fit$fitted.values cpvar <- crossprod(glm_res) mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, S0 = S0, nsim = nsim, stdev = stdev) pIZ <- mRES$p.value used[min_iZ] <- TRUE min_v <- c(min_v, min_iZ) if (verbose) cat("eV[,", min_iZ, "], I: ", mRES$estimate, " ZI: ", mRES$statistic, ", pr(ZI): ", pIZ, "\n", sep = "") tres <- rbind(tres, c(min_iZ, mRES$statistic, pIZ)) } sv <- eV[, min_v, drop = FALSE] colnames(sv) <- paste("vec", min_v, sep = "") colnames(tres) <- c("Eigenvector", "ZI", "pr(ZI)") rownames(tres) <- 0:(nrow(tres) - 1) res <- list(selection = tres, vectors = sv,eV=eV) class(res) <- "ME_res" res } 2012/1/31 Roger Bivand <roger.biv...@nhh.no> > On Tue, 31 Jan 2012, Pablo Gonzalez wrote: > > Dear all, >> >> I am trying to modify the function ME() of the package spdep to reduce the >> spatial autocorrelation problem of a negative binomial model by Spatial >> Eigenvector Mapping (Dray et al 2006, Dormann et al 2007). I am having >> problems to use the eigenvectors created because they include complex >> numbers and the negative binomial function, glm.nb(), doesn't allow such >> numbers. >> > > The usual reason for complex eigenvectors from weights matrices is that > they are asymmetric. In your editing of ME(), did you remove the line > making sure that W is symmetric: > > listw <- listw2U(listw) # make weights symmetric > > Try doing bits manually outside your draft function. If: > > Wmat <- listw2mat(listw) # convert to full matrix form > > Cent <- diag(n) - (matrix(1, n, n)/n) > eV <- eigen(Cent %*% Wmat %*% Cent, EISPACK=TRUE)$vectors > > eV are complex, something odd is going on, and maybe the EISPACK=TRUE is > an issue. Are all the Im(eV) zero? > > Roger > > > >> Honestly, I don't know why the function eigen() create eigenvectors with >> complex numbers. It might be a problem of the spatial weight matrix which >> includes points without neighbours or the complexity itself of the matrix. >> When I use the function ME() in its original form for a glm with poisson >> family it works because the function glm() seems to accept complex >> predictors. >> >> Could be possible to force only real eigenvectors or to allow complex >> predictors in NB glms?? I appreciate any help. Thank you very much in >> advance! >> >> If it helps, I copy bellow the modified function: >> >> ME.nb <- function (formula, data, listw, weights,alpha = 0.05, nsim = 99, >> verbose = TRUE, stdev = FALSE) >> { >> #Moran's Index >> MoraneI.boot <- function(var, i, ...) { >> var <- var[i] >> I <- (n/S0) * (crossprod(sW %*% var, var))/cpvar >> return(c(as(I, "matrix"))) >> } >> #Test Moran's Index >> MIR_a <- function(resids, sW, n, cpvar, S0, nsim, stdev = TRUE) { >> boot1 <- boot(resids, statistic = MoraneI.boot, R = nsim, >> sim = "permutation", sW = sW, n = n, S0 = S0, cpvar = cpvar) >> mi <- boot1$t0 >> if (stdev) { >> zi <- (boot1$t0 - mean(boot1$t))/sqrt(var(boot1$**t)) >> pri <- pnorm(abs(zi), lower.tail = FALSE) >> } >> else { >> zi <- NA >> pri <- (sum(boot1$t >= mi) + 1)/(nsim + 1) >> } >> res <- list(estimate = mi, statistic = zi, p.value = pri) >> res >> } >> if (is.null(verbose)) >> verbose <- get("verbose", env = .spdepOptions) >> stopifnot(is.logical(verbose)) >> listw <- listw2U(listw) >> sW <- as_dgRMatrix_listw(listw) >> sW <- as(sW, "CsparseMatrix") >> Wmat <- listw2mat(listw) >> n <- ncol(Wmat) >> S0 <- Szero(listw) >> >> if (missing(data)) >> data <- environment(formula) >> mf <- match.call(expand.dots = FALSE) >> m <- match(c("formula", "data", "weights", "offset"), names(mf),0) >> mf <- mf[c(1, m)] >> mf$drop.unused.levels <- TRUE >> mf[[1]] <- as.name("model.frame") >> mf <- eval(mf, parent.frame()) >> mt <- attr(mf, "terms") >> Y <- model.extract(mf, "response") >> X <- model.matrix(mt, mf) >> weights <- model.weights(mf) >> if (!is.null(weights) && any(weights < 0)) >> stop("negative weights not allowed") >> offset <- model.offset(mf) >> if (!is.null(offset) && length(offset) != NROW(Y)) >> stop("number of offsets should equal number of observations") >> #Fit model >> glm_fit <- glm.nb(formula,data=data) >> glm_res <- glm_fit$y - glm_fit$fitted.values >> cpvar <- crossprod(glm_res) >> mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, S0 = S0, >> nsim = nsim, stdev = stdev) >> pIZ <- mRES$p.value >> print(pIZ) >> tres <- c(NA, mRES$statistic, pIZ) >> if (pIZ > alpha) >> stop("base correlation larger than alpha") >> Cent <- diag(n) - (matrix(1, n, n)/n) >> #Create eigenvectors of the Spatial Weights matrix >> eV <- eigen(Cent %*% Wmat %*% Cent, EISPACK = TRUE)$vectors >> str(eV) >> rm(Cent, Wmat) >> iZ <- numeric(n) >> # Select eigenvectors that reduce Moran's Index >> for (i in 1:n) { >> iX <- eV[,i] >> i_glm <- update(glm_fit, .~.+ iX) >> glm_res <- i_glm$y - i_glm$fitted.values >> cpvar <- crossprod(glm_res) >> iZ[i] <- c(as((n/S0) * (crossprod(sW %*% glm_res, >> glm_res))/cpvar,"matrix")) >> } >> min_iZ <- which.min(abs(iZ)) >> X <- eV[, min_iZ] >> glm_fit <- update(glm_fit, .~.+ X) >> glm_res <- glm_fit$y - glm_fit$fitted.values >> cpvar <- crossprod(glm_res) >> mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, S0 = S0, >> nsim = nsim, stdev = stdev) >> pIZ <- mRES$p.value >> used <- rep(FALSE, n) >> used[min_iZ] <- TRUE >> min_v <- min_iZ >> if (verbose) >> cat("eV[,", min_iZ, "], I: ", mRES$estimate, " ZI: ", >> mRES$statistic, ", pr(ZI): ", pIZ, "\n", sep = "") >> tres <- rbind(tres, c(min_iZ, mRES$statistic, pIZ)) >> # Try rest eigenvectors till Moran's index is not significant >> while (pIZ <= alpha) { >> for (i in 1:n) { >> if (!used[i]) { >> iX <- eV[,i] >> i_glm <- update(glm_fit, .~.+ iX) >> glm_res <- i_glm$y - i_glm$fitted.values >> cpvar <- crossprod(glm_res) >> iZ[i] <- c(as((n/S0) * (crossprod(sW %*% glm_res, >> glm_res))/cpvar, "matrix")) >> } >> else iZ[i] <- NA >> } >> min_iZ <- which.min(abs(iZ)) >> X <- eV[, min_iZ] >> glm_fit <- update(glm_fit, .~.+ X) >> glm_res <- glm_fit$y - glm_fit$fitted.values >> cpvar <- crossprod(glm_res) >> mRES <- MIR_a(glm_res, sW = sW, n = n, cpvar = cpvar, >> S0 = S0, nsim = nsim, stdev = stdev) >> pIZ <- mRES$p.value >> used[min_iZ] <- TRUE >> min_v <- c(min_v, min_iZ) >> if (verbose) >> cat("eV[,", min_iZ, "], I: ", mRES$estimate, " ZI: ", >> mRES$statistic, ", pr(ZI): ", pIZ, "\n", sep = "") >> tres <- rbind(tres, c(min_iZ, mRES$statistic, pIZ)) >> } >> sv <- eV[, min_v, drop = FALSE] >> colnames(sv) <- paste("vec", min_v, sep = "") >> colnames(tres) <- c("Eigenvector", "ZI", "pr(ZI)") >> rownames(tres) <- 0:(nrow(tres) - 1) >> res <- list(selection = tres, vectors = sv) >> class(res) <- "ME_res" >> res >> } >> >> >> >> > -- > Roger Bivand > Department of Economics, NHH Norwegian School of Economics, > Helleveien 30, N-5045 Bergen, Norway. > voice: +47 55 95 93 55; fax +47 55 95 95 43 > e-mail: roger.biv...@nhh.no > > -- Pablo González Moreno Department of Integrative Ecology Estación Biológica de Doñana (EBD-CSIC) Avda. Américo Vespucio s/n 41092 Sevilla Tel: 954 466700 (Ext. 1463) Fax: 954 621125 [[alternative HTML version deleted]]
_______________________________________________ R-sig-Geo mailing list R-sig-Geo@r-project.org https://stat.ethz.ch/mailman/listinfo/r-sig-geo