Performs Fisher's exact test for testing the null of independence of rows and columns in a contingency table.

Wrappers around the R base function fisher.test() but have the advantage of performing pairwise and row-wise fisher tests, the post-hoc tests following a significant chi-square test of homogeneity for 2xc and rx2 contingency tables.

fisher_test(
  xtab,
  workspace = 2e+05,
  alternative = "two.sided",
  conf.int = TRUE,
  conf.level = 0.95,
  simulate.p.value = FALSE,
  B = 2000,
  detailed = FALSE,
  ...
)

pairwise_fisher_test(xtab, p.adjust.method = "holm", detailed = FALSE, ...)

row_wise_fisher_test(xtab, p.adjust.method = "holm", detailed = FALSE, ...)

Arguments

xtab

a contingency table in a matrix form.

workspace

an integer specifying the size of the workspace used in the network algorithm. In units of 4 bytes. Only used for non-simulated p-values larger than \(2 \times 2\) tables. Since R version 3.5.0, this also increases the internal stack size which allows larger problems to be solved, however sometimes needing hours. In such cases, simulate.p.values=TRUE may be more reasonable.

alternative

indicates the alternative hypothesis and must be one of "two.sided", "greater" or "less". You can specify just the initial letter. Only used in the \(2 \times 2\) case.

conf.int

logical indicating if a confidence interval for the odds ratio in a \(2 \times 2\) table should be computed (and returned).

conf.level

confidence level for the returned confidence interval. Only used in the \(2 \times 2\) case and if conf.int = TRUE.

simulate.p.value

a logical indicating whether to compute p-values by Monte Carlo simulation, in larger than \(2 \times 2\) tables.

B

an integer specifying the number of replicates used in the Monte Carlo test.

detailed

logical value. Default is FALSE. If TRUE, a detailed result is shown.

...

Other arguments passed to the function fisher_test().

p.adjust.method

method to adjust p values for multiple comparisons. Used when pairwise comparisons are performed. Allowed values include "holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none". If you don't want to adjust the p value (not recommended), use p.adjust.method = "none".

Value

return a data frame with some the following columns:

  • group: the categories in the row-wise proportion tests.

  • p: p-value.

  • p.adj: the adjusted p-value.

  • method: the used statistical test.

  • p.signif, p.adj.signif: the significance level of p-values and adjusted p-values, respectively.

  • estimate: an estimate of the odds ratio. Only present in the 2 by 2 case.

  • alternative: a character string describing the alternative hypothesis.

  • conf.low,conf.high: a confidence interval for the odds ratio. Only present in the 2 by 2 case and if argument conf.int = TRUE.

The returned object has an attribute called args, which is a list holding the test arguments.

Functions

  • fisher_test(): performs Fisher's exact test for testing the null of independence of rows and columns in a contingency table with fixed marginals. Wrapper around the function fisher.test().

  • pairwise_fisher_test(): pairwise comparisons between proportions, a post-hoc tests following a significant Fisher's exact test of homogeneity for 2xc design.

  • row_wise_fisher_test(): performs row-wise Fisher's exact test of count data, a post-hoc tests following a significant chi-square test of homogeneity for rx2 contingency table. The test is conducted for each category (row).

Examples


# Comparing two proportions
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Data: frequencies of smokers between two groups
xtab <- as.table(rbind(c(490, 10), c(400, 100)))
dimnames(xtab) <- list(
  group = c("grp1", "grp2"),
  smoker = c("yes", "no")
)
xtab
#>       smoker
#> group  yes  no
#>   grp1 490  10
#>   grp2 400 100
# compare the proportion of smokers
fisher_test(xtab, detailed = TRUE)
#> # A tibble: 1 × 8
#>       n estimate        p conf.low conf.high method              alter…¹ p.sig…²
#> * <dbl>    <dbl>    <dbl>    <dbl>     <dbl> <chr>               <chr>   <chr>  
#> 1  1000     12.2 8.77e-22     6.27      26.6 Fisher's Exact test two.si… ****   
#> # … with abbreviated variable names ¹​alternative, ²​p.signif

# Homogeneity of proportions between groups
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# H0: the proportion of smokers is similar in the four groups
# Ha:  this proportion is different in at least one of the populations.
#
# Data preparation
grp.size <- c( 106, 113, 156, 102 )
smokers  <- c( 50, 100, 139, 80 )
no.smokers <- grp.size - smokers
xtab <- as.table(rbind(
  smokers,
  no.smokers
))
dimnames(xtab) <- list(
  Smokers = c("Yes", "No"),
  Groups = c("grp1", "grp2", "grp3", "grp4")
)
xtab
#>        Groups
#> Smokers grp1 grp2 grp3 grp4
#>     Yes   50  100  139   80
#>     No    56   13   17   22

