簡體   English   中英

"R中兩個向量之間的角度"

[英]Angle between two vectors in R

編程語言R<\/a>中計算兩個向量之間角度的最有效方法是什么?

"

根據此 PDF 的第 5 頁, sum(a*b)是用於查找向量ab的點積的 R 命令,而sqrt(sum(a * a))是用於查找向量a范數的 R 命令,而acos(x)是反余弦的 R 命令。 因此,計算兩個向量之間的角度的 R 代碼是

theta <- acos( sum(a*b) / ( sqrt(sum(a * a)) * sqrt(sum(b * b)) ) )

我的回答由兩部分組成。 第 1 部分是數學 - 向線程的所有讀者提供清晰的信息,並使后面的 R 代碼易於理解。 第 2 部分是 R 編程。

第 1 部分 - 數學

兩個向量xy的點積可以定義為:

在此處輸入圖片說明

哪里 || × || 是向量x的歐幾里得范數(也稱為 L 2范數)。

操縱點積的定義,我們可以得到:

在此處輸入圖片說明

其中 theta 是以弧度表示的向量xy之間的角度。 請注意,theta 可以取位於從 0 到 pi 的閉區間上的值。

求解 theta 本身,我們得到:

在此處輸入圖片說明

第 2 部分 - R 代碼

要將數學轉化為 R 代碼,我們需要知道如何執行兩個矩陣(向量)計算; 點積和歐幾里得范數(這是一種特定類型的范數,稱為 L 2范數)。 我們還需要知道反余弦函數 cos -1的 R 等價物。

從頂部開始。 通過參考?"%*%" ,可以使用%*%運算符計算點積(也稱為內積)。 參考?normnorm()函數(基礎包)返回向量范數。 這里感興趣的范數是 L 2范數,或者用 R 幫助文檔的說法,“譜”或“2”范數。 這意味着norm()函數的type參數應該設置為等於"2" 最后,R 中的反余弦函數由acos()函數表示。

解決方案

配備了數學和相關的 R 函數,原型函數(即非生產標准)可以放在一起 - 使用 Base 包函數 - 如下所示。 如果上述信息有意義,那么后面的angle()函數應該很清楚,無需進一步評論。

angle <- function(x,y){
  dot.prod <- x%*%y 
  norm.x <- norm(x,type="2")
  norm.y <- norm(y,type="2")
  theta <- acos(dot.prod / (norm.x * norm.y))
  as.numeric(theta)
}

測試功能

用於驗證該功能是否有效的測試。 x = (2,1) 和y = (1,2)。 xy之間的點積為4 x的歐幾里得范數是SQRT(5)。 y 的歐幾里德范數也是 sqrt(5)。 cos theta = 4/5。 Theta 約為 0.643 弧度。

x <- as.matrix(c(2,1))
y <- as.matrix(c(1,2))
angle(t(x),y)          # Use of transpose to make vectors (matrices) conformable.
[1] 0.6435011

我希望這有幫助!

對於 2D 向量,在接受的答案中給出的方法和其他方法不考慮角度的方向(符號)( angle(M,N)angle(N,M) )並且它返回僅適用於0pi之間的角度的正確值。

使用atan2函數獲取定向角度和正確值(模2pi )。

angle <- function(M,N){
  acos( sum(M*N) / ( sqrt(sum(M*M)) * sqrt(sum(N*N)) ) )
}
angle2 <- function(M,N){
  atan2(N[2],N[1]) - atan2(M[2],M[1]) 
}

檢查angle2給出了正確的值:

> theta <- seq(-2*pi, 2*pi, length.out=10)
> O <- c(1,0)
> test1 <- sapply(theta, function(theta) angle(M=O, N=c(cos(theta),sin(theta))))
> all.equal(test1 %% (2*pi), theta %% (2*pi))
[1] "Mean relative difference: 1"
> test2 <- sapply(theta, function(theta) angle2(M=O, N=c(cos(theta),sin(theta))))
> all.equal(test2 %% (2*pi), theta %% (2*pi))
[1] TRUE

您應該使用點積。 假設您有V ₁ = ( x ₁, y ₁, z ₁) 和V ₂ = ( x ₂, y ₂, z ₂),則計算點積,我將用V ₁· V ₂ 表示作為

V ₁· V ₂ = x ₁· x ₂ + y ₁· y ₂ + z ₁· z ₂ = | V₁| · | V 2| · cos( θ );

這意味着左邊顯示的總和等於向量的絕對值乘以向量之間角度的余弦的乘積。 向量V ₁ 和V ₂ 的絕對值計算如下

| V₁| = √( x ₁² + y ₁² + z ₁²),和
| V 2| = √( x 2² + y 2² + z 2²),

所以,如果你重新排列上面的第一個等式,你會得到

cos( θ ) = ( x ₁· x 2 + y ₁· y 2 + z ₁· z 2) ÷ (| V ₁|·| V 2|),

並且您只需要將反余弦函數(或反余弦)應用於 cos( θ ) 即可獲得角度。

根據您的 arccos 函數,角度可能以度或弧度為單位。

(對於二維向量,只需忘記z坐標並進行相同的計算。)

祝你好運,

約翰·多納

另一種解決方案:兩個向量之間的相關性等於兩個向量之間夾角的余弦。

所以角度可以通過acos(cor(u,v))

# example u(1,2,0) ; v(0,2,1)

cor(c(1,2),c(2,1))
theta = acos(cor(c(1,2),c(2,1)))

如果您安裝/上傳庫(matlib):有一個名為 angle(x, y, degree = TRUE) 的函數,其中 x 和 y 是向量。 注意:如果您有矩陣形式的 x 和 y,請使用 as.vector(x) 和 as.vector(y):

