Подтвердить что ты не робот

Почему среднее() так медленно?

Все в вопросе! Я просто попытался немного оптимизировать и пригвоздить куски бутылки, из любопытства, я попробовал это:

t1 <- rnorm(10)
microbenchmark(
  mean(t1),
  sum(t1)/length(t1),
  times = 10000)

и результат состоит в том, что среднее() в 6 раз меньше, чем вычисление "вручную"!

Есть ли это из-за накладных расходов в коде mean() перед вызовом Internal (среднее) или это сам код C, который медленнее? Зачем? Есть ли веская причина и, следовательно, хороший прецедент?

4b9b3361

Ответ 1

Это связано с тем, что s3 ищет метод, а затем необходимый анализ аргументов в файле mean.default. (а также другой код в среднем)

sum и length являются примитивными функциями. так будет быстро (но как вы обрабатываете значения NA?)

t1 <- rnorm(10)
microbenchmark(
  mean(t1),
  sum(t1)/length(t1),
  mean.default(t1),
  .Internal(mean(t1)),
  times = 10000)

Unit: nanoseconds
                expr   min    lq median    uq     max neval
            mean(t1) 10266 10951  11293 11635 1470714 10000
  sum(t1)/length(t1)   684  1027   1369  1711  104367 10000
    mean.default(t1)  2053  2396   2738  2739 1167195 10000
 .Internal(mean(t1))   342   343    685   685   86574 10000

Внутренний бит mean быстрее, чем sum/length.

Подробнее см. http://rwiki.sciviews.org/doku.php?id=packages:cran:data.table#method_dispatch_takes_time (и решение data.table, которое позволяет избежать .Internal

Заметим, что если мы увеличим длину вектора, то примитивный подход будет самым быстрым

t1 <- rnorm(1e7)
microbenchmark(
     mean(t1),
     sum(t1)/length(t1),
     mean.default(t1),
     .Internal(mean(t1)),
+     times = 100)

Unit: milliseconds
                expr      min       lq   median       uq      max neval
            mean(t1) 25.79873 26.39242 26.56608 26.85523 33.36137   100
  sum(t1)/length(t1) 15.02399 15.22948 15.31383 15.43239 19.20824   100
    mean.default(t1) 25.69402 26.21466 26.44683 26.84257 33.62896   100
 .Internal(mean(t1)) 25.70497 26.16247 26.39396 26.63982 35.21054   100

Теперь отправка метода - это всего лишь часть общего "времени".

Ответ 2

mean медленнее, чем вычисление "вручную" по нескольким причинам:

  • Отправка метода S3
  • NA обработка
  • Коррекция ошибок

Баллы 1 и 2 уже рассмотрены. Точка 3 обсуждается в Какой алгоритм используется R для вычисления среднего?. В принципе, mean делает 2 прохода над вектором, чтобы исправить ошибки с плавающей запятой. sum делает только 1 проход над вектором.

Обратите внимание, что identical(sum(t1)/length(t1), mean(t1)) может быть FALSE из-за этих проблем точности.

> set.seed(21); t1 <- rnorm(1e7,,21)
> identical(sum(t1)/length(t1), mean(t1))
[1] FALSE
> sum(t1)/length(t1) - mean(t1)
[1] 2.539201e-16