Computes odds ratios, either from a 2x2 contingency table or from a binomial generalized linear model. The table method returns a single odds ratio, the model method one odds ratio per regression coefficient.
Usage
oddsRatio(x, ...)
# Default S3 method
oddsRatio(
x,
y = NULL,
conf.level = NA,
sides = c("two.sided", "left", "right"),
method = c("wald", "exact", "midp"),
interval = c(0, 1000),
...
)
# S3 method for class 'glm'
oddsRatio(
x,
conf.level = 0.95,
sides = c("two.sided", "left", "right"),
method = c("wald", "profile"),
...
)
# S3 method for class 'OddsRatio'
print(x, digits = 3, ...)Arguments
- x
a 2x2 contingency table, two vectors to be cross-tabulated, or a binomial
stats::glm()object- ...
further arguments passed to methods. For the default method with two vectors, these reach
table(), souseNAcan be set here.- y
optional second variable. If supplied,
table(x, y, ...)is computed.- conf.level
confidence level of the interval. For the table method
NA(the default) returns the point estimate only; the model method computes an interval by default.- sides
character string specifying the sidedness of the confidence interval (one of
"two.sided"(default),"left"or"right"). SeeConfidenceIntervals(). An odds ratio is bounded below by 0 and unbounded above, so the open side is reported at 0 orInfaccordingly. Ignored, with a warning, formethod = "profile".- method
character string specifying the interval method. For a contingency table one of
"wald","exact"or"midp"; for a binomial model one of"wald"or"profile". See Details.- interval
numeric vector of length two giving the search interval for the root finding in the mid-p method. Only used by
method = "midp"; widen it if the reported bound sits at one of its ends.- digits
number of digits used for printing
Value
For a contingency table with conf.level = NA a numeric scalar,
otherwise a named numeric vector with the elements est, lci
and uci.
For a binomial model an object of class "OddsRatio", a list with:
coefficientsa data frame with one row per coefficient and the columns
term,est(the exponentiated coefficient),logEst(the coefficient itself),stdError(on the log scale),pValue,lcianducisource"glm"method,conf.level,sidesas supplied - with
sidesrecording what was computed, which formethod = "profile"is always"two.sided"nObsnumber of observations used in the fit
callthe model call
There is a print method; the interval bounds are on the odds scale,
the standard error on the log scale.
Details
Contingency tables
For a 2x2 table the odds ratio is
$$OR = \frac{n_{11} n_{22}}{n_{12} n_{21}}$$
Three interval methods are available. "wald" is the asymptotic
interval on the log scale, fast and adequate for reasonably large counts.
"exact" is the conditional interval based on the noncentral
hypergeometric distribution (Fisher); it guarantees coverage but is
conservative, sometimes markedly so. "midp" halves the probability
of the observed table and lies between the two: it has coverage closer to
the nominal level than the exact interval without the Wald interval's
reliance on large counts. With a zero cell the point estimate is 0 or
Inf and only "exact" and "midp" still deliver a
finite bound on the informative side.
Binomial models
For a model fitted with glm(family = binomial), each coefficient is
exponentiated: \(\exp(\beta_j)\) is the factor by which the odds of the
response are multiplied when the corresponding predictor increases by one
unit, all other predictors held fixed. For a dummy variable this is the
odds ratio between the level and its reference level.
The intercept is exponentiated along with the rest, but \(\exp(\beta_0)\) is not an odds ratio - it is the odds of the response when all predictors are zero. It is reported for completeness and is usually not the quantity of interest.
Two interval methods are available. "wald" is the symmetric
interval on the log-odds scale, back-transformed. "profile" inverts
the likelihood ratio test through stats::confint.glm(); it is
asymmetric on the odds scale, generally more reliable in small samples or
with sparse cells, and considerably slower because the model is refitted
along each coefficient. Profile intervals are two-sided by construction,
so sides is ignored for them and a warning is issued.
Unlike the table method, the model method computes an interval by default
(conf.level = 0.95): a coefficient table without intervals would
be less informative than summary() itself.
Note
No short alias is exported by default to avoid conflicts with
rlang and base R naming conventions. Call
attachAliases() once per session (or script) to make
or() available as a convenient shorthand.
References
Agresti, A. (2013). Categorical Data Analysis (3rd ed.). Wiley.
Fisher, R. A. (1935). The logic of inductive inference. Journal of the Royal Statistical Society, 98(1), 39–82.
Gart, J. J. (1966). Alternative analyses of contingency tables. Journal of the Royal Statistical Society Series B, 28(1), 164–179.
See also
attachAliases, relRisk, stats::confint.glm()
Other effect.size:
cohenD(),
cohenH(),
etaSq(),
glassDelta(),
relRisk()
Examples
# --- 2x2 table -------------------------------------------------
tab <- matrix(c(10, 20,
5, 30), nrow = 2)
oddsRatio(tab)
#> [1] 3
oddsRatio(tab, conf.level = 0.95)
#> est lci uci
#> 3.0000000 0.8914747 10.0956314
# the exact interval is the widest, the Wald interval the narrowest
sapply(c("wald", "exact", "midp"),
function(m) oddsRatio(tab, conf.level = 0.95, method = m))
#> wald exact midp
#> est 3.0000000 2.9483345 2.9118822
#> lci 0.8914747 0.7770679 0.8795254
#> uci 10.0956314 12.7381845 10.8604692
# one-sided: "left" carries the finite lower bound
oddsRatio(tab, conf.level = 0.95, sides = "left")
#> est lci uci
#> 3.000000 1.083524 Inf
# --- binomial model --------------------------------------------
fit <- glm(vs ~ am + wt, data = mtcars, family = binomial)
oddsRatio(fit)
#>
#> Call:
#> glm(formula = vs ~ am + wt, family = binomial, data = mtcars)
#>
#> Odds Ratios (95% two.sided CI, method = wald):
#>
#> est lci uci pValue
#> (Intercept) 2.793411e+09 185.176 4.213903e+16 0.00991
#> am 2.000000e-03 0.000 4.310000e-01 0.02310
#> wt 2.000000e-03 0.000 2.060000e-01 0.00904
#>
# the exponentiated intercept is the baseline odds, not an odds ratio
res <- oddsRatio(fit)
res$coefficients
#> term est logEst stdError pValue lci
#> 1 (Intercept) 2.793411e+09 21.750529 8.433431 0.009906264 1.851762e+02
#> 2 am 2.169003e-03 -6.133488 2.700169 0.023115514 1.091119e-05
#> 3 wt 1.782578e-03 -6.329695 2.424632 0.009038881 1.538857e-05
#> uci
#> 1 4.213903e+16
#> 2 4.311695e-01
#> 3 2.064898e-01
# profile likelihood intervals: asymmetric on the odds scale, slower
oddsRatio(fit, method = "profile")
#> Waiting for profiling to be done...
#> Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
#>
#> Call:
#> glm(formula = vs ~ am + wt, family = binomial, data = mtcars)
#>
#> Odds Ratios (95% two.sided CI, method = profile):
#>
#> est lci uci pValue
#> (Intercept) 2.793411e+09 6739.932 5.653093e+18 0.00991
#> am 2.000000e-03 0.000 1.560000e-01 0.02310
#> wt 2.000000e-03 0.000 7.200000e-02 0.00904
#>
