IQSS / Zelig

A statistical framework that serves as a common interface to a large range of models

Home Page:http://zeligproject.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Odds ratios for relogit

christophergandrud opened this issue · comments

For example:

library(Zelig)
data(mid)
 
z.out1 <- zelig(conflict ~ major + contig + power + maxdem + mindem + years,
                    data = mid, model = "relogit", tau = 1042/303772,
                    cite = FALSE, case.control = "weighting")

summary(z.out1, odds_ratios = TRUE)

## Model: 
## 
## Call:
## relogit(formula = cbind(conflict, 1 - conflict) ~ major + contig + 
##     power + maxdem + mindem + years, data = as.data.frame(.), 
##     tau = 0.00343020423212146, bias.correct = TRUE, case.control = "weighting")
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -0.94933  -0.04958  -0.02173   0.19019   0.48253  
## 
## Coefficients:
##             Estimate (OR) Std. Error (OR, robust) z value Pr(>|z|)    
## (Intercept)      0.001335                1.373658 -20.848  < 2e-16 ***
## major            5.323748                1.321046   6.006  1.9e-09 ***
## contig          55.501077                1.258019  17.498  < 2e-16 ***
## power            1.334239                1.515488   0.694 0.487925    
## maxdem           1.068533                1.019434   3.444 0.000573 ***
## mindem           0.921799                1.030414  -2.718 0.006572 ** 
## years            0.889520                1.013448  -8.764  < 2e-16 ***
## ---
## Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
## 
##     Null deviance: 143.116  on 3125  degrees of freedom
## Residual deviance:  91.178  on 3119  degrees of freedom
## AIC: 27.041
## 
## Number of Fisher Scoring iterations: 10

Great addition. Thanks.

@christophergandrud I just had a look at the code and the way you are calculating the SE Odds Ratio is almost certainly wrong.

While coefficient odds ratios can easily be calculated using exp(coef(model)), the same method can not be applied to the standard error. This seems to be exactly what you are doing:

Zelig/R/utils.R

Lines 688 to 698 in 4f2dc6b

or_summary <- function(obj, label_mod_coef = "(OR)",
label_mod_se = "(OR)"){
if (class(obj) != "summary.glm")
stop("obj must be of summary.glm class.",
call. = FALSE)
obj$coefficients[, c(1, 2)] <- exp(obj$coefficients[, c(1, 2)])
colnames(obj$coefficients)[c(1, 2)] <- paste(
colnames(obj$coefficients)[c(1, 2)], c(label_mod_coef, label_mod_se))
return(obj)
}

The SE OR is often calculated using the delta method: ref1, ref2

A simpler way would be to calculate coef(summary(model))[,2] * exp(coef(model)): ref

Both deviate largely from the current implementation.

Here is a snippet to get the SE OR using the delta method (variable model contains the output from zelig function using a relogit model):

# 1. the `vcov` method should return a matrix, but zelig's vcov returns a list of one matrix instead, hence the unlisting
# 2. the `summary` method shouldn't return any text output when it is attributed to an identifier, but zelig's summary actually does, hence the `capture.output` command

get.or.se <- function(model) {
  var.diag = diag(vcov(model)[[1]]) 
  capture.output( 
    output <-
      coef(summary(model)) %>%
      as.data.frame() %>%
      dplyr::mutate(or = exp(Estimate),
                    or.se = sqrt(or ^ 2 * var.diag)) %>%
      dplyr::select(or.se) %>% unlist %>% unname
  )
  return(output)
}

Ah good catch (sorry I just quickly ported over the code from logit). Will fix now . . .

Quick fix in 466c97c

It seems to work with the example from ref, but just let me know if you see anything.