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

一笑奈何 提交于 2019-12-20 09:47:49

问题


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?


回答1:


This is a trivial function to write yourself:

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



回答2:


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



回答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.




回答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.




回答5:


We can also find the norm as :

Result<-sum(abs(x)^2)^(1/2)

OR Even You can also try as:

Result<-sqrt(t(x)%*%x)

Both will give the same answer




回答6:


I'mma throw this out there too as an equivalent R expression

norm_vec(x) <- function(x){sqrt(crossprod(x))}

Don't confuse R's crossprod with a similarly named vector/cross product. That naming is known to cause confusion especially for those with a physics/mechanics background.




回答7:


If you have a data.frame or a data.table 'DT', and want to compute the Euclidian norm (norm 2) across each row, the apply function can be used.

apply(X = DT, MARGIN = 1, FUN = norm, '2')

Example:

>DT 

        accx       accy       accz
 1: 9.576807 -0.1629486 -0.2587167
 2: 9.576807 -0.1722938 -0.2681506
 3: 9.576807 -0.1634264 -0.2681506
 4: 9.576807 -0.1545590 -0.2681506
 5: 9.576807 -0.1621254 -0.2681506
 6: 9.576807 -0.1723825 -0.2682434
 7: 9.576807 -0.1723825 -0.2728810
 8: 9.576807 -0.1723825 -0.2775187

> apply(X = DT, MARGIN = 1, FUN = norm, '2')
 [1] 9.581687 9.582109 9.581954 9.581807 9.581932 9.582114 9.582245 9.582378



回答8:


Create your matrix as column vise using cbind then the norm function works well with Frobenius norm (the Euclidean norm) as an argument.

x1<-cbind(1:3)

norm(x1,"f")

[1] 3.741657

sqrt(1*1+2*2+3*3)

[1] 3.741657




回答9:


Following AbdealiJK's answer,

I experimented further to gain some insight.

Here's one.

x = c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299)
sqrt(sum(x^2))
norm(x, type='2')

The first result is Inf and the second one is 1.227355e+300 which is quite correct as I show you in the code below.

library(Rmpfr)
y <- mpfr(x, 120)
sqrt(sum(y*y))    

The result is 1227354879.... I didn't count the number of trailing numbers but it looks all right. I know there another way around this OVERFLOW problem which is first applying log function to all numbers and summing up, which I do not have time to implement!



来源:https://stackoverflow.com/questions/10933945/how-to-calculate-the-euclidean-norm-of-a-vector-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!