# Compare the proportions of smokers between groups
fisher_test(xtab, detailed = TRUE)
#> # A tibble: 1 × 5
#>       n       p method              alternative p.signif
#> * <dbl>   <dbl> <chr>               <chr>       <chr>   
#> 1   477 6.1e-15 Fisher's Exact test two.sided   ****    

# Pairwise comparison between groups
pairwise_fisher_test(xtab)
#> # A tibble: 6 × 6
#>   group1 group2     n        p    p.adj p.adj.signif
#> * <chr>  <chr>  <dbl>    <dbl>    <dbl> <chr>       
#> 1 grp1   grp2     219 2.39e-11 1.2 e-10 ****        
#> 2 grp1   grp3     262 1.22e-13 7.32e-13 ****        
#> 3 grp1   grp4     208 3.79e- 6 1.52e- 5 ****        
#> 4 grp2   grp3     269 1   e+ 0 1   e+ 0 ns          
#> 5 grp2   grp4     215 6.35e- 2 1.27e- 1 ns          
#> 6 grp3   grp4     258 2.17e- 2 6.51e- 2 ns          


# Pairwise proportion tests
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Data: Titanic
xtab <- as.table(rbind(
  c(122, 167, 528, 673),
  c(203, 118, 178, 212)
))
dimnames(xtab) <- list(
  Survived = c("No", "Yes"),
  Class = c("1st", "2nd", "3rd", "Crew")
)
xtab
#>         Class
#> Survived 1st 2nd 3rd Crew
#>      No  122 167 528  673
#>      Yes 203 118 178  212
# Compare the proportion of survived between groups
pairwise_fisher_test(xtab)
#> # A tibble: 6 × 6
#>   group1 group2     n        p    p.adj p.adj.signif
#> * <chr>  <chr>  <dbl>    <dbl>    <dbl> <chr>       
#> 1 1st    2nd      610 2.78e- 7 8.34e- 7 ****        
#> 2 1st    3rd     1031 3.68e-30 1.84e-29 ****        
#> 3 1st    Crew    1210 1.81e-34 1.09e-33 ****        
#> 4 2nd    3rd      991 8.19e- 7 1.64e- 6 ****        
#> 5 2nd    Crew    1170 2.77e- 8 1.11e- 7 ****        
#> 6 3rd    Crew    1591 5.98e- 1 5.98e- 1 ns          

# Row-wise proportion tests
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Data: Titanic
xtab <- as.table(rbind(
  c(180, 145), c(179, 106),
  c(510, 196), c(862, 23)
))
dimnames(xtab) <- list(
  Class = c("1st", "2nd", "3rd", "Crew"),
  Gender = c("Male", "Female")
)
xtab
#>       Gender
#> Class  Male Female
#>   1st   180    145
#>   2nd   179    106
#>   3rd   510    196
#>   Crew  862     23
# Compare the proportion of males and females in each category
row_wise_fisher_test(xtab)
#> # A tibble: 4 × 5
#>   group     n        p    p.adj p.adj.signif
#> * <chr> <dbl>    <dbl>    <dbl> <chr>       
#> 1 1st    2201 9.38e-25 2.81e-24 ****        
#> 2 2nd    2201 3.96e-11 7.92e-11 ****        
#> 3 3rd    2201 8.67e- 7 8.67e- 7 ****        
#> 4 Crew   2201 8.02e-85 3.21e-84 ****        

# A r x c table  Agresti (2002, p. 57) Job Satisfaction
Job <- matrix(c(1,2,1,0, 3,3,6,1, 10,10,14,9, 6,7,12,11), 4, 4,
              dimnames = list(income = c("< 15k", "15-25k", "25-40k", "> 40k"),
                             satisfaction = c("VeryD", "LittleD", "ModerateS", "VeryS")))
fisher_test(Job)
#> # A tibble: 1 × 3
#>       n     p p.signif
#> * <dbl> <dbl> <chr>   
#> 1    96 0.783 ns      
fisher_test(Job, simulate.p.value = TRUE, B = 1e5)
#> # A tibble: 1 × 3
#>       n     p p.signif
#> * <dbl> <dbl> <chr>   
#> 1    96 0.783 ns