【问题标题】:R: scan vectors once instead of 4 times?R:扫描向量一次而不是 4 次?
【发布时间】:2015-03-12 23:29:47
【问题描述】:

假设我有两个长度相等的逻辑向量。 计算confusion matrix 的简单方法:

c(sum(actual == 1 & predicted == 1),
  sum(actual == 0 & predicted == 1),
  sum(actual == 1 & predicted == 0),
  sum(actual == 0 & predicted == 0))

需要扫描向量 4 次。

是否可以一次性完成?

PS。我试过table(2*actual+predicted)table(actual,predicted) 但显然都慢得多。

PPS。速度不是我在这里的主要考虑因素,我对理解语言更感兴趣。

【问题讨论】:

  • 也许你可以试试data.table。 IE。 DT <- data.table(actual, predicted); setkey(DT, actual, predicted)[,.N, .(actual, predicted)]$N
  • 这确实更快!我猜 data.table 使用基数排序?
  • 这个链接可能对stackoverflow.com/questions/20039335/…有帮助
  • @akrun:请将您的评论变成答案
  • 没有data.table 可能快,但也不是太破旧data_frame(actual, predicted) %>% group_by(actual, predicted) %>% summarise(n())

标签: r


【解决方案1】:

你可以试试data.table

library(data.table)
DT <- data.table(actual, predicted)
setkey(DT, actual, predicted)[,.N, .(actual, predicted)]$N

数据

set.seed(24)
actual <- sample(0:1, 10 , replace=TRUE)
predicted <- sample(0:1, 10, replace=TRUE)

基准测试

使用data.table_1.9.5dplyr_0.4.0

library(microbenchmark)
set.seed(245)
actual <- sample(0:1, 1e6 , replace=TRUE)
predicted <- sample(0:1, 1e6, replace=TRUE)
f1 <- function(){
  DT <- data.table(actual, predicted)
  setkey(DT, actual, predicted)[,.N, .(actual, predicted)]$N}

f2 <- function(){table(actual, predicted)}
f3 <- function() {data_frame(actual, predicted) %>%
                      group_by(actual, predicted) %>% 
                      summarise(n())}

microbenchmark(f1(), f2(), f3(), unit='relative', times=20L)
#Unit: relative
# expr       min        lq      mean   median        uq       max neval cld
#f1()  1.000000  1.000000  1.000000  1.00000  1.000000  1.000000    20  a 
#f2() 20.818410 22.378995 22.321816 22.56931 22.140855 22.984667    20   b
#f3()  1.262047  1.248396  1.436559  1.21237  1.220109  2.504662    20  a 

包括来自dplyrtabulatecount 也在稍大数据集的基准测试中

set.seed(498)
actual <- sample(0:1, 1e7 , replace=TRUE)
predicted <- sample(0:1, 1e7, replace=TRUE)
f4 <- function() {data_frame(actual, predicted) %>% 
                       count(actual, predicted)}
f5 <- function(){tabulate(4-actual-2*predicted, 4)}

更新

在基准测试中也包含另一个data.table 解决方案(由@Arun 提供)

f6 <- function() {setDT(list(actual, predicted))[,.N, keyby=.(V1,V2)]$N}

microbenchmark(f1(),  f3(), f4(), f5(), f6(),  unit='relative', times=20L)
#Unit: relative
#expr      min       lq     mean   median       uq      max neval  cld
#f1() 2.003088 1.974501 2.020091 2.015193 2.080961 1.924808    20   c 
#f3() 2.488526 2.486019 2.450749 2.464082 2.481432 2.141309    20    d
#f4() 2.388386 2.423604 2.430581 2.459973 2.531792 2.191576    20    d
#f5() 1.034442 1.125585 1.192534 1.217337 1.239453 1.294920    20  b  
#f6() 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    20 a   

【讨论】:

  • 这与 plyr::count 或 Khashaa 建议的 dplyr 解决方案相比如何?
  • @flodel 的解决方案中的tabulate 怎么样?
  • @sds 看起来更快,因为它不需要转换为data.table/data.frame 以及grouping
  • data.table 解决方案可能只是:setDT(list(actual, predicted))[,.N, keyby=.(V1,V2)]$N
  • @Arun 感谢您的评论。我会将其包含在基准测试中。
【解决方案2】:

像这样:

tabulate(4 - actual - 2*predicted, 4)

(这里的tabulatetable 快得多,因为它知道输出将是一个长度为4 的向量)。

【讨论】:

    【解决方案3】:

    table 计算交叉表,如果 actualpredicted 仅包含零和一,则应给出相似的结果:

    table(actual, predicted)
    

    在内部,这是通过pasteing 向量来实现的——效率极低。似乎对character 的强制也发生在仅列出一个值时,这可能也是table(actual*2 + predicted) 表现不佳的原因。

    【讨论】:

    • 仍然很慢。这是我能期待的最好的吗?
    • @sds:你的向量有多长?它们包含什么?
    • 长度为 3135417 的逻辑向量
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 2018-06-21
    相关资源
    最近更新 更多