Циклы в R медленные по той же причине, что и любой интерпретируемый язык медленный: каждая операция влечет за собой много дополнительного багажа.
Посмотрите на R_execClosure
в eval.c
(это функция, вызываемая для вызова пользовательской функции).Он длиной почти 100 строк и выполняет все виды операций - создание среды для выполнения, назначение аргументов в среду и т. Д.
Подумайте, насколько меньше будет происходить, когда вы вызываете функцию в C (выдвигайте аргументы наstack, jump, pop args).
Вот почему вы получаете такие моменты времени (как указывал Джоран в комментарии, на самом деле это не apply
, это быстро, это внутренний цикл C в mean
это быстро. apply
это просто обычный старый код R):
A = matrix(as.numeric(1:100000))
Использование цикла: 0,342 секунды:
system.time({
Sum = 0
for (i in seq_along(A)) {
Sum = Sum + A[[i]]
}
Sum
})
Использование суммы: неизмеримо мало:
sum(A)
Это немного сбивает с толку, потому что, асимптотически, цикл так же хорош, как sum
;нет никакой практической причины, это должно быть медленным;это просто делает больше дополнительной работы каждую итерацию.
Итак, рассмотрим:
# 0.370 seconds
system.time({
I = 0
while (I < 100000) {
10
I = I + 1
}
})
# 0.743 seconds -- double the time just adding parentheses
system.time({
I = 0
while (I < 100000) {
((((((((((10))))))))))
I = I + 1
}
})
(Этот пример был обнаружен Рэдфорд Нил )
Потому что (
в R является оператором и фактически требует поиска имени каждый раз, когда вы его используете:
> `(` = function(x) 2
> (3)
[1] 2
Или, как правило, интерпретируемые операции (на любом языке) имеют больше шагов.Конечно, эти шаги также дают преимущества: вы не можете сделать этот (
трюк в C.