46

我试过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 中计算向量范数的函数是什么?

4

10 回答 10

75
norm(c(1,1), type="2")     # 1.414214
norm(c(1, 1, 1), type="2")  # 1.732051
于 2014-12-10T16:16:18.320 回答
57

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

norm_vec <- function(x) sqrt(sum(x^2))
于 2012-06-07T14:43:27.350 回答
25

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

> 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 

似乎norm至少手动获取电源然后 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)
    ...

编辑(2019 年 10 月 20 日):

有一些评论指出了上述测试用例没有带来的正确性问题:

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

发生这种情况是因为大数在 R 中被视为无穷大:

> 10^309
[1] Inf

所以,它看起来像:

似乎手动获取电源然后 sqrt 比用于小数字的实值向量的内置规范更快。

多么小?这样平方和就不会溢出。

于 2016-09-06T04:27:37.273 回答
15
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.

于 2014-06-12T19:12:17.423 回答
4

我们还可以找到范数:

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

或者甚至您也可以尝试:

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

两者都会给出相同的答案

于 2013-02-15T09:32:38.700 回答
3

我也要把它作为等效的 R 表达式扔出去

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

不要将 R 的 crossprod 与类似命名的 vector/ cross product混淆。众所周知,这种命名会引起混淆,尤其是对于那些具有物理/力学背景的人。

于 2014-12-12T22:31:43.073 回答
2

带有缩放以避免破坏性下溢和溢出的向量的欧几里得长度(k-范数)的答案是

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

请参阅下面的说明。

1. 没有缩放的向量的欧几里得长度:


norm()是一个向量值函数,它计算向量的长度。它需要两个参数,例如 class 的向量x和 classmatrix的范数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-norm 也称为“欧几里得 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()是它不能防止这里这里提到的溢出或下溢问题。

幸运的是,有人已经在 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.f上述6个步骤的单行R是:

# 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
于 2020-09-06T11:49:36.023 回答
2

如果您有一个 data.frame 或一个 data.table 'DT',并且想要计算每一行的欧几里得范数(范数 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
于 2016-08-16T04:58:12.857 回答
1

按照 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问题的另一种方法是首先将日志函数应用于所有数字并总结,我没有时间实现!

于 2018-06-14T21:15:14.937 回答
0

使用 cbind 将矩阵创建为立柱虎钳,然后 norm 函数与 Frobenius norm(欧几里得范数)作为参数很好地配合使用。

x1<-cbind(1:3)

范数(x1,“f”)

[1] 3.741657

平方(1*1+2*​​2+3*3)

[1] 3.741657

于 2014-11-18T20:22:45.930 回答