如何为数据框的每一行创建一个意外事件 table

how to create a contingency table for each row of a data frame

我有一个大型数据框,其中行作为物种,从 2 年开始计数作为列。我想为每一行创建一个意外事件 table 以测试从第一年到第二年是否有显着变化(减少)。这是类似的假装数据:

Species   2016    2017
cat        14      8
dog        16      12
bird       10      5

然后对于每一行我想要一个 table 比如:

cat       2017 2018
present   14    8
absent     0    6

dog       2017  2018
present   16    12
absent     0    4

bird      2017  2018
present    10    5
absent      0    5

有了这个,我将对每个 table 进行 Fisher 精确检验,以检验减少是否显着。

我认为这可以通过 dplyr 或应用循环来完成,类似于下面的 link 但我不确定如何首先构建正确的 table 列表。

我从一行开始:

A <- df[1,1:3]
A[2,] <- 0
A[2,3] <- (A[1,2] - A[1,3])
fisher.test(A[2:3])

非常感谢有关如何将其应用于大量行的建议!我的大脑真的很难编码。

这是一个使用 base R 的解决方案。您可以使用此答案中的一些想法来做出更简洁的答案。让我知道这是否适合您!

# Create dataframe
df <- data.frame(Species = c("cat", "dog", "bird"),
                 year_2016 = c(14, 16, 10),
                 year_2017 = c(8, 12, 5), 
                 stringsAsFactors = F)

# Create columns to later convert to a matrix
df$absent <- 0
df$present <- df$year_2016 - df$year_2017

# Tranpose the dataframe to use lapply
df_t <- t(df)
colnames(df_t) <- as.vector(df_t[1,])
df_t <- df_t[-1,]
class(df_t) <- "numeric"

# Use lapply to create matrices
matrix_list <- lapply(1:ncol(df_t), function(x) matrix(as.vector(df_t[,x]), 2, 2, byrow = T))
names(matrix_list) <- colnames(df_t)
matrix_list
$cat
     [,1] [,2]
[1,]   14    8
[2,]    0    6

$dog
     [,1] [,2]
[1,]   16   12
[2,]    0    4

$bird
     [,1] [,2]
[1,]   10    5
[2,]    0    5

# Lots of fisher.tests
lapply(matrix_list, fisher.test)
$cat

    Fisher's Exact Test for Count Data

data:  X[[i]]
p-value = 0.01594
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 1.516139      Inf
sample estimates:
odds ratio 
       Inf 


$dog

    Fisher's Exact Test for Count Data

data:  X[[i]]
p-value = 0.1012
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 0.7200866       Inf
sample estimates:
odds ratio 
       Inf 


$bird

    Fisher's Exact Test for Count Data

data:  X[[i]]
p-value = 0.03251
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 1.195396      Inf
sample estimates:
odds ratio 
       Inf 

然后,如果您想要 p 值,可以使用 sapply:

将它们放入向量中
sapply(tests, "[[", "p.value")
       cat        dog       bird 
0.01594203 0.10122358 0.03250774 

编辑:这可能是一个小改进。它更简洁一些。今天晚些时候,如果您关心性能(或者您对 运行 进行了大量测试),我可以检查它如何随 microbenchmark 扩展。另外,请记住用所有这些测试来惩罚那些 p 值;)。此外,@tmfmnk posted 一个很棒的 tidyverse 解决方案,如果你更喜欢 tidyverse 而不是 base。

# Create columns to later convert to a matrix
df$absent <- 0
df$present <- df$year_2016 - df$year_2017
df_t <- t(df[-1]) # tranpose dataframe excluding column of species

# Use lapply to create the list of matrices
matrix_list <- lapply(1:ncol(df_t), function(x) matrix(as.vector(df_t[,x]), 2, 2, byrow = T))
names(matrix_list) <- df$Species

# Running the fisher's test on every matrix 
# in the list and extracting the p-values
tests <- lapply(matrix_list, fisher.test)
sapply(tests, "[[", "p.value")
       cat        dog       bird 
0.01594203 0.10122358 0.03250774 

上次编辑。能够 运行 他们通过 microbenchmark 并希望 post 为将来遇到此 post 的任何人提供结果:

Unit: milliseconds

expr           min    lq     mean   median uq     max     neval
tidyverse_sol  12.506 13.497 15.130 14.560 15.827 26.205  100
base_sol       1.120  1.162  1.339  1.225  1.296  5.712   100

一个 tidyverse 可能性是:

library(tidyverse)
library(broom)

df %>%
 rowid_to_column() %>%
 gather(var, present, -c(Species, rowid)) %>%
 arrange(rowid, var) %>%
 group_by(rowid) %>%
 mutate(absent = lag(present, default = first(present)) - present) %>%
 ungroup() %>%
 select(-rowid, -var) %>%
 nest(present, absent) %>%
 mutate(p_value = data %>%
         map(~fisher.test(.)) %>%
         map(tidy) %>%
         map_dbl(pluck, "p.value")) %>%
 select(-data)

  Species p_value
  <chr>     <dbl>
1 cat      0.0159
2 dog      0.101 
3 bird     0.0325

在这里,它首先执行从宽到长的数据转换,不包括列 "Species" 和引用行 ID 的列。其次,它根据行 ID 和引用年份和组的原始列名按行 ID 排列数据。第三,它计算了年份之间的差异。最后,它嵌套每个物种的存在和缺失变量并执行 fisher.test,然后 returns 每个物种的 p 值。