2016-09-08 1 views
3

Я оцениваю некоторые пространственные эконометрические модели, которые содержат как пространственный авторегрессионный член rho, так и пространственный коэффициент ошибки лямбда. При попытке сообщить свои результаты я использовал пакет texreg, который принимает модели sacsarlm, с которыми я работаю. Я заметил, однако, что texreg печатает значения p для параметров rho и лямбда, которые идентичны. Texreg, похоже, возвращает значение p, найденное в слоте [email protected]$p.value объекта модели.Вычисление p.values ​​в пространственных эконометрических моделях: почему существуют несоответствия между summary() и texreg()?

Параметры rho и лямбда различны по величине и имеют разные стандартные ошибки, поэтому они не должны иметь эквивалентных значений p. Если я вызываю резюме на объекте модели, я получаю уникальные значения p, но не могу понять, где эти значения хранятся в объекте модели, несмотря на то, что они проходят через каждый элемент в вызове str(model).

Мой вопрос имеет два аспекта:

  1. Я правильно думать, что это ошибка в texreg (и т.д. screenreg) функция или я заблуждающихся в моей интерпретации?
  2. Как вычислить правильное значение p или найти его в объекте модели (я пишу новую функцию извлечения для texreg и вам нужно найти правильное значение)?

Ниже приведен минимальный пример, который показывает проблему:

library(spdep) 
library(texreg) 
set.seed(42) 
W.ran <- matrix(rbinom(100*100, 1, .3),nrow=100) 
X <- rnorm(100) 
Y <- .2 * X + rnorm(100) + .9*(W.ran %*% X) 

W.test <- mat2listw(W.ran) 
model <- sacsarlm(Y~X, type = "sacmixed", 
       listw=W.test, zero.policy=TRUE) 
summary(model) 

Call:sacsarlm(formula = Y ~ X, listw = W.test, type = "sacmixed", 
    zero.policy = TRUE) 

Residuals: 
     Min  1Q Median  3Q  Max 
-2.379283 -0.750922 0.036044 0.675951 2.577148 

Type: sacmixed 
Coefficients: (asymptotic standard errors) 
        Estimate Std. Error z value Pr(>|z|) 
(Intercept)  0.91037455 0.65700059 1.3857 0.1659 
X    -0.00076362 0.10330510 -0.0074 0.9941 
lag.(Intercept) -0.03193863 0.02310075 -1.3826 0.1668 
lag.X   0.89764491 0.02231353 40.2287 <2e-16 

Rho: -0.0028541 
Asymptotic standard error: 0.0059647 
    z-value: -0.47849, p-value: 0.6323 
Lambda: -0.020578 
Asymptotic standard error: 0.020057 
    z-value: -1.026, p-value: 0.3049 

LR test value: 288.74, p-value: < 2.22e-16 

Log likelihood: -145.4423 for sacmixed model 
ML residual variance (sigma squared): 1.0851, (sigma: 1.0417) 
Number of observations: 100 
Number of parameters estimated: 7 
AIC: 304.88, (AIC for lm: 585.63) 

screenreg(model) 

================================= 
         Model 1  
--------------------------------- 
(Intercept)    0.91  
         (0.66) 
X      -0.00  
         (0.10) 
lag.(Intercept)   -0.03  
         (0.02) 
lag.X     0.90 *** 
         (0.02) 
--------------------------------- 
Num. obs.    100  
Parameters    7  
AIC (Linear model)  585.63  
AIC (Spatial model) 304.88  
Log Likelihood  -145.44  
Wald test: statistic  1.05  
Wald test: p-value  0.90  
Lambda: statistic  -0.02  
Lambda: p-value   0.00  
Rho: statistic   -0.00  
Rho: p-value    0.00  
================================= 
*** p < 0.001, ** p < 0.01, * p < 0.05 

