File: anova-glmrob.R

package info (click to toggle)
robustbase 0.99-6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 4,584 kB
  • sloc: fortran: 3,245; ansic: 3,243; sh: 15; makefile: 2
file content (156 lines) | stat: -rw-r--r-- 5,885 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

anova.glmrob <- function(object, ...,
                         test = c("Wald", "QD", "QDapprox"))
{
    dotargs <- list(...)
    if (!is.null(names(dotargs))) {
	named <- (names(dotargs) != "")
	if (any(named)) {
	    warning("the following arguments to 'anova.glmrob' are invalid and",
		    "dropped:\n",
		    pasteK(deparse(dotargs[named])))
	    dotargs <- dotargs[!named]
	}
    }
    is.glmrob <- vapply(dotargs, inherits, NA, what="glmrob")
    if(!all(is.glmrob) || !inherits(object, "glmrob"))
	stop("anova.glmrob() only works for 'glmrob' objects")
    test <- match.arg(test)
    if (length(dotargs) > 0)
	anovaGlmrobList(c(list(object), dotargs), test=test)
    else {
	##
	## "'Anova Table' for a single model object
	stop("'Anova Table' for a single model object not yet implemented")
    }
}


anovaGlmrobList <- function (object, test=NULL)
{
  nmodels <- length(object)
  stopifnot(nmodels >= 2)
  responses <- as.character(lapply(object,
				   function(x) deparse(formula(x)[[2]])))
  if (!all(responses == responses[1]))
    stop("Not the same response used in the fitted models")
  nobs <- sapply(object, function(x) length(x$residuals))
  if (any(nobs != nobs[1]))
        stop("models were not all fitted to the same size of dataset")
  methods <- as.character(lapply(object, function(x) x$method))
  if(!all(methods == methods[1]))
    stop("Not the same method used for fitting the models")
  note <- paste("Models fitted by method '", methods[1], "'", sep="")
  tccs <- sapply(object, function(x) length(x$tcc))
  if(!all(tccs == tccs[1]))
    stop("Not the same tuning constant c used in the robust fits")
  ##
  tbl <- matrix(rep(NA, nmodels*4), ncol = 4)
  tbl[1,1] <- nobs[1] - length(coef(object[[1]]))
  for(k in 2:nmodels)
    tbl[k,] <- anovaGlmrobPair(object[[k-1]], object[[k]], test=test)

  ## return
  dimnames(tbl) <- list(1:nmodels,
                        c("pseudoDf", "Test.Stat", "Df", "Pr(>chisq)"))
  title <- switch(test,
                  Wald = "Robust Wald Test Table",
                  QD = "Robust Quasi-Deviance Table",
                  QDapprox =
              "Robust Quasi-Deviance Table Based on a Quadratic Approximation",
                   "")
  variables <- lapply(object, function(x)
                      paste(deparse(formula(x)), collapse = "\n"))
  topnote <- paste("Model ", format(1:nmodels), ": ", variables,
                   sep = "", collapse = "\n")
  structure(as.data.frame(tbl), heading = c(title, "", topnote, note,""),
            class = c("anova", "data.frame"))
}


anovaGlmrobPair <- function(obj1, obj2, test)
{
  if(length(coef(obj1)) < length(coef(obj2))){
      Sign <- 1
      full.mfit <- obj2
      reduced.mfit <- obj1
  }
  else {
      Sign <- -1
      full.mfit <- obj1
      reduced.mfit <- obj2
  }
  X <- model.matrix(full.mfit)
  asgn <- attr(X, "assign")
  tt <- terms(full.mfit)
  tt0 <- terms(reduced.mfit)
  tl <- attr(tt, "term.labels")
  tl0 <- attr(tt0, "term.labels")
  numtl0 <- match(tl0 , tl, nomatch = -1)
  if(attr(tt0, "intercept") == 1) numtl0 <- c(0, numtl0)
  if(any(is.na(match(numtl0, unique(asgn)))))
    stop("Models are not nested!")
  mod0 <- seq(along = asgn)[!is.na(match(asgn, numtl0))]
  if (length(asgn) == length(mod0))
    stop("Models are not strictly nested")
  H0ind <- setdiff(seq(along = asgn), mod0)
  H0coef <- coef(full.mfit)[H0ind]
  df <- length(H0coef)
  pp <- df + length(mod0)

  if(test == "Wald") {
    t.cov <- full.mfit$cov
    t.chisq <- sum(H0coef * solve(t.cov[H0ind, H0ind], H0coef))
    statistic <- c(chisq = t.chisq)
  }
  else if(full.mfit$method=="Mqle" && (test == "QD" || test == "QDapprox")) {
      matM <- full.mfit$matM
      if(test == "QDapprox") {
        ## Difference of robust quasi-deviances
        ## via the asymptotically equivalent quadratic form
        matM11 <- matM[mod0,   mod0, drop=FALSE]
        matM12 <- matM[mod0,  H0ind, drop=FALSE]
        matM22 <- matM[H0ind, H0ind, drop=FALSE]
        matM22.1 <- matM22 - crossprod(matM12, solve(matM11, matM12))
        Dquasi.dev <- nrow(X) * c(H0coef %*% matM22.1 %*% H0coef)
      }
      else {
        quasiDev <- switch(full.mfit$family$family,
			   poisson  = glmrobMqleDiffQuasiDevPois,
			   binomial = glmrobMqleDiffQuasiDevB,
			   Gamma    = glmrobMqleDiffQuasiDevGamma,
                           stop("This family is not implemented"))

        ## note that qdev and qdev0 do depend on an incorrectly specified
        ## lower limits in the integration. But this does't matter in
        ## the following difference, because the difference does not
        ## deepend on it! (Hence I could use the centered nui
        ## (cnui= nui - Enui) in quasiDev as the function to be integrated.
        Dquasi.dev <- quasiDev(mu = full.mfit$fitted.values,
                               mu0 = reduced.mfit$fitted.values,
                               y = full.mfit$y, ni = full.mfit$ni,
                               w.x = full.mfit$w.x, phi=full.mfit$dispersion,
                               tcc = full.mfit$tcc)
      }
      ## Asymptotic distribution: variance and weights of the sum of chi2
      matQ <- full.mfit$matQ
      matM11inv <- solve(matM[mod0,mod0])
      Mplus <- matrix(0, ncol = pp, nrow = pp)
      Mplus[mod0, mod0] <- matM11inv

      d.ev <- Re(eigen(matQ %*% (solve(matM)-Mplus), only.values=TRUE)$values)
      d.ev <- d.ev[1:df] ## just the q (=df) lagest eigenvalues are needed

      if(any(d.ev < 0)) warning("some eigenvalues are negative")

      ## p-value: exact computation for q=1, approximated for q>1 (q=df)
      statistic <- c(quasi.dev = Dquasi.dev/mean(d.ev))

    } else stop("non-implemented test method:", test,
                "for fitting method", full.mfit$method)

  ## return
  c(nrow(X)-pp+df*(Sign<0), Sign*statistic, Sign*df,
    pchisq(as.vector(statistic), df=df, lower.tail = FALSE))
}