Los bucles en R son lentos por la misma razón que cualquier lenguaje interpretado es lento: cada operación conlleva mucho equipaje adicional.
Mire R_execClosureeneval.c (esta es la función llamada para llamar a una función definida por el usuario). Tiene casi 100 líneas de largo y realiza todo tipo de operaciones: crear un entorno de ejecución, asignar argumentos al entorno, etc.
Piense en cuánto menos sucede cuando llama a una función en C (presione args para apilar, saltar, hacer pop args).
Entonces, es por eso que obtienes tiempos como estos (como Joran señaló en el comentario, en realidad no es applyque sea rápido; es el bucle C interno lo mean
que es rápido. applyEs solo un código R antiguo normal):
A = matrix(as.numeric(1:100000))
Usando un bucle: 0.342 segundos:
system.time({
Sum = 0
for (i in seq_along(A)) {
Sum = Sum + A[[i]]
}
Sum
})
Usando sum: inmensurablemente pequeño:
sum(A)
Es un poco desconcertante porque, asintóticamente, el bucle es tan bueno como sum; no hay ninguna razón práctica para que sea lento; solo está haciendo más trabajo extra en cada iteración.
Así que considere:
system.time({
I = 0
while (I < 100000) {
10
I = I + 1
}
})
system.time({
I = 0
while (I < 100000) {
((((((((((10))))))))))
I = I + 1
}
})
(Ese ejemplo fue descubierto por Radford Neal )
Porque (en R es un operador, y en realidad requiere una búsqueda de nombre cada vez que lo usa:
> `(` = function(x) 2
> (3)
[1] 2
O, en general, las operaciones interpretadas (en cualquier idioma) tienen más pasos. Por supuesto, esos pasos también brindan beneficios: no podría hacer ese (truco en C.
system.timecomiencen las guerras en las respuestas ...