Очевидно, что в данном примере, Ро и Лямбда имеют различные р-значения ни один из которых равны нулю, и, таким образом, существует проблема с выход texreg. Любая помощь в том, почему это происходит или где получить правильные значения p, очень ценится!

+1

Да, когда-то R является немного неясным - когда вы вызываете резюме, вероятность того, что значения, которые вы заинтересованы в не извлекаются из режима объект, но рассчитывается в этот момент суммарной функцией. Это не полный ответ, но вы должны проверить пакет «метла», который может предоставить важную информацию о модели в простой в использовании data.frame (обычно включая значения p и т. Д.) – jakub

+0

Почему бы просто не заменить вручную значения в выводе 'texreg'? Он выплескивает латекс или html afterall ... –

+0

Я посмотрю на пакет веников, спасибо @jakub. Я создаю выход латекса из тексрега внутри документа sweave, который вяжется в конечный продукт, поэтому его не практично делать ручное редактирование латекса. – gfgm

ответ

4

texreg автор здесь. Спасибо, что поймал это. Как описано в моем ответе here, texreg использует методы extract для извлечения соответствующей информации из любого типа (в настоящее время более 70 поддерживаемых) типов объектов модели. Похоже, что существует глюк в части GOF метода для объектов sarlm.

Вот что метод в настоящее время выглядит (как из texreg 1.36.13):

