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

后端 未结 10 1199
灰色年华
灰色年华 2021-02-01 13:22

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

10条回答
  •  渐次进展
    2021-02-01 14:08

    Answer for Euclidean length of a vector (k-norm) with scaling to avoid destructive underflow and overflow is

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

    See below for explanation.

    1. Euclidean length of a vector with no scaling:


    norm() is a vector-valued function which computes the length of the vector. It takes two arguments such as the vector x of class matrix and the type of norm k of class 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-norm (10.0) converges to infinity-norm (4.0).
    • k-norm is also called as "Euclidean norm in Euclidean n-dimensional space".

    Note: In the norm() function definition, for vectors with real components, the absolute values can be dropped in norm-2k or even indexed norms, where k >= 1.

    If you are confused with the norm function definition, you can read each one individually as given below.

    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. Euclidean length of a vector with scaling to avoid destructive overflow and underflow issues:


    Note-2: The only problem with this solution norm() is that it does not guard against overflow or underflow problems as alluded here and here.

    Fortunately, someone had already solved this problem for 2-norm (euclidean length) in the blas (basic linear algebra subroutines) fortran library. A description of this problem can be found in the textbook of "Numerical Methods and Software by Kahaner, Moler and Nash" - Chapter-1, Section 1.3, page - 7-9.

    The name of the fortran subroutine is dnrm2.f, which handles destructive overflow and underflow issues in the norm() by scaling with the maximum of the vector components. The destructive overflow and underflow problem arise due to radical operation in the norm() function.

    I will show how to implement dnrm2.f in R below.

    #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
    

    one-liner of the above 6-steps of dnrm2.f in R is:

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

    Lets try example vectors to compute 2-norm (see other solutions in this thread) for this problem.

    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
    

    Therefore, the recommended way to implement a generalized solution for k-norm in R is that single line, which guard against the destructive overflow or underflow problems. To improve this one-liner, you can use a combination of norm() without scaling for a vector containing not-too-small or not-too-large components and knorm() with scaling for a vector with too-small or too-large components. Implementing scaling for all vectors results in too many calculations. I did not implement this improvement in knorm() given below.

    # 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
    

提交回复
热议问题