tidymodels / infer

An R package for tidyverse-friendly statistical inference
https://infer.tidymodels.org
Other
726 stars 80 forks source link

Tidy Chi-Squared Tests: support data that is already a contingency table #470

Closed emmansh closed 1 year ago

emmansh commented 1 year ago

This has been cross-posted to the Posit Community forum. Unless I'm missing something fundamental in the way {infer} works, I'd like to suggest a feature for supporting contingency tables when using {infer}. Much like chisq.test(), which accepts a contingency table as input.

I want to conduct a statistical inference given a two-way table of frequencies (i.e., contingency table). Thus, I'd like to use the chi-squared test of independence. I've found a very nice streamlined procedure with the {infer} package from tidymodels.

However, I cannot follow the tutorial's example given my own data. The tutorial assumes that the starting point is a dataset with two categorical columns (i.e., of type factor):

library(dplyr, warn.conflicts = FALSE)

data(ad_data, package = "modeldata")

ad_data_gen_class <- ad_data |> 
  select(Genotype, Class)

ad_data_gen_class
#> # A tibble: 333 x 2
#>    Genotype Class   
#>    <fct>    <fct>   
#>  1 E3E3     Control 
#>  2 E3E4     Control 
#>  3 E3E4     Control 
#>  4 E3E4     Control 
#>  5 E3E3     Control 
#>  6 E4E4     Impaired
#>  7 E2E3     Control 
#>  8 E2E3     Control 
#>  9 E3E3     Control 
#> 10 E2E3     Impaired
#> # ... with 323 more rows

However, my starting point is already a contingency table. In other words, imagine that the following ad_data_xtab is a given:

ad_data_xtab <- 
  ad_data_gen_class |>
  table()

ad_data_xtab
#>         Class
#> Genotype Impaired Control
#>     E2E2        0       2
#>     E2E3        7      30
#>     E2E4        1       7
#>     E3E3       34     133
#>     E3E4       41      65
#>     E4E4        8       5

My question: given ad_data_xtab as the starting point of my analysis, how can I nevertheless use {infer} procedure as demonstrated in the tutorial?

One way, I guess, would be to somehow "untable" ad_data_xtab back into ad_data_gen_class. This has at least two limitations:

  1. When "un-table-ing" ad_data_xtab, is it guaranteed that we get exactly ad_data_gen_class?
  2. Unlike ad_data_xtab, my real data's contingency table has much larger values for counts. If I am to "un-table" it, it would result in a combinatorial explosion of millions of rows, eating up my computer's memory (likely crashing it), for apparently no good reason.

What else can I do?

andrewpbray commented 1 year ago

Hi emmansh,

Indeed you can still use infer if you're starting with a contingency table, but there are some caveats. Let me weigh in on your two limitations.

  1. I think that depends on how you go about untabling. My inclination would be to try pivot_longer() then uncount(). I'm pretty sure they constitute reliable inverse operations to `table().

  2. Uf, I think here you're running into a fundamental limitation of the way infer works right now. It's built so that it's data frame in, data frame out. That means that you'll need to process that table into a data frame before sending through an infer pipelines. It also means that the output of the generate() function can be a very large data frame (it has the number of rows in the original data frame * reps). There are benefits to this approach - it allows for inspection of those data frames generated under the null - but there are costs in terms of performance. We had at one point discussed adding an option that would do the simulation through an efficient iteration process, bypassing the big data frame, but haven't done that yet (to my knowledge).

This might be a place where chisq.test() makes more sense. It permits tabular inputs and defaults to using the asymptotic chi-square distribution of the test statistic, which should be a very good approximation if your counts are very large.

simonpcouch commented 1 year ago

Thanks for the issue, @emmansh! My responses would be the same as Andrew's. Will go ahead and close this issue, though feel free to holler if you feel your questions are unanswered and we can reopen.🙂

github-actions[bot] commented 1 year ago

This issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with a reprex: https://reprex.tidyverse.org) and link to this issue.