1

This seems like a newb question, but I just can't figure it out. I'm looking at a 3d contingency table and I want to run analyses on the partial tables. Below is some sample data:

df2 <- data.frame(Gender = c(rep("M", 6), rep("F", 6)), Beliefs = c(rep("Fund", 2), rep("Mod", 2), rep("Liberal", 2), rep("Fund", 2), rep("Mod", 2), rep("Liberal", 2)), Afterlife = c(rep(c("Yes", "No"), 6)), Count = c(252, 43, 274, 47, 226, 100, 420, 50, 415, 50, 273, 83))

df2.tab <- xtabs(Count ~ Beliefs + Afterlife + Gender, data = df2)

Originally, Gender was my Z variable. But I want to compare the partial tables across levels of Beliefs. Sure, I can create an xtabs with Beliefs as my grouping variable, but even then I can't figure out how to select the partial tables (or level of Z) independently so I can find the ORs for each partial table, e.g., using epitools::oddsratio.wald

Thanks much!

Michael
  • 111
  • 9
  • 1
    Do you mean something like `apply(df2.tab, 3, chisq.test)` where I'm running a `chisq.test` for each `Gender` group? `apply` can work on any dimensions, and combination of dimensions, not just rows and columns, – thelatemail Oct 10 '19 at 23:51
  • What is your expected output ? As thelatemail said do you need `apply(df2.tab, 3, epitools::oddsratio)` ? – Ronak Shah Oct 11 '19 at 01:16
  • I guess that does do what I want. I was thinking more along the lines of selecting a partial table as easily as one might select an element of an object with $, instead of, in this case, having to create a whole new table where Beliefs are the grouping variable and then use apply on it. But ultimately I think it's the same amount of work if not less via the apply method. – Michael Oct 11 '19 at 03:09
  • @Michael - `aperm` can also be used to 'spin' the dimensions of tables, e.g.: `aperm(df2.tab, c(1,3,2))` – thelatemail Oct 11 '19 at 04:47
  • Didn't know that function. Together with apply, I think this is what I'm looking for. Thanks everyone! – Michael Oct 11 '19 at 05:15

1 Answers1

1

Here's an attempt at explaining how apply can be useful here, by example:

printchk <- function(x) {print(x); print(class(x)); cat("------\n")}
tab <- array(1:8,dim=c(2,2,2))
printchk(tab)
#, , 1
#
#     [,1] [,2]
#[1,]    1    3
#[2,]    2    4
#
#, , 2
#
#     [,1] [,2]
#[1,]    5    7
#[2,]    6    8
#
#[1] "array"
#------

Work with combined rows across strata

invisible(apply(tab, 1, printchk))
#     [,1] [,2]
#[1,]    1    5
#[2,]    3    7
#[1] "matrix"
#------
#     [,1] [,2]
#[1,]    2    6
#[2,]    4    8
#[1] "matrix"
#------

Work with combined columns across strata

invisible(apply(tab, 2, printchk))
#     [,1] [,2]
#[1,]    1    5
#[2,]    2    6
#[1] "matrix"
#------
#     [,1] [,2]
#[1,]    3    7
#[2,]    4    8
#[1] "matrix"
#------
 

Work with strata

invisible(apply(tab, 3, printchk))
#     [,1] [,2]
#[1,]    1    3
#[2,]    2    4
#[1] "matrix"
#------
#     [,1] [,2]
#[1,]    5    7
#[2,]    6    8
#[1] "matrix"
#------

So, without changing dimensions or structure, you can compare different parts of the array using apply calls.

oddsratio <- function(x) (x[1,1]/x[2,1]) / (x[1,2]/x[2,2])

apply(tab, 1, oddsratio)
##Expecting: (1/3)/(5/7) = 0.46
##           (2/4)/(6/8) = 0.66

#[1] 0.4666667 0.6666667

Yep, works as intended.

Multiple dimensions

One can then extend this logic to use multiple dimensions at once, e.g.:

invisible(apply(tab, c(1,2), printchk))
#[1] 1 5
#[1] "integer"
#------
#[1] 2 6
#[1] "integer"
#------
#[1] 3 7
#[1] "integer"
#------
#[1] 4 8
#[1] "integer"
#------
Community
  • 1
  • 1
thelatemail
  • 91,185
  • 12
  • 128
  • 188
  • What about parts of a dimension? Say the array is 2x4x2 but you're only interested in marginal association, so you're looking at the 2x4 table. But that itself has a bunch of partial tables to apply over like x[,c(1,4)]. How would one use apply to cover all 2x2 partial tables within an array? I think you'd have to write some kind of function for that, right? – Michael Oct 11 '19 at 23:09
  • @Michael - I'll see if I'm understanding right, do you want to compare *all* 2x2 table possibilities like `c(1,2)` then `c(1,3)` then `c(1,4)` then `c(2,3)` etc? I think you'd have to use something like `combn` inside the `apply`-ed function. It starts getting more complex, but it's doable: `apply(tab, 3, function(x) combn(ncol(x),2,FUN=function(y) chisq.test(x[,y]),simplify=FALSE) )` – thelatemail Oct 11 '19 at 23:24