R:扫描向量一次而不是 4 次?
R: scan vectors once instead of 4 times?
假设我有两个等长的逻辑向量。
计算 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。速度不是我这里主要考虑的,我更感兴趣的是理解语言。
table
计算交叉表,如果 actual
和 predicted
只包含零和一,应该会给出类似的结果:
table(actual, predicted)
在内部,这是通过 paste
ing 向量来实现的——效率极低。似乎 character
的强制也发生在仅列出一个值时,这可能是 table(actual*2 + predicted)
.
表现不佳的原因
您可以尝试使用 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.5
和 dplyr_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
包括来自 dplyr
和 tabulate
的 count
也在稍大数据集的基准测试中
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
像这样:
tabulate(4 - actual - 2*predicted, 4)
(这里的tabulate
比table
快得多,因为它知道输出将是一个长度为4的向量)。
假设我有两个等长的逻辑向量。 计算 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。速度不是我这里主要考虑的,我更感兴趣的是理解语言。
table
计算交叉表,如果 actual
和 predicted
只包含零和一,应该会给出类似的结果:
table(actual, predicted)
在内部,这是通过 paste
ing 向量来实现的——效率极低。似乎 character
的强制也发生在仅列出一个值时,这可能是 table(actual*2 + predicted)
.
您可以尝试使用 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.5
和 dplyr_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
包括来自 dplyr
和 tabulate
的 count
也在稍大数据集的基准测试中
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
像这样:
tabulate(4 - actual - 2*predicted, 4)
(这里的tabulate
比table
快得多,因为它知道输出将是一个长度为4的向量)。