library(matlib)
matA <- matrix(c(3, 1), nrow = 2)  ##column vectors
matB <- matrix(c(5, 5), nrow = 2)
angle(as.vector(matA), as.vector(matB))  
##default in degrees, use degree = FALSE for radians

我認為你需要的是一個內積。 對於兩個向量v,u (在R^n或任何其他內積空間中) <v,u>/|v||u|= cos(alpha) alpha是向量之間的角度)

有關更多詳細信息,請參閱:

http://en.wikipedia.org/wiki/Inner_product_space

如果要計算多個變量之間的角度,可以使用以下函數,它是@Graeme Walsh 提供的解決方案的擴展。

angles <- function(matrix){

  ## Calculate the cross-product of the matrix
  cross.product <- t(matrix)%*%matrix

  ## the lower and the upper triangle of the cross-product is the dot products among vectors 
  dot.products<- cross.product[lower.tri(cross.product)]

  ## Calculate the L2 norms
  temp <- suppressWarnings(diag(sqrt(cross.product)))
  temp <- temp%*%t(temp)
  L2.norms <- temp[lower.tri(temp)]

  ## Arccosine values for each pair of variables
  lower.t <- acos(dot.products/L2.norms)

  ## Create an empty matrix to present the results
  result.matrix <- matrix(NA,ncol = dim(matrix)[2],nrow=dim(matrix)[2])

  ## Fill the matrix with arccosine values and assign the diagonal values as zero “0”
  result.matrix[lower.tri(result.matrix)] <- lower.t
  diag(result.matrix) <- 0
  result.matrix[upper.tri(result.matrix)] <- t(result.matrix)[upper.tri(t(result.matrix))]

  ## Get the result matrix
  return(result.matrix)
}

此外,如果您對輸入變量進行均值中心化並獲得上面提供的結果矩陣的余弦值,您將獲得變量的精確相關矩陣。

下面是該函數的一個應用。

set.seed(123)
n <- 100
m <- 5

# Generate a set of random variables 

mt <- matrix(rnorm(n*m),nrow = n,ncol = m)

# Mean-centered matrix
mt.c <- scale(mt,scale = F)

# Cosine angles 
cosine.angles <- angles(matrix = mt)

> cosine.angles
         [,1]     [,2]     [,3]     [,4]     [,5]
[1,] 0.000000 1.630819 1.686037 1.618119 1.751859
[2,] 1.630819 0.000000 1.554695 1.523353 1.712214
[3,] 1.686037 1.554695 0.000000 1.619723 1.581786
[4,] 1.618119 1.523353 1.619723 0.000000 1.593681
[5,] 1.751859 1.712214 1.581786 1.593681 0.000000



# Centered-data cosine angles 
centered.cosine.angles <- angles(matrix = mt.c)

> centered.cosine.angles
         [,1]     [,2]     [,3]     [,4]     [,5]
[1,] 0.000000 1.620349 1.700334 1.614890 1.764721
[2,] 1.620349 0.000000 1.540213 1.526950 1.701793
[3,] 1.700334 1.540213 0.000000 1.615677 1.595647
[4,] 1.614890 1.526950 1.615677 0.000000 1.590057
[5,] 1.764721 1.701793 1.595647 1.590057 0.000000

# This will give you correlation matrix 
cos(angles(matrix = mt.c))

            [,1]        [,2]        [,3]        [,4]        [,5]
[1,]  1.00000000 -0.04953215 -0.12917601 -0.04407900 -0.19271110
[2,] -0.04953215  1.00000000  0.03057903  0.04383271 -0.13062219
[3,] -0.12917601  0.03057903  1.00000000 -0.04486571 -0.02484838
[4,] -0.04407900  0.04383271 -0.04486571  1.00000000 -0.01925986
[5,] -0.19271110 -0.13062219 -0.02484838 -0.01925986  1.00000000

# Orginal correlation matrix
cor(mt)

            [,1]        [,2]        [,3]        [,4]        [,5]
[1,]  1.00000000 -0.04953215 -0.12917601 -0.04407900 -0.19271110
[2,] -0.04953215  1.00000000  0.03057903  0.04383271 -0.13062219
[3,] -0.12917601  0.03057903  1.00000000 -0.04486571 -0.02484838
[4,] -0.04407900  0.04383271 -0.04486571  1.00000000 -0.01925986
[5,] -0.19271110 -0.13062219 -0.02484838 -0.01925986  1.00000000

# Check whether they are equal
all.equal(cos(angles(matrix = mt.c)),cor(mt))
[1] TRUE

獲得兩個向量之間角度的傳統方法(即acos(sum(a*b) \/ (sqrt(sum(a*a)) * sqrt(sum(b*b))))<\/code> ,如某些其他答案)在幾個極端情況下存在數值不穩定性。 以下代碼適用於n<\/em>維和所有極端情況(它不檢查零長度向量,但這很容易添加)。 請參閱下面的注釋。

# Get angle between two n-dimensional vectors
angle_btw <- function(v1, v2) {

  signbit <- function(x) {
    x < 0
  }

  u1 <- v1 / norm(v1, "2")
  u2 <- v2 / norm(v2, "2")

  y <- u1 - u2
  x <- u1 + u2

  a0 <- 2 * atan(norm(y, "2") / norm(x, "2"))

  if (!(signbit(a0) || signbit(pi - a0))) {
    a <- a0
  } else if (signbit(a0)) {
    a <- 0.0
  } else {
    a <- pi
  }

  a
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM