how to calculate the Euclidean norm of a vector in R?

I tried norm, but I think it gives the wrong result. (the norm of c(1, 2, 3) is sqrt(1*1+2*2+3*3), but it returns 6..

x1 <- 1:3
norm(x1)
# Error in norm(x1) : 'A' must be a numeric matrix
norm(as.matrix(x1))
# [1] 6
as.matrix(x1)
#      [,1]
# [1,]    1
# [2,]    2
# [3,]    3
norm(as.matrix(x1))
# [1] 6

Does anyone know what's the function to calculate the norm of a vector in R?


Solution 1:

norm(c(1,1), type="2")     # 1.414214
norm(c(1, 1, 1), type="2")  # 1.732051

Solution 2:

This is a trivial function to write yourself:

norm_vec <- function(x) sqrt(sum(x^2))

Solution 3:

I was surprised that nobody had tried profiling the results for the above suggested methods, so I did that. I've used a random uniform function to generate a list and used that for repetition (Just a simple back of the envelop type of benchmark):

> 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 

It seems that taking the power and then sqrt manually is faster than the builtin norm for real values vectors at least. This is probably because norm internally does an 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))
}

and the SVD function internally converts the vector into a matrix, and does more complicated stuff:

> svd
function (x, nu = min(n, p), nv = min(n, p), LINPACK = FALSE) 
{
    x <- as.matrix(x)
    ...

EDIT (20 Oct 2019):

There have been some comments to point out the correctness issue which the above test case doesn't bring out:

> norm_vec(c(10^155))
[1] Inf
> norm(c(10^155), type="2")
[1] 1e+155

This happens because large numbers are considered as infinity in R:

> 10^309
[1] Inf

So, it looks like:

It seems that taking the power and then sqrt manually is faster than the builtin norm for real values vectors for small numbers.

How small? So that the sum of squares doesn't overflow.

Solution 4:

norm(x, type = c("O", "I", "F", "M", "2"))

The default is "O".

"O", "o" or "1" specifies the one norm, (maximum absolute column sum);

"F" or "f" specifies the Frobenius norm (the Euclidean norm of x treated as if it were a vector);

norm(as.matrix(x1),"o")

The result is 6, same as norm(as.matrix(x1))

norm(as.matrix(x1),"f")

The result is sqrt(1*1+2*2+3*3)

So, norm(as.matrix(x1),"f") is answer.