如果你有一个向量x,计算三个最大值之和的函数可能是
fun = function(x)
sum(tail(sort(x), 3))
您想将此应用于对象的每一行m
apply(m, 1, fun)
一个稍快(例如,40%)的实现是
colSums(apply(m, 1, sort, decreasing = TRUE)[1:3, ])
或者使用部分排序
colSums(apply(m, 1, sort.int, partial = 9:11)[9:11, ])
为了性能,如果m 中有很多行,请避免使用apply() 隐含的对行的迭代。一个实现可能是
library(matrixStats)
rowSums(m * (rowRanks(m) > ncol(m) - 3))
但是当m 的行中有联系时,这会失败; rowRanks() 不支持 ties.method = "first"。相反,实现我们自己的rowRanks()
.rowRanks <- function(m) {
m[] = sort.list(sort.list(m))
rowRanks(m)
}
rowSums(m * (.rowRanks(m) > ncol(m) - 3))
对于一个 tidyverse 解决方案,似乎要从整洁的数据开始
tbl <- df %>%
rowid_to_column() %>%
gather("letter","value",-1) %>%
group_by(rowid)
使用top_n() 的解决方案会产生不正确的结果,因此最好的选择似乎是
summarize(tbl, fun(value))
(fun 可以在这里扩展,但这似乎不是一个好主意,因为它使得单独修改和测试变得更加困难)。
比较方法
f0 = function(m) apply(m, 1, fun)
f0a = function(m) colSums(apply(m, 1, sort, decreasing=TRUE)[1:3, ])
f0b = function(m) colSums(apply(m, 1, sort.int, partial = 9:11)[9:11, ])
f1 = function(m) rowSums(m * (.rowRanks(m) > ncol(m) - 3))
f2 = function(tbl) summarize(tbl, fun(value))
与
> library(microbenchmark)
> identical(f0(m), f0a(m))
[1] TRUE
> identical(f0(m), f0b(m))
[1] TRUE
> identical(f0(m), f1(m))
[1] TRUE
> identical(f0(m), f2(tbl)$`fun(value)`)
[1] TRUE
> microbenchmark(f0(m), f0a(m), f0b(m), f1(m), f2(tbl), times=10)
Unit: microseconds
expr min lq mean median uq max neval
f0(m) 837.505 860.890 894.9245 905.9880 921.386 948.242 10
f0a(m) 594.895 637.258 650.7217 653.1800 673.599 713.167 10
f0b(m) 274.925 277.734 305.6551 296.2975 330.482 362.765 10
f1(m) 166.416 169.290 192.8086 189.5945 215.491 219.478 10
f2(tbl) 2265.451 2277.599 2425.6083 2327.7015 2359.896 3349.995 10
> m = m[sample(nrow(m), 1000, TRUE),]
> microbenchmark(f0(m), f0a(m), f0b(m), f1(m), times=10)
Unit: milliseconds
expr min lq mean median uq max neval
f0(m) 137.705781 139.793459 141.658415 141.821540 143.653272 144.428092 10
f0a(m) 85.946679 86.663967 88.500392 87.513880 89.634696 94.458554 10
f0b(m) 29.762981 30.890124 32.470553 32.649594 33.116767 36.686603 10
f1(m) 2.034407 2.120689 2.137723 2.144328 2.176306 2.184712 10