# extension for sarlm objects (spdep package) 
extract.sarlm <- function(model, include.nobs = TRUE, include.aic = TRUE, 
    include.loglik = TRUE, include.wald = TRUE, include.lambda = TRUE, 
    include.rho = TRUE, ...) { 
    s <- summary(model, ...) 

    names <- rownames(s$Coef) 
    cf <- s$Coef[, 1] 
    se <- s$Coef[, 2] 
    p <- s$Coef[, ncol(s$Coef)] 

    gof <- numeric() 
    gof.names <- character() 
    gof.decimal <- logical() 

    if (include.nobs == TRUE) { 
    n <- length(s$fitted.values) 
    param <- s$parameters 
    gof <- c(gof, n, param) 
    gof.names <- c(gof.names, "Num.\ obs.", "Parameters") 
    gof.decimal <- c(gof.decimal, FALSE, FALSE) 
    } 
    if (include.aic == TRUE) { 
    aic <- AIC(model) 
    aiclm <- s$AIC_lm.model 
    gof <- c(gof, aiclm, aic) 
    gof.names <- c(gof.names, "AIC (Linear model)", "AIC (Spatial model)") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 
    if (include.loglik == TRUE) { 
    ll <- s$LL 
    gof <- c(gof, ll) 
    gof.names <- c(gof.names, "Log Likelihood") 
    gof.decimal <- c(gof.decimal, TRUE) 
    } 
    if (include.wald == TRUE) { 
    waldstat <- s$Wald1$statistic 
    waldp <- s$Wald1$p.value 
    gof <- c(gof, waldstat, waldp) 
    gof.names <- c(gof.names, "Wald test: statistic", "Wald test: p-value") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 
    if (include.lambda == TRUE && !is.null(s$lambda)) { 
    lambda <- s$lambda 
    LRpval <- s$LR1$p.value[1] 
    gof <- c(gof, lambda, LRpval) 
    gof.names <- c(gof.names, "Lambda: statistic", "Lambda: p-value") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 
    if (include.rho == TRUE && !is.null(s$rho)) { 
    rho <- s$rho 
    LRpval <- s$LR1$p.value[1] 
    gof <- c(gof, rho, LRpval) 
    gof.names <- c(gof.names, "Rho: statistic", "Rho: p-value") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 

    tr <- createTexreg(
     coef.names = names, 
     coef = cf, 
     se = se, 
     pvalues = p, 
     gof.names = gof.names, 
     gof = gof, 
     gof.decimal = gof.decimal 
) 
    return(tr) 
} 

setMethod("extract", signature = className("sarlm", "spdep"), 
    definition = extract.sarlm) 

Я думаю, вы правы, что лямбда и Rho части нуждаются в обновлении. sacsarlm функция не сохраняет результаты, выводимые его метод summary в любом объекте, так что вы справедливо указывая на то, что любые попытки использовать str не появляются, чтобы показать истинный р-значение и т.д.

Поэтому имеет смысл брать посмотрите, что делает функция print.summary.sarlm в пакете spdep, когда он печатает сводку. Я нашел код для этой функции в файле R/summary.spsarlm.R в source code of the package on CRAN. Это выглядит следующим образом:

print.summary.sarlm <- function(x, digits = max(5, .Options$digits - 3), 
    signif.stars = FALSE, ...) 
{ 
    cat("\nCall:", deparse(x$call), sep = "", fill=TRUE) 
     if (x$type == "error") if (isTRUE(all.equal(x$lambda, x$interval[1])) || 
      isTRUE(all.equal(x$lambda, x$interval[2]))) 
      warning("lambda on interval bound - results should not be used") 
     if (x$type == "lag" || x$type == "mixed") 
      if (isTRUE(all.equal(x$rho, x$interval[1])) || 
      isTRUE(all.equal(x$rho, x$interval[2]))) 
      warning("rho on interval bound - results should not be used") 
    cat("\nResiduals:\n") 
    resid <- residuals(x) 
    nam <- c("Min", "1Q", "Median", "3Q", "Max") 
    rq <- if (length(dim(resid)) == 2L) 
     structure(apply(t(resid), 1, quantile), dimnames = list(nam, 
      dimnames(resid)[[2]])) 
    else structure(quantile(resid), names = nam) 
    print(rq, digits = digits, ...) 
    cat("\nType:", x$type, "\n") 
    if (x$zero.policy) { 
     zero.regs <- attr(x, "zero.regs") 
     if (!is.null(zero.regs)) 
      cat("Regions with no neighbours included:\n", 
      zero.regs, "\n") 
    } 
     if (!is.null(x$coeftitle)) { 
     cat("Coefficients:", x$coeftitle, "\n") 
     coefs <- x$Coef 
     if (!is.null(aliased <- x$aliased) && any(x$aliased)){ 
     cat(" (", table(aliased)["TRUE"], 
      " not defined because of singularities)\n", sep = "") 
     cn <- names(aliased) 
     coefs <- matrix(NA, length(aliased), 4, dimnames = list(cn, 
        colnames(x$Coef))) 
       coefs[!aliased, ] <- x$Coef 
     } 
     printCoefmat(coefs, signif.stars=signif.stars, digits=digits, 
     na.print="NA") 
    } 
# res <- LR.sarlm(x, x$lm.model) 
    res <- x$LR1 
     pref <- ifelse(x$ase, "Asymptotic", "Approximate (numerical Hessian)") 
    if (x$type == "error") { 
     cat("\nLambda: ", format(signif(x$lambda, digits)), 
      ", LR test value: ", format(signif(res$statistic, 
         digits)), ", p-value: ", format.pval(res$p.value, 
         digits), "\n", sep="") 
     if (!is.null(x$lambda.se)) { 
        if (!is.null(x$adj.se)) { 
         x$lambda.se <- sqrt((x$lambda.se^2)*x$adj.se) 
        } 
      cat(pref, " standard error: ", 
       format(signif(x$lambda.se, digits)), 
      ifelse(is.null(x$adj.se), "\n z-value: ", 
           "\n t-value: "), format(signif((x$lambda/ 
       x$lambda.se), digits)), 
      ", p-value: ", format.pval(2*(1-pnorm(abs(x$lambda/ 
       x$lambda.se))), digits), "\n", sep="") 
      cat("Wald statistic: ", format(signif(x$Wald1$statistic, 
      digits)), ", p-value: ", format.pval(x$Wald1$p.value, 
      digits), "\n", sep="") 
     } 
    } else if (x$type == "sac" || x$type == "sacmixed") { 
     cat("\nRho: ", format(signif(x$rho, digits)), "\n", 
        sep="") 
       if (!is.null(x$rho.se)) { 
        if (!is.null(x$adj.se)) { 
         x$rho.se <- sqrt((x$rho.se^2)*x$adj.se) 
        } 
      cat(pref, " standard error: ", 
      format(signif(x$rho.se, digits)), 
         ifelse(is.null(x$adj.se), "\n z-value: ", 
           "\n t-value: "), 
      format(signif((x$rho/x$rho.se), digits)), 
      ", p-value: ", format.pval(2 * (1 - pnorm(abs(x$rho/ 
       x$rho.se))), digits), "\n", sep="") 
       } 
     cat("Lambda: ", format(signif(x$lambda, digits)), "\n", sep="") 
     if (!is.null(x$lambda.se)) { 
        pref <- ifelse(x$ase, "Asymptotic", 
         "Approximate (numerical Hessian)") 
        if (!is.null(x$adj.se)) { 
         x$lambda.se <- sqrt((x$lambda.se^2)*x$adj.se) 
        } 
      cat(pref, " standard error: ", 
       format(signif(x$lambda.se, digits)), 
      ifelse(is.null(x$adj.se), "\n z-value: ", 
           "\n t-value: "), format(signif((x$lambda/ 
       x$lambda.se), digits)), 
      ", p-value: ", format.pval(2*(1-pnorm(abs(x$lambda/ 
       x$lambda.se))), digits), "\n", sep="") 
       } 
       cat("\nLR test value: ", format(signif(res$statistic, digits)), 
      ", p-value: ", format.pval(res$p.value, digits), "\n", 
        sep="") 
     } else { 
     cat("\nRho: ", format(signif(x$rho, digits)), 
        ", LR test value: ", format(signif(res$statistic, digits)), 
      ", p-value: ", format.pval(res$p.value, digits), "\n", 
        sep="") 
       if (!is.null(x$rho.se)) { 
        if (!is.null(x$adj.se)) { 
         x$rho.se <- sqrt((x$rho.se^2)*x$adj.se) 
        } 
      cat(pref, " standard error: ", 
      format(signif(x$rho.se, digits)), 
         ifelse(is.null(x$adj.se), "\n z-value: ", 
           "\n t-value: "), 
      format(signif((x$rho/x$rho.se), digits)), 
      ", p-value: ", format.pval(2 * (1 - pnorm(abs(x$rho/ 
       x$rho.se))), digits), "\n", sep="") 
       } 
     if (!is.null(x$Wald1)) { 
      cat("Wald statistic: ", format(signif(x$Wald1$statistic, 
      digits)), ", p-value: ", format.pval(x$Wald1$p.value, 
      digits), "\n", sep="") 
     } 

    } 
    cat("\nLog likelihood:", logLik(x), "for", x$type, "model\n") 
    cat("ML residual variance (sigma squared): ", 
     format(signif(x$s2, digits)), ", (sigma: ", 
     format(signif(sqrt(x$s2), digits)), ")\n", sep="") 
     if (!is.null(x$NK)) cat("Nagelkerke pseudo-R-squared:", 
      format(signif(x$NK, digits)), "\n") 
    cat("Number of observations:", length(x$residuals), "\n") 
    cat("Number of parameters estimated:", x$parameters, "\n") 
    cat("AIC: ", format(signif(AIC(x), digits)), ", (AIC for lm: ", 
     format(signif(x$AIC_lm.model, digits)), ")\n", sep="") 
    if (x$type == "error") { 
     if (!is.null(x$Haus)) { 
      cat("Hausman test: ", format(signif(x$Haus$statistic, 
      digits)), ", df: ", format(x$Haus$parameter), 
         ", p-value: ", format.pval(x$Haus$p.value, digits), 
         "\n", sep="") 
     } 
     } 
    if ((x$type == "lag" || x$type == "mixed") && x$ase) { 
     cat("LM test for residual autocorrelation\n") 
     cat("test value: ", format(signif(x$LMtest, digits)), 
      ", p-value: ", format.pval((1 - pchisq(x$LMtest, 1)), 
      digits), "\n", sep="") 
    } 
     if (x$type != "error" && !is.null(x$LLCoef)) { 
     cat("\nCoefficients: (log likelihood/likelihood ratio)\n") 
     printCoefmat(x$LLCoef, signif.stars=signif.stars, 
      digits=digits, na.print="NA") 
     } 
     correl <- x$correlation 
     if (!is.null(correl)) { 
      p <- NCOL(correl) 
      if (p > 1) { 
        cat("\n", x$correltext, "\n") 
        correl <- format(round(correl, 2), nsmall = 2, 
        digits = digits) 
        correl[!lower.tri(correl)] <- "" 
        print(correl[-1, -p, drop = FALSE], quote = FALSE) 
       } 
     } 
     cat("\n") 
     invisible(x) 
} 

Вы можете видеть, что функция первой различает между различными субмоделями (error против sac/sacmixed против другого), а затем решает, какие стандартные ошибки в использовании, а затем вычисляет p-значения на лету, не сохраняя их нигде.

Так вот что нам нужно сделать в нашем методе extract, чтобы получить тот же результат, что и метод summary в пакете spdep. Нам также необходимо перенести это из блока GOF до блока коэффициентов таблицы (см. Раздел комментариев ниже для обсуждения). Вот моя попытка принятия их подхода в методе extract:

# extension for sarlm objects (spdep package) 
extract.sarlm <- function(model, include.nobs = TRUE, include.loglik = TRUE, 
    include.aic = TRUE, include.lr = TRUE, include.wald = TRUE, ...) { 
    s <- summary(model, ...) 

    names <- rownames(s$Coef) 
    cf <- s$Coef[, 1] 
    se <- s$Coef[, 2] 
    p <- s$Coef[, ncol(s$Coef)] 

    if (model$type != "error") { # include coefficient for autocorrelation term 
    rho <- model$rho 
    cf <- c(cf, rho) 
    names <- c(names, "$\\rho$") 
    if (!is.null(model$rho.se)) { 
     if (!is.null(model$adj.se)) { 
     rho.se <- sqrt((model$rho.se^2) * model$adj.se) 
     } else { 
     rho.se <- model$rho.se 
     } 
     rho.pval <- 2 * (1 - pnorm(abs(rho/rho.se))) 
     se <- c(se, rho.se) 
     p <- c(p, rho.pval) 
    } else { 
     se <- c(se, NA) 
     p <- c(p, NA) 
    } 
    } 

    if (!is.null(model$lambda)) { 
    cf <-c(cf, model$lambda) 
    names <- c(names, "$\\lambda$") 
    if (!is.null(model$lambda.se)) { 
     if (!is.null(model$adj.se)) { 
     lambda.se <- sqrt((model$lambda.se^2) * model$adj.se) 
     } else { 
     lambda.se <- model$lambda.se 
     } 
     lambda.pval <- 2 * (1 - pnorm(abs(model$lambda/lambda.se))) 
     se <- c(se, lambda.se) 
     p <- c(p, lambda.pval) 
    } else { 
     se <- c(se, NA) 
     p <- c(p, NA) 
    } 
    } 

    gof <- numeric() 
    gof.names <- character() 
    gof.decimal <- logical() 

    if (include.nobs == TRUE) { 
    n <- length(s$fitted.values) 
    param <- s$parameters 
    gof <- c(gof, n, param) 
    gof.names <- c(gof.names, "Num.\ obs.", "Parameters") 
    gof.decimal <- c(gof.decimal, FALSE, FALSE) 
    } 
    if (include.loglik == TRUE) { 
    ll <- s$LL 
    gof <- c(gof, ll) 
    gof.names <- c(gof.names, "Log Likelihood") 
    gof.decimal <- c(gof.decimal, TRUE) 
    } 
    if (include.aic == TRUE) { 
    aic <- AIC(model) 
    aiclm <- s$AIC_lm.model 
    gof <- c(gof, aiclm, aic) 
    gof.names <- c(gof.names, "AIC (Linear model)", "AIC (Spatial model)") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 
    if (include.lr == TRUE && !is.null(s$LR1)) { 
    gof <- c(gof, s$LR1$statistic[[1]], s$LR1$p.value[[1]]) 
    gof.names <- c(gof.names, "LR test: statistic", "LR test: p-value") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 
    if (include.wald == TRUE && !is.null(model$Wald1)) { 
    waldstat <- model$Wald1$statistic 
    waldp <- model$Wald1$p.value 
    gof <- c(gof, waldstat, waldp) 
    gof.names <- c(gof.names, "Wald test: statistic", "Wald test: p-value") 
    gof.decimal <- c(gof.decimal, TRUE, TRUE) 
    } 

    tr <- createTexreg(
     coef.names = names, 
     coef = cf, 
     se = se, 
     pvalues = p, 
     gof.names = gof.names, 
     gof = gof, 
     gof.decimal = gof.decimal 
) 
    return(tr) 
} 

setMethod("extract", signature = className("sarlm", "spdep"), 
    definition = extract.sarlm) 

Вы можете просто выполнить этот код во время выполнения обновления пути texreg обрабатывает эти объекты. Пожалуйста, дайте мне знать, если вы все еще думаете, что есть какие-то глюки, которые я не заметил. Если в комментариях ничего не сообщается, я включу этот обновленный метод extract в следующем выпуске texreg.

С учетом этих изменений, вызывая screenreg(model, single.row = TRUE) дает следующий результат:

======================================= 
        Model 1   
--------------------------------------- 
(Intercept)    0.91 (0.66)  
X      -0.00 (0.10)  
lag.(Intercept)  -0.03 (0.02)  
lag.X     0.90 (0.02) *** 
rho     -0.00 (0.01)  
lambda     -0.02 (0.02)  
--------------------------------------- 
Num. obs.    100    
Parameters    7    
Log Likelihood  -145.44   
AIC (Linear model) 585.63   
AIC (Spatial model) 304.88   
LR test: statistic 288.74   
LR test: p-value  0.00   
======================================= 
*** p < 0.001, ** p < 0.01, * p < 0.05 
+0

Это невероятно тщательный ответ, спасибо! Фактически, я уже написал (гораздо менее полную) функцию извлечения для модели саксарма, которую я оценивал (мне нужны были определенные изменения, а также перемещение местоположения rho и лямбда вплоть до коэффициентов) и вычисляемые значения p в обычным способом. Ваша идея искать в источнике spdep для того, что именно делала сводка (вместо того, чтобы реконструировать ее путем угадывания), гораздо разумнее. Кроме того, я думаю, что создание texreg, расширяемое функцией extract, было отличной идеей, и я очень благодарен вам за то, что написал это так! – gfgm

+0

Рад помочь. На ваш взгляд, какой будет идеальный порядок предметов в блоке GOF? –

+0

Ну, я действительно перевел Ро и Лямбду в колонку коэффициентов наверху. Rho является основным коэффициентом интереса в моем исследовании, поскольку я использую его для захвата эффектов сверстников в сетевом анализе. Это не является необычным способом использования этих моделей, и если это так, то вы, конечно, хотите, чтобы коэффициенты пространственной автокорреляции отображались как коэффициенты. На самом деле, как extract.lnam() делает это, если вы используете версию lnam этого вида пространственной модели из пакета sna (ее гораздо медленнее, поэтому я использую spdep). – gfgm