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_execClosure
eneval.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 apply
que sea rápido; es el bucle C interno lo mean
que es rápido. apply
Es 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.time
comiencen las guerras en las respuestas ...