[英]Angle between two vectors in R
根據此 PDF 的第 5 頁, sum(a*b)
是用於查找向量a
和b
的點積的 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 編程。
兩個向量x和y的點積可以定義為:
哪里 || × || 是向量x的歐幾里得范數(也稱為 L 2范數)。
操縱點積的定義,我們可以得到:
其中 theta 是以弧度表示的向量x和y之間的角度。 請注意,theta 可以取位於從 0 到 pi 的閉區間上的值。
求解 theta 本身,我們得到:
要將數學轉化為 R 代碼,我們需要知道如何執行兩個矩陣(向量)計算; 點積和歐幾里得范數(這是一種特定類型的范數,稱為 L 2范數)。 我們還需要知道反余弦函數 cos -1的 R 等價物。
從頂部開始。 通過參考?"%*%"
,可以使用%*%
運算符計算點積(也稱為內積)。 參考?norm
, norm()
函數(基礎包)返回向量的范數。 這里感興趣的范數是 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)。 x和y之間的點積為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)
)並且它返回僅適用於0
和pi
之間的角度的正確值。
使用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
是向量之間的角度)
有關更多詳細信息,請參閱:
如果要計算多個變量之間的角度,可以使用以下函數,它是@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.