Me sorprendió que nadie hubiera intentado perfilar los resultados de los métodos sugeridos anteriormente, así que lo hice. Usé una función de distribución uniforme aleatoria para generar una lista y la utilicé para la repetición (solo un simple tipo de referencia rápido):
> uut <- lapply(1:100000, function(x) {runif(1000, min=-10^10, max=10^10)})
> norm_vec <- function(x) sqrt(sum(x^2))
> norm_vec2 <- function(x){sqrt(crossprod(x))}
>
> system.time(lapply(uut, norm_vec))
user system elapsed
0.58 0.00 0.58
> system.time(lapply(uut, norm_vec2))
user system elapsed
0.35 0.00 0.34
> system.time(lapply(uut, norm, type="2"))
user system elapsed
6.75 0.00 6.78
> system.time(lapply(lapply(uut, as.matrix), norm))
user system elapsed
2.70 0.00 2.73
Parece que elevar al cuadrado y luego tomar la raíz cuadrada manualmente es más rápido que el builtin norm
para vectores de valores reales al menos. Esto se debe probablemente a que internamente norm hace una SVD:
> norm
function (x, type = c("O", "I", "F", "M", "2"))
{
if (identical("2", type)) {
svd(x, nu = 0L, nv = 0L)$d[1L]
}
else .Internal(La_dlange(x, type))
}
y la función SVD internamente convierte el vector en una matriz, y realiza operaciones más complicadas:
> svd
function (x, nu = min(n, p), nv = min(n, p), LINPACK = FALSE)
{
x <- as.matrix(x)
...
EDICIÓN (20 Oct 2019):
Ha habido algunos comentarios que señalan el problema de corrección que el caso de prueba anterior no revela:
> norm_vec(c(10^155))
[1] Inf
> norm(c(10^155), type="2")
[1] 1e+155
Esto sucede porque los números grandes se consideran como infinito en R:
> 10^309
[1] Inf
Así que parece que:
Parece que elevar al cuadrado y luego tomar la raíz cuadrada manualmente es más rápido que el builtin norm para vectores de valores reales para números pequeños.
¿Qué tan pequeños? Lo suficiente para que la suma de los cuadrados no se desborde.