破壊的なアンダーフローとオーバーフローを回避するためのスケーリングを使用したベクトルのユークリッド長(k-norm)に対する回答は次のとおりです。
norm <- function(x, k) { max(abs(x))*(sum((abs(x)/max(abs(x)))^k))^(1/k) }
説明については、以下を参照してください。
1.スケーリングなしのベクトルのユークリッド距離:
norm()
ベクトルの長さを計算するベクトル値関数です。x
クラスのベクトルとクラスmatrix
のノルムk
のタイプなど、2つの引数を取ります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()
ほのめかされているように、オーバーフローまたはアンダーフローの問題を防ぐことができないことです。
幸いなことに、誰かがすでにこの問題を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ステップのinのワンライナーは次のとおり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の一般化されたソリューションを実装するための推奨される方法は、破壊的なオーバーフローまたはアンダーフローの問題を防ぐ単一のラインです。このワンライナーを改善するため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