【问题标题】:Count the number of valid observations (no NA) pairwise in a data frame在数据框中成对地计算有效观察值(无 NA)的数量
【发布时间】:2012-03-13 21:10:39
【问题描述】:

假设我有一个这样的数据框:

Df <- data.frame(
    V1 = c(1,2,3,NA,5),
    V2 = c(1,2,NA,4,5),
    V3 = c(NA,2,NA,4,NA)
)

现在我想计算两个变量的每个组合的有效观察数。为此,我写了一个函数sharedcount

sharedcount <- function(x,...){
    nx <- names(x)
    alln <- combn(nx,2)
    out <- apply(alln,2,
      function(y)sum(complete.cases(x[y]))
    )
    data.frame(t(alln),out)
}

这给出了输出:

> sharedcount(Df)
  X1 X2 out
1 V1 V2   3
2 V1 V3   1
3 V2 V3   2

一切都很好,但是函数本身在大数据帧上需要很长时间(600 个变量和大约 10000 个观察值)。我感觉我正在监督一种更简单的方法,特别是因为 cor(...,use='pairwise') 运行速度仍然快得多,而它必须做类似的事情:

> require(rbenchmark)    
> benchmark(sharedcount(TestDf),cor(TestDf,use='pairwise'),
+     columns=c('test','elapsed','relative'),
+     replications=1
+ )
                           test elapsed relative
2 cor(TestDf, use = "pairwise")    0.25     1.0
1           sharedcount(TestDf)    1.90     7.6

感谢任何提示。


注意:使用文森特的技巧,我编写了一个返回相同数据帧的函数。代码在我下面的答案中。

【问题讨论】:

    标签: r dataframe missing-data


    【解决方案1】:

    下面的稍微快一点:

    x <- !is.na(Df)
    t(x) %*% x
    
    #       test elapsed relative
    #    cor(Df)  12.345 1.000000
    # t(x) %*% x  20.736 1.679708
    

    【讨论】:

    • 非常好! crossprod(x) 而不是 t(x) %*% x 仍然可以改进一点。我仍然需要将其放入示例中的数据框中,但这并不难。
    • 因为你的诀窍是缩短时间,所以你是公认的答案。我给出了自己的函数作为参考答案。
    【解决方案2】:

    我认为文森特看起来非常优雅,更不用说比我的二年级 for 循环更快,除了它似乎需要我在下面添加的提取步骤。这只是与数据帧一起使用时应用方法中大量开销的示例。

    shrcnt <- function(Df) {Comb <- t(combn(1:ncol(Df),2) )
    shrd <- 1:nrow(Comb)
    for (i in seq_len(shrd)){ 
         shrd[i] <- sum(complete.cases(Df[,Comb[i,1]], Df[,Comb[i,2]]))}
    return(shrd)}
    
       benchmark(
          shrcnt(Df), sharedcount(Df), {prs <- t(x) %*% x; prs[lower.tri(prs)]}, 
          cor(Df,use='pairwise'),
            columns=c('test','elapsed','relative'),
            replications=100
          )
     #--------------
                           test elapsed relative
    3                         {   0.008      1.0
    4 cor(Df, use = "pairwise")   0.020      2.5
    2           sharedcount(Df)   0.092     11.5
    1                shrcnt(Df)   0.036      4.5
    

    【讨论】:

    • 也是一个不错的优化。为我上一堂课:使用索引,而不是名称。
    【解决方案3】:

    基于 Vincent 的可爱技巧和 DWin 的附加 lower.tri() 建议,我想出了以下函数,它可以提供与原始输出相同的输出(即数据框),并且运行速度要快得多:

    sharedcount2 <- function(x,stringsAsFactors=FALSE,...){
        counts <- crossprod(!is.na(x))
        id <- lower.tri(counts)
        count <- counts[id]
        X1 <- colnames(counts)[col(counts)[id]]
        X2 <- rownames(counts)[row(counts)[id]]
        data.frame(X1,X2,count)
    }
    

    注意crossprod() 的使用,因为与%*% 相比,它提供了一个小的改进,但它完全一样。

    时间安排:

    > benchmark(sharedcount(TestDf),sharedcount2(TestDf),
    +           replications=5,
    +           columns=c('test','replications','elapsed','relative'))
    
                      test replications elapsed relative
    1  sharedcount(TestDf)            5   10.00 90.90909
    2 sharedcount2(TestDf)            5    0.11  1.00000
    

    注意:我在问题中提供了 TestDf,因为我注意到时间根据数据帧的大小而有所不同。如此处所示,与使用小数据框相比,时间增加要显着得多。

    【讨论】:

      猜你喜欢
      • 2016-06-26
      • 1970-01-01
      • 2022-12-08
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多