если бы у вас был вектор 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