我尝试了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中计算向量范数的函数是什么?
答案 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
注意:
在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()
的唯一问题是,它无法防范所暗示的here和here的上溢或下溢问题。
幸运的是,有人已经在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
中R
的上述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
问题的方法,首先将日志函数应用于所有数字并总结,我没有时间实现!