Nothing
## Modifications:
## -- return a dnames component, containing dimnames for the array version of coef
## -- added dim methods: dim.loddsratio, dimnames.loddsratio
## -- added print.loddsratio
## -- handle strata: result computed correctly, but structure of coef() loses names
## and confint doesn't work in the 2x2xk or RxCxk case
## -- Fixed problem with strata by setting rownames and colnames for contrast matrix
## DONE: handle multiple strata (|foo:bar)
## -- print.loddsratio now uses drop() for dimensions of length 1
## -- made generic, anticipating a formula method, maybe structable or ftable methods
## DONE: decide which methods should allow a log=FALSE argument to provide exp(lor)
## -- Now handle any number of strata
## -- Added log= argument to print, coef methods, and added confint.loddsratio method,
## allowing log=FALSE
## -- Incorporated Z code additions, fixing some <FIXME>s
## -- Added as.matrix and as.array methods; had to make as.array S3 generic
## -- Added header to print method
## -- Added as.data.frame method (for use in plots)
## -- "LOR" is renamed "OR" if log=FALSE
## -- Revised as.matrix to drop leading 1:2 dimensions of length 1
## -- Removed as.array generic, now in base
## -- DM: added plot.oddsratio method
## -- DM: added formula interface
## -- DM: add t() and aperm() methdos
loddsratio <- function(x, ...)
UseMethod("loddsratio")
loddsratio.formula <-
function(formula, data = NULL, ..., subset = NULL, na.action = NULL)
{
m <- match.call(expand.dots = FALSE)
edata <- eval(m$data, parent.frame())
fstr <- strsplit(paste(deparse(formula), collapse = ""), "~")
vars <- strsplit(strsplit(gsub(" ", "", fstr[[1]][2]), "\\|")[[1]], "\\+")
varnames <- vars[[1]]
condnames <- if (length(vars) > 1) vars[[2]] else NULL
dep <- gsub(" ", "", fstr[[1]][1])
if (!dep %in% c("","Freq")) {
if (all(varnames == ".")) {
varnames <- if (is.data.frame(data))
colnames(data)
else
names(dimnames(as.table(data)))
varnames <- varnames[-which(varnames %in% dep)]
}
varnames <- c(dep, varnames)
}
if (inherits(edata, "ftable") || inherits(edata, "table") || length(dim(edata)) > 2) {
condind <- NULL
dat <- as.table(data)
if(all(varnames != ".")) {
ind <- match(varnames, names(dimnames(dat)))
if (any(is.na(ind)))
stop(paste("Can't find", paste(varnames[is.na(ind)], collapse=" / "), "in", deparse(substitute(data))))
if (!is.null(condnames)) {
condind <- match(condnames, names(dimnames(dat)))
if (any(is.na(condind)))
stop(paste("Can't find", paste(condnames[is.na(condind)], collapse=" / "), "in", deparse(substitute(data))))
ind <- c(ind, condind)
}
dat <- margin.table(dat, ind)
}
loddsratio.default(dat, strata = if (is.null(condind)) NULL else match(condnames, names(dimnames(dat))), ...)
} else {
m <- m[c(1, match(c("formula", "data", "subset", "na.action"), names(m), 0))]
m[[1]] <- as.name("xtabs")
m$formula <-
formula(paste(if("Freq" %in% colnames(data)) "Freq",
"~",
paste(c(varnames, condnames), collapse = "+")))
tab <- eval(m, parent.frame())
loddsratio.default(tab, ...)
}
}
loddsratio.default <- function(x, strata = NULL, log = TRUE,
ref = NULL, correct = any(x == 0), ...)
{
## check dimensions
L <- length(d <- dim(x))
if(any(d < 2L)) stop("All table dimensions must be 2 or greater")
if(L > 2L && is.null(strata)) strata <- 3L:L
if(is.character(strata)) strata <- which(names(dimnames(x)) == strata)
if(L - length(strata) != 2L) stop("All but 2 dimensions must be specified as strata.")
## dimensions of primary R x C table
dp <- if (length(strata)) d[-strata] else d
dn <- if (length(strata)) dimnames(x)[-strata] else dimnames(x)
R <- dp[1]
C <- dp[2]
# shadow matrix with proper dimnames
X <- matrix(0, R, C, dimnames=dn)
## process reference categories (always return list of length
## two with reference for rows/cols, respectively)
if(is.null(ref)) {
ref <- list(NULL, NULL)
} else if(is.character(ref)) {
if(length(ref) != 2L) stop("'ref' must specify both reference categories")
ref <- list(match(ref[1L], rownames(x)), match(ref[2L], colnames(x)))
} else if(is.numeric(ref)) {
ref <- as.integer(rep(ref, length.out = 2L))
ref <- list(ref[1L], ref[2L])
}
## compute corresponding indices
compute_index <- function(n, ref) {
if(is.null(ref)) return(cbind(1:(n-1), 2:n))
rval <- cbind(ref, 1:n)
d <- rval[,2L] - rval[,1L]
rval <- rbind(
rval[d > 0, 1:2],
rval[d < 0, 2:1]
)
return(rval[order(rval[,1L]),,drop = FALSE])
}
Rix <- compute_index(R, ref[[1L]])
Cix <- compute_index(C, ref[[2L]])
## set up contrast matrix for the primary R x C table
contr <- matrix(0L, nrow = (R-1) * (C-1), ncol = R * C)
colnames(contr) <- paste(rownames(X)[as.vector(row(X))], colnames(X)[as.vector(col(X))], sep = ":")
rownames(contr) <- rep("", (R-1) * (C-1))
for(i in 1:(R-1)) for(j in 1:(C-1)) {
rix <- (j-1) * (R-1) + i
cix <- rep(Rix[i,], 2L) + R * (rep(Cix[j,], each = 2L) - 1L)
contr[rix, cix] <- c(1L, -1L, -1L, 1L)
if (R > 2 || C > 2 || is.null(strata))
rownames(contr)[rix] <- sprintf("%s/%s",
paste(rownames(X)[Rix[i,]], collapse = ":"),
paste(colnames(X)[Cix[j,]], collapse = ":"))
}
# handle strata
if (!is.null(strata)) {
if (length(strata)==1) {
sn <- dimnames(x)[[strata]]
}
else {
sn <- apply(expand.grid(dimnames(x)[strata]), 1, paste, collapse = ":")
}
SEP <- if (R > 2 || C > 2 || is.null(strata)) "|" else ""
rn <- as.vector(outer( dimnames(contr)[[1]], sn, paste, sep=SEP))
cn <- as.vector(outer( dimnames(contr)[[2]], sn, paste, sep=SEP))
contr <- kronecker(diag(prod(dim(x)[strata])), contr)
rownames(contr) <- rn
colnames(contr) <- cn
}
## dimnames for array version
dn <- list(rep("", R-1), rep("", C-1))
for(i in 1:(R-1)) dn[[1]][i] <- paste(rownames(x)[Rix[i,]], collapse = ":")
for(j in 1:(C-1)) dn[[2]][j] <- paste(colnames(x)[Cix[j,]], collapse = ":")
if (!is.null(strata)) dn <- c(dn, dimnames(x)[strata])
if (!is.null(names(dimnames(x)))) names(dn) <- names(dimnames(x))
## point estimates
if (is.logical(correct)) {
add <- if(correct) 0.5 else 0
}
else if(is.numeric(correct)) {
add <- as.vector(correct)
if (length(add) != length(x))
stop("array size of 'correct' does not conform to the data")
}
else stop("correct is not valid")
##coef <- drop(contr %*% log(as.vector(x) + add))
##FIXME: 0 cells mess up the matrix product, try workaround:
mat <- log(as.vector(x) + add) * t(contr)
nas <- apply(contr != 0 & is.na(t(mat)), 1, any)
coef <- apply(mat, 2, sum, na.rm = TRUE)
coef[nas] <- NA
## covariances
##vcov <- crossprod(diag(sqrt(1/(as.vector(x) + add))) %*% t(contr))
tmp <- sqrt(1/(as.vector(x) + add)) * t(contr)
tmp[is.na(tmp)] <- 0
vcov <- crossprod(tmp)
vcov[nas,] <- NA
vcov[,nas] <- NA
rval <- structure(list(
coefficients = coef,
dimnames = dn,
dim = as.integer(sapply(dn, length)),
vcov = vcov,
contrasts = contr,
log = log
), class = "loddsratio")
rval
}
## dim methods
dimnames.loddsratio <- function(x, ...) x$dimnames
dim.loddsratio <- function(x, ...) x$dim
## t/aperm-methods
t.loddsratio <- function(x)
aperm(x)
aperm.loddsratio <- function(a, perm = NULL, ...)
{
d <- length(a$dim)
if(is.null(perm)) {
perm <- if (d < 3) 2L : 1L else c(2L : 1L, d : 3L)
} else {
if (any(perm[1:2] > 2L) || (d > 2L) && any(perm[-c(1:2)] < 2L))
stop("Mixing of strata and non-strata variables not allowed!")
}
nams <- names(a$coefficients)
a$coefficients <- as.vector(aperm(array(a$coef, dim = a$dim),
perm, ...))
nams <- as.vector(aperm(array(nams, dim = a$dim), perm, ...))
names(a$coefficients) <- nams
a$dimnames <- a$dimnames[perm]
a$dim <- a$dim[perm]
a$vcov <- a$vcov[nams, nams]
a$contrasts <- a$contrasts[nams,]
a
}
## straightforward methods
coef.loddsratio <- function(object, log = object$log, ...)
if(log) object$coefficients else exp(object$coefficients)
vcov.loddsratio <- function(object, log = object$log, ...)
if(log) object$vcov else `diag<-`(object$vcov, diag(object$vcov) * exp(object$coefficients)^2)
confint.loddsratio <-
function(object, parm, level = 0.95, log = object$log, ...) {
if (log) confint.default(object, parm = parm, level = level, ... )
else {
object$log = TRUE
exp(confint.default(object, parm = parm, level = level, ... ))
}
}
make_header <- function(x)
{
vn <- names(dimnames(x))
header <- c(if(x$log) "log" else "",
"odds ratios for", vn[1], "and", vn[2],
if (length(vn)>2) c("by", paste(vn[-(1:2)], collapse=', ')), "\n\n")
paste(header, sep = " ")
}
## print method
print.loddsratio <- function(x, log = x$log, ...) {
cat(make_header(x))
print(drop(array(coef(x, log = log), dim = dim(x), dimnames = dimnames(x)), ...))
invisible(x)
}
summary.loddsratio <- function(object, ...)
lmtest::coeftest(object, ...)
## reshape coef() methods
as.matrix.loddsratio <- function (x, log=x$log, ...) {
Coef <- coef(x, log = log)
if (length(dim(x))==2) matrix(Coef, ncol = dim(x)[2], dimnames=dimnames(x))
else { # drop leading dimensions with length 1, then reshape
ddim <- which(dim(x)[1:2]==1)
dim(Coef) <- dim(x)[-ddim]
dimnames(Coef) <- dimnames(x)[-ddim]
if (length(dim(Coef))==1) Coef
else
matrix(Coef, ncol = prod(dim(Coef)[-1]),
dimnames=list(dimnames(Coef)[[1]], apply(expand.grid(dimnames(Coef)[[-1]]), 1, paste, collapse = ":")))
}
}
as.array.loddsratio <- function (x, log=x$log, ...) {
res <- array(coef(x, log = log), dim = dim(x), dimnames=dimnames(x))
drop(res)
}
as.data.frame.loddsratio <- function(x, row.names = NULL, optional, log=x$log, ...) {
df <-data.frame(expand.grid(dimnames(x)),
LOR = coef(x, log=log),
ASE = sqrt(diag(vcov(x, log=log))), row.names=row.names, ...
)
if (!log) colnames(df)[ncol(df)-1] <- "OR"
df
}
image.loddsratio <-
function(x, interpolate = NULL, legend = legend_fixed,
gp = shading_Friendly, gp_args = NULL,
labeling = labeling_values("residuals", suppress = 0),
perm = NULL, ...)
{
a <- as.array(x)
if (!is.null(dim(a))) {
if (is.null(perm)) {
d <- seq_along(dim(a))
perm <- c(d[-c(1:2)], 1:2)
}
a <- aperm(a, perm)
} else {
a <- as.table(a)
names(dimnames(a)) <- names(dimnames(x))[1]
}
if (is.null(interpolate))
interpolate <- seq(0.1, max(abs(a), length.out = 4))
if (is.null(gp_args))
gp_args <- list(interpolate = interpolate)
tmp <- a
tmp[] <- 1
mosaic(tmp, type = "expected",
residuals = a, shade = TRUE,
gp = shading_Friendly, gp_args = gp_args,
legend = legend,
labeling = labeling, ...)
}
tile.loddsratio <-
function(x, interpolate = NULL, legend = legend_fixed,
gp = shading_Friendly, gp_args = NULL,
labeling = labeling_values("residuals", suppress = 0),
halign = "center", valign = "center", perm = NULL, ...)
{
a <- as.array(x)
if (!is.null(dim(a))) {
if (is.null(perm)) {
d <- seq_along(dim(a))
perm <- c(d[-c(1:2)], 1:2)
}
a <- aperm(a, perm)
} else {
a <- as.table(a)
names(dimnames(a)) <- names(dimnames(x))[1]
}
if (is.null(interpolate))
interpolate <- seq(0.1, max(abs(a), length.out = 4))
if (is.null(gp_args))
gp_args <- list(interpolate = interpolate)
tile(abs(a), halign = halign, valign = valign,
residuals = a, shade = TRUE,
gp = shading_Friendly, gp_args = gp_args,
legend = legend,
labeling = labeling, ...)
}
"plot.loddsratio" <-
function(x,
baseline = TRUE,
gp_baseline = gpar(lty = 2),
lines = TRUE,
lwd_lines = 3,
confidence = TRUE,
conf_level = 0.95,
lwd_confidence = 2,
whiskers = 0,
transpose = FALSE,
col = NULL,
cex = 0.8,
pch = NULL,
bars = NULL,
gp_bars = gpar(fill = "lightgray", alpha = 0.5),
bar_width = unit(0.05, "npc"),
legend = TRUE, legend_pos = "topright", legend_inset = c(0, 0),
legend_vgap = unit(0.5, "lines"),
gp_legend_frame = gpar(lwd = 1, col = "black"),
gp_legend_title = gpar(fontface = "bold"),
gp_legend = gpar(), legend_lwd = 1,
legend_size = 1,
xlab = NULL,
ylab = NULL,
xlim = NULL,
ylim = NULL,
main = NULL,
gp_main = gpar(fontsize = 12, fontface = "bold"),
newpage = TRUE, pop = FALSE, return_grob = FALSE,
add = FALSE,
prefix = "",
...)
{
## handle default values, limits etc.
LOG <- x$log
values <- as.array(x)
d <- dim(values)
if (is.null(bars))
bars <- is.null(d)
oddsrange <- range(values, na.rm = TRUE)
if(confidence) {
CI <- confint(x, log = LOG, level = conf_level)
lwr <- CI[,1]
upr <- CI[,2]
oddsrange <- if (baseline)
c(min(0, lwr, na.rm = TRUE), max(0, upr, na.rm = TRUE))
else
c(min(lwr, na.rm = TRUE), max(upr, na.rm = TRUE))
}
if (is.null(main))
main <- paste(make_header(x), collapse = " ")
if (is.null(xlim))
xlim <- if (is.null(d))
c(1, length(values))
else
c(1, d[1])
if (is.null(ylim))
ylim <- oddsrange
ylimaxis <- ylim + c(-1, 1) * diff(ylim) * 0.04
xlimaxis <- xlim + c(-1, 1) * diff(xlim) * 0.04
ncols <- if (is.null(d)) 1 else prod(d[-1])
if (is.null(col))
col <- rainbow_hcl(ncols, l = 50)
if (is.null(pch))
pch <- c(19,15,17, 1:14, 16, 18, 20:25)
labs <- if (is.null(d)) names(values) else dimnames(values)[[1]]
if (is.null(xlab))
xlab <- if (is.null(d)) names(dimnames(x))[3] else names(dimnames(values))[1]
if (is.null(ylab))
ylab <- paste(if (LOG) "L" else "",
"OR(", paste(names(dimnames(x))[1:2], collapse = " / "), ")", sep = "")
if (newpage) grid.newpage()
if (transpose) {
if (!add) {
## set up plot region, similar to plot.xy()
pushViewport(plotViewport(xscale = ylimaxis, yscale = xlimaxis,
default.units = "native",
name = paste(prefix,"oddsratio_plot")))
grid.yaxis(name = "yaxis", seq_along(labs), labs,
edits = gEdit("labels", rot = 90, hjust = .5, vjust = 0))
grid.xaxis()
grid.text(ylab, y = unit(-3.5, "lines"))
grid.text(xlab, x = unit(-3, "lines"), rot = 90)
grid.text(main, y = unit(1, "npc") + unit(1, "lines"), gp = gp_main)
pushViewport(viewport(xscale = ylimaxis, yscale = xlimaxis,
default.units = "native", clip = "on"))
## baseline
if (baseline)
grid.lines(unit(c(1,1) - LOG, "native"),
unit(c(0,1), "npc"),
gp = gp_baseline)
}
# workhorse for one stratum
draw_one_stratum <- function(vals, pch = "o", col = "black", offset = 0,
jitter = 0) {
if (bars) {
if (any(vals > !LOG))
grid.rect(unit(vals[vals > !LOG], "native"),
unit(seq_along(vals)[vals > !LOG], "native"),
height = bar_width,
width = unit(vals[vals > !LOG] - !LOG, "native"),
just = "right",
gp = gp_bars
)
if (any(vals < !LOG))
grid.rect(unit(vals[vals < !LOG], "native"),
unit(seq_along(vals)[vals < !LOG], "native"),
height = bar_width,
width = unit(abs(vals[vals < !LOG] - !LOG), "native"),
just = "left",
gp = gp_bars
)
}
if (lines)
grid.lines(unit(vals, "native"),
unit(seq_along(vals), "native"),
gp = gpar(col = col, lwd = lwd_lines),
default.units = "native"
)
grid.points(unit(vals, "native"),
unit(seq_along(vals), "native"),
pch = pch,
size = unit(cex, "char"),
gp = gpar(col = col, lwd = lwd_lines),
default.units = "native"
)
if (confidence)
for (i in seq_along(vals)) {
ii <- i + jitter
grid.lines(unit(c(lwr[offset + i], upr[offset + i]), "native"),
unit(c(ii, ii), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
grid.lines(unit(c(lwr[offset + i], lwr[offset + i]), "native"),
unit(c(ii - whiskers/2, ii + whiskers/2), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
grid.lines(unit(c(upr[offset + i], upr[offset + i]), "native"),
unit(c(ii - whiskers/2, ii + whiskers/2), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
}
}
} else {
if (!add) {
## set up plot region
pushViewport(plotViewport(xscale = xlimaxis, yscale = ylimaxis,
default.units = "native",
name = "oddsratio_plot"))
grid.xaxis(seq_along(labs), labs)
grid.yaxis()
grid.text(xlab, y = unit(-3.5, "lines"))
grid.text(ylab, x = unit(-3, "lines"), rot = 90)
grid.text(main, y = unit(1, "npc") + unit(1, "lines"), gp = gp_main)
pushViewport(viewport(xscale = xlimaxis, yscale = ylimaxis,
default.units = "native", clip = "on"))
## baseline
if (baseline)
grid.lines(unit(c(0,1), "npc"),
unit(c(1,1) - LOG, "native"),
gp = gp_baseline)
}
## workhorse for one stratum
draw_one_stratum <- function(vals, pch = "o", col = "black", offset = 0,
jitter = 0) {
if (bars) {
if (any(vals > !LOG))
grid.rect(unit(seq_along(vals)[vals > !LOG], "native"),
unit(vals[vals > !LOG], "native"),
width = bar_width,
height = unit(vals[vals > !LOG] - !LOG, "native"),
just = "top",
gp = gp_bars
)
if (any(vals < !LOG))
grid.rect(unit(seq_along(vals)[vals < !LOG], "native"),
unit(vals[vals < !LOG], "native"),
width = bar_width,
height = unit(abs(vals[vals < !LOG] - !LOG), "native"),
just = "bottom",
gp = gp_bars
)
}
if (lines)
grid.lines(unit(seq_along(vals), "native"),
unit(vals, "native"),
gp = gpar(col = col, lwd = lwd_lines),
default.units = "native"
)
grid.points(unit(seq_along(vals), "native"),
unit(vals, "native"),
pch = pch,
size = unit(cex, "char"),
gp = gpar(col = col, lwd = lwd_lines),
default.units = "native"
)
if (confidence)
for (i in seq_along(vals)) {
ii <- i + jitter
grid.lines(unit(c(ii, ii), "native"),
unit(c(lwr[offset + i], upr[offset + i]), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
grid.lines(unit(c(ii - whiskers/2, ii + whiskers/2), "native"),
unit(c(lwr[offset + i], lwr[offset + i]), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
grid.lines(unit(c(ii - whiskers/2, ii + whiskers/2), "native"),
unit(c(upr[offset + i], upr[offset + i]), "native"),
gp = gpar(col = col, lwd = lwd_confidence))
}
}
}
if (is.null(d))
draw_one_stratum(values, pch[1], col[1])
else {
jitt <- scale(seq_len(prod(d[-1])), scale = 25 * prod(d[-1]))
for (i in 1 : prod(d[-1]))
draw_one_stratum(values[(i - 1) * d[1] + seq(d[1])],
pch[(i - 1 ) %% length(pch) + 1],
col[i],
offset = (i - 1) * d[1],
jitt[i])
if (legend)
grid_legend(legend_pos,
labels = apply(expand.grid(dimnames(values)[-1]),
1, paste, collapse = "|"),
pch = pch[1 : prod(d[-1])],
col = col,
lwd = legend_lwd,
lty = "solid",
size = legend_size,
vgap = legend_vgap,
gp = gp_legend,
gp_frame = gp_legend_frame,
inset = legend_inset,
title = paste(names(dimnames(values)[-1]), collapse = " x "),
gp_title = gp_legend_title, ...)
}
grid.rect(gp = gpar(fill = "transparent"))
if (!add && pop) popViewport(2)
if (return_grob)
invisible(grid.grab())
else
invisible(NULL)
}
lines.loddsratio <-
function(x, legend = FALSE, confidence = FALSE, cex = 0, ...)
{
plot(x, add = TRUE, newpage = FALSE, legend = legend, confidence = confidence, cex = cex, ...)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.