Эффективность кода: применять семейные или оптимизированные альтернативы - PullRequest
2 голосов
/ 05 марта 2019

Я всегда воспринимал это как факт, что colMeans() или colSums() - это самый быстрый способ выполнения соответствующих операций.Как правило, я имею в виду базовые, а не dplyr или data.table реализации.

Обучая некоторых новых пользователей, я сам проверил эталонный тест, чтобы доказать это.Сейчас я постоянно вижу противоречивые выводы.

n = 10000
p = 100

test_matrix <- matrix(runif(n*p), n, p)
test_df <- as.data.frame(test_matrix) 

benchmark <- microbenchmark(
  colMeans(test_df),
  colMeans(as.matrix(test_df)),
  sapply(test_df, mean),
  vapply(test_df, mean, 0),
  colMeans(test_matrix),
  apply(test_matrix, 2, mean)
)

Unit: microseconds
                         expr      min        lq      mean    median        uq       max neval
            colMeans(test_df) 3099.941 3165.8290  3733.024  3241.345  3617.039 11387.090   100
 colMeans(as.matrix(test_df)) 3091.634 3158.0880  3553.537  3241.345  3548.507  8531.067   100
        sapply(test_df, mean) 2209.227 2267.3750  2723.176  2338.172  2602.289 10384.612   100
     vapply(test_df, mean, 0) 2180.153 2228.2945  2611.982  2270.584  2514.123  7421.356   100
        colMeans(test_matrix)  904.307  915.0685  1020.085   939.422  1002.667  2985.911   100
  apply(test_matrix, 2, mean) 9748.388 9957.0020 12098.328 10330.429 12582.889 34873.009   100

Для матрицы colMeans() факелы apply() Это ожидаемо.Но для фрейма данных sapply() и vapply() обычно бьют colMeans(), даже когда я увеличиваю n и p.Есть ли причина, по которой я хотел бы использовать colMeans() для фрейма данных?Похоже, что разница возникает из-за издержек, связанных с преобразованием кадра данных обратно в матрицу.

microbenchmark of means

Основной вопрос

Другими словами, есть ли причина, по которой (более формальная версия) следующее было бы нецелесообразным?Тесты показывают, что в основном не выпадают.Очевидно, это делает предположение о вводе, который вводит пользователь, но здесь дело не в этом.

colMeans2 <- function(myobject) {
  if (typeof(myobject) == "double") {
    colMeans(myobject)
  } else if (typeof(myobject) == "list") {
    vapply(myobject, mean, 0)
  } else {
    stop("what is this")
  }
}

Для справки

Вот еще два поста, которые яможно найти как несколько связанные, так и упоминания о том, как colMeans() должно быть быстрее.

Функции группировки (tapply, by, aggregate) и * apply family

Почему функции `colMeans ()` и `rowMeans ()` работают быстрее, чем использование средней функции с `lapply ()`?

...