【问题标题】:Apply function over dataframe including rbind statement在数据帧上应用函数,包括 rbind 语句
【发布时间】:2020-08-05 20:33:39
【问题描述】:

我正在寻找在一个非常大的数据框中使用四列来应用 fisher.test 的最快方法

下面是一个使用慢 for 循环的测试示例。

应用会更快,但我不知道如何在应用函数中使用 rbind。

也非常欢迎提供更快的建议。

testdf<-data.frame(a=c(80,1,3,4),b=c(100,200,300,400),c=c(1,2,3,4),d=c(200,250,350,450))

for (i in 1:nrow(testdf)){
  testdf$e[i] <- fisher.test(rbind(c(testdf$a[i],testdf$b[i]),c(testdf$c[i],testdf$d[i])))$p.value
}

非常感谢您的帮助

【问题讨论】:

  • FWIW(我知道你有解决方案)。我针对您的数据的 10,000 行变体(无重复)运行 microbenchmarkfor-loop 耗时 7.323463 秒,apply 耗时 7.083603,而我的 tidyverse 解决方案 7.346125 显然还有其他权衡,但在这种情况下不会出现循环慢得多。

标签: r loops dataframe apply


【解决方案1】:

由于rowwise 的状态为“质疑”,这里有一个带有dplyrpurrr 的tidyverse 解决方案。请参阅我上面的评论,在这种情况下,对 10,000 行进行基准测试,所有 3 行都需要非常相似的时间。

library(dplyr)
library(purrr)
testdf<-data.frame(a=c(80,1,3,4,80),b=c(100,200,300,400,100),c=c(1,2,3,4,1),d=c(200,250,350,450,200))
testdf <- 
  testdf %>%
  distinct %>%
  mutate(e = pmap_dbl(.l = list(a, b, c, d),
                      .f = ~ fisher.test(matrix(c(..1, ..2, ..3, ..4),
                                                ncol = 2,
                                                byrow = TRUE)
                                         )$p.value
                      )
          )

reprex package (v0.3.0) 于 2020-04-24 创建

【讨论】:

    【解决方案2】:

    这是使用dplyr::rowwisetidyverse 解决方案。我使用了您的原始语法以及@StupidWolf 的矩阵建议。在您非常小的数据集上,它的速度似乎大约是原来的两倍。

    # https://stackoverflow.com/questions/61371610/apply-function-over-dataframe-including-rbind-statement
    
    library(dplyr)
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    
    testdf<-data.frame(a=c(80,1,3,4),b=c(100,200,300,400),c=c(1,2,3,4),d=c(200,250,350,450))
    
    for (i in 1:nrow(testdf)){
      testdf$e[i] <- fisher.test(rbind(c(testdf$a[i],testdf$b[i]),c(testdf$c[i],testdf$d[i])))$p.value
    }
    
    testdf <- testdf %>% 
      distinct() %>%
      rowwise() %>% 
      mutate(pvalue1 = fisher.test(rbind(c(a, b), 
                                         c(c, d)))$p.value)
    
    testdf <- testdf %>% 
      distinct() %>%
      rowwise() %>% 
      mutate(pvalue2 = fisher.test(matrix(c(a, b, c, d), 
                                          ncol = 2))$p.value)
    
    testdf
    #> Source: local data frame [4 x 7]
    #> Groups: <by row>
    #> 
    #> # A tibble: 4 x 7
    #>       a     b     c     d        e  pvalue1  pvalue2
    #>   <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>    <dbl>
    #> 1    80   100     1   200 3.00e-30 3.00e-30 3.00e-30
    #> 2     1   200     2   250 1.00e+ 0 1.00e+ 0 1.00e+ 0
    #> 3     3   300     3   350 1.00e+ 0 1.00e+ 0 1.00e+ 0
    #> 4     4   400     4   450 1.00e+ 0 1.00e+ 0 1.00e+ 0
    all.equal(testdf$e, testdf$pvalue1)
    #> [1] TRUE
    all.equal(testdf$e, testdf$pvalue2)
    #> [1] TRUE
    

    reprex package (v0.3.0) 于 2020 年 4 月 23 日创建

    【讨论】:

      【解决方案3】:

      您可以尝试将行强制转换为矩阵:

      apply(testdf,1,function(i)fisher.test(matrix(i,ncol=2))$p.value)
      

      正如@Chuck 所指出的,它应该是 byrow=TRUE,以测试完全相同的矩阵。我选择了一条捷径,因为使用 fisher.test,您正在测试行和列之间的关联。只要不交换对角线,就可以得到相同的 p 值和优势比

      如果您的矩阵确实很大,有几种方法,一种是获取矩阵中的唯一值,然后计算这些 pvalue。

      另一种方法是计算the pvalue directly,但这仅适用于单面测试。

      【讨论】:

      • 要生成与@mgene 相同的答案,您需要添加byrow = TRUE
      • 非常感谢,这非常有效。如果我在运行之前将数据帧过滤为唯一值并在之后合并回来,它会将其缩短到可管理的操作时间。非常感谢您的帮助。
      • 哦,是的..很高兴独特的价值观适合你。是的,我不太喜欢单方面的测试。
      • 我确实尝试过运行它。他生成...` testdf$e [1] 3.00086e-30 1.00000e+00 1.00000e+00 1.00000e+00` 你生成` apply(testdf,1,function(i)fisher.test(matrix(i, ncol=2))$p.value) [1] 5.177477e-59 7.384057e-130 2.497031e-186 1.932974e-244` 因为matrix 默认首先运行列...
      • 好的,好点。我不知道你为什么得到这样的值,但是在fisher.test中,p.value是一样的,不管你是否翻转它。因为您正在测试行和列之间的关联。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      • 2011-09-24
      • 1970-01-01
      • 2013-12-01
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多