如何计算R中向量的欧几里德范数?

时间:2012-06-07 14:34:28

标签: r vector statistics

我尝试了norm,但我认为它给出了错误的结果。 (c(1, 2, 3)的标准为sqrt(1*1+2*2+3*3),但会返回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

有谁知道在R中计算向量范数的函数是什么?

10 个答案:

答案 0 :(得分:51)

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

答案 1 :(得分:42)

这是一个简单的函数来写自己:

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

答案 2 :(得分:12)

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

默认值为"O"

"O""o""1"指定一个标准,(最大绝对列总和);

“F”或“f”指定Frobenius范数(x的欧几里德范数被视为矢量);

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

结果为6,与norm(as.matrix(x1))

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

结果为sqrt(1*1+2*2+3*3)

所以,norm(as.matrix(x1),"f")就是答案。

答案 3 :(得分:12)

我很惊讶没有人尝试过对上述建议方法的结果进行分析,所以我这样做了。我使用了一个随机的统一函数来生成一个列表并将其用于重复(只是一个简单的背包信封类型):

> 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 

似乎手动获取功率然后sqrt比内置norm更快地获得实数值向量。这可能是因为规范内部做了一个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))
}

并且SVD函数在内部将向量转换为矩阵,并且执行更复杂的操作:

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

答案 4 :(得分:2)

我们也可以找到标准:

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

或者您甚至可以尝试:

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

两者都会给出相同的答案

答案 5 :(得分:2)

我也把它当作等效的R表达式抛出

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

不要将R的crossprod与同名的矢量/ cross product混淆。众所周知,这种命名会导致confusion,特别是那些具有物理/力学背景的人。

答案 6 :(得分:1)

如果您有data.frame或data.table&#39; DT&#39;,并希望计算每行的欧几里德范数(规范2),则可以使用apply函数。

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

示例:

>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

答案 7 :(得分:1)

为避免破坏性下溢和溢出而对向量的欧式长度(k范数)进行解答

norm <- function(x, k) { max(abs(x))*(sum((abs(x)/max(abs(x)))^k))^(1/k) }

有关说明,请参见下文。

1。没有缩放比例的向量的欧几里得长度:


norm()是一个向量值函数,用于计算向量的长度。它有两个参数,例如类x的向量matrix和类k的范数integer的类型。

norm <- function(x, k) {
  # x = matrix with column vector and with dimensions mx1 or mxn
  # k = type of norm with integer from 1 to +Inf
  stopifnot(k >= 1) # check for the integer value of k greater than 0
  stopifnot(length(k) == 1) # check for length of k to be 1. The variable k is not vectorized.
  if(k == Inf) {
    # infinity norm
    return(apply(x, 2, function(vec) max(abs(vec)) ))
  } else {
    # k-norm
    return(apply(x, 2, function(vec) (sum((abs(vec))^k))^(1/k) ))
  }
}

x <- matrix(c(1,-2,3,-4)) # column matrix
sapply(c(1:4, Inf), function(k) norm(x = x, k = k))
# [1] 10.000000  5.477226  4.641589  4.337613  4.000000
  • 1-范数(10.0)收敛到无穷范数(4.0)。
  • k范数也称为“欧几里德n维空间中的欧几里德范数”。

注意:norm()函数定义中,对于具有实分量的向量,可以将绝对值放入norm-2k甚至索引范数中,其中k >= 1

如果您对norm函数定义感到困惑,则可以按以下说明逐一阅读。

norm_1 <- function(x) sum(abs(x))
norm_2 <- function(x) (sum((abs(x))^2))^(1/2)
norm_3 <- function(x) (sum((abs(x))^3))^(1/3)
norm_4 <- function(x) (sum((abs(x))^4))^(1/4)
norm_k <- function(x) (sum((abs(x))^k))^(1/k)
norm_inf <- max(abs(x))

2。具有缩放比例的向量的欧式长度,以避免破坏性的上溢和下溢问题:


注2: 此解决方案norm()的唯一问题是,它无法防范所暗示的herehere的上溢或下溢问题。

幸运的是,有人已经在blas(基本线性代数子例程)fortran库中针对2-范数(欧几里德长度)解决了这个问题。有关此问题的说明,可在“ Kahaner,Moler和Nash的数值方法和软件”教科书中找到-第1章,第1.3节,第7-9页。

fortran子例程的名称为dnrm2.f,它通过缩放矢量分量的最大值来处理norm()中破坏性的上溢和下溢问题。由于norm()函数中的基本操作,导致破坏性的上溢和下溢问题。

我将在下面的dnrm2.f中展示如何实现R

#1. find the maximum among components of vector-x
max_x <- max(x)
#2. scale or divide the components of vector by max_x
scaled_x <- x/max_x
#3. take square of the scaled vector-x
sq_scaled_x <- (scaled_x)^2
#4. sum the square of scaled vector-x
sum_sq_scaled_x <- sum(sq_scaled_x)
#5. take square root of sum_sq_scaled_x
rt_sum_sq_scaled_x  <- sqrt(sum_sq_scaled_x)
#6. multiply the maximum of vector x with rt_sum_sq_scaled_x
max_x*rt_sum_sq_scaled_x

dnrm2.fR的上述6个步骤中的一个是:

# Euclidean length of vector - 2norm
max(x)*sqrt(sum((x/max(x))^2))

让我们尝试使用示例矢量来计算此2范数(请参阅此线程中的其他解决方案)。

x = c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299)
max(x)*sqrt(sum((x/max(x))^2))
# [1] 1.227355e+300

x <- (c(1,-2,3,-4))
max(x)*sqrt(sum((x/max(x))^2))
# [1] 5.477226

因此,在R中为k范数实施广义解决方案的推荐方法是单行,以防止破坏性的上溢或下溢问题。要改善这种单行代码,您可以结合使用norm()而不对包含分量不太小或不太大的向量进行缩放,而对knorm()进行组合而对不包含太小的分量的向量进行缩放较小或太大的组件。对所有矢量实施缩放会导致太多的计算。我没有在下面给出的knorm()中实现此改进。

# one-liner for k-norm - generalized form for all norms including infinity-norm:
max(abs(x))*(sum((abs(x)/max(abs(x)))^k))^(1/k)

# knorm() function using the above one-liner.
knorm <- function(x, k) { 
  # x = matrix with column vector and with dimensions mx1 or mxn
  # k = type of norm with integer from 1 to +Inf
  stopifnot(k >= 1) # check for the integer value of k greater than 0
  stopifnot(length(k) == 1) # check for length of k to be 1. The variable k is not vectorized.
  # covert elements of matrix to its absolute values
  x <- abs(x)
  if(k == Inf) { # infinity-norm
    return(apply(x, 2, function(vec) max(vec)))
  } else { # k-norm
    return(apply(x, 2, function(vec) {
      max_vec <- max(vec)
      return(max_vec*(sum((vec/max_vec)^k))^(1/k))
    }))
  }
}

# 2-norm
x <- matrix(c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299))
sapply(2, function(k) knorm(x = x, k = k))
# [1] 1.227355e+300

# 1-norm, 2-norm, 3-norm, 4-norm, and infinity-norm
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
# [1] 2.480000e+300 1.227355e+300 9.927854e+299 9.027789e+299 8.000000e+299

x <- matrix(c(1,-2,3,-4))
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
# [1] 10.000000  5.477226  4.641589  4.337613  4.000000

x <- matrix(c(1,-2,3,-4, 0, -8e+299, -6e+299, 5e+299, -8e+298, -5e+299), nc = 2)
sapply(c(1:4, Inf), function(k) knorm(x = x, k = k))
#           [,1]          [,2]          [,3]          [,4]   [,5]
# [1,]  1.00e+01  5.477226e+00  4.641589e+00  4.337613e+00  4e+00
# [2,] 2.48e+300 1.227355e+300 9.927854e+299 9.027789e+299 8e+299

答案 8 :(得分:0)

使用cbind将矩阵创建为列vise,然后norm函数与Frobenius范数(欧几里德范数)作为参数一起使用。

  

X1&LT; -cbind(1:3)

     

范数(X1,&#34; F&#34)

[1] 3.741657

  

SQRT(1 * 1 + 2 * 2 + 3 * 3)

[1] 3.741657

答案 9 :(得分:0)

按照AbdealiJK的回答,

我进一步尝试以获得一些见解。

这是一个。

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

第一个结果是Inf,第二个结果是1.227355e+300,这正如我在下面的代码中向您展示的那样。

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

结果是1227354879...。我没有计算尾随数字的数量,但看起来还不错。我知道另一种解决这个OVERFLOW问题的方法,首先将日志函数应用于所有数字并总结,我没有时间实现!