简体   繁体   English

"R中两个向量之间的角度"

[英]Angle between two vectors in R

编程语言R<\/a>中计算两个向量之间角度的最有效方法是什么?

"

According to page 5 of this PDF , sum(a*b) is the R command to find the dot product of vectors a and b , and sqrt(sum(a * a)) is the R command to find the norm of vector a , and acos(x) is the R command for the arc-cosine.根据此 PDF 的第 5 页, sum(a*b)是用于查找向量ab的点积的 R 命令,而sqrt(sum(a * a))是用于查找向量a范数的 R 命令,而acos(x)是反余弦的 R 命令。 It follows that the R code to calculate the angle between the two vectors is因此,计算两个向量之间的角度的 R 代码是

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

My answer consists of two parts.我的回答由两部分组成。 Part 1 is the math - to give clarity to all readers of the thread and to make the R code that follows understandable.第 1 部分是数学 - 向线程的所有读者提供清晰的信息,并使后面的 R 代码易于理解。 Part 2 is the R programming.第 2 部分是 R 编程。

Part 1 - Math第 1 部分 - 数学

The dot product of two vectors x and y can be defined as:两个向量xy的点积可以定义为:

在此处输入图片说明

where ||哪里 || x || × || is the Euclidean norm (also known as the L 2 norm) of the vector x .是向量x的欧几里得范数(也称为 L 2范数)。

Manipulating the definition of the dot product, we can obtain:操纵点积的定义,我们可以得到:

在此处输入图片说明

where theta is the angle between the vectors x and y expressed in radians.其中 theta 是以弧度表示的向量xy之间的角度。 Note that theta can take on a value that lies on the closed interval from 0 to pi.请注意,theta 可以取位于从 0 到 pi 的闭区间上的值。

Solving for theta itself, we get:求解 theta 本身,我们得到:

在此处输入图片说明

Part 2 - R Code第 2 部分 - R 代码

To translate the mathematics into R code, we need to know how to perform two matrix (vector) calculations;要将数学转化为 R 代码,我们需要知道如何执行两个矩阵(向量)计算; dot product and Euclidean norm (which is a specific type of norm, known as the L 2 norm).点积和欧几里得范数(这是一种特定类型的范数,称为 L 2范数)。 We also need to know the R equivalent of the inverse cosine function, cos -1 .我们还需要知道反余弦函数 cos -1的 R 等价物。

Starting from the top.从顶部开始。 By reference to ?"%*%" , the dot product (also referred to as the inner product) can be calculated using the %*% operator.通过参考?"%*%" ,可以使用%*%运算符计算点积(也称为内积)。 With reference to ?norm , the norm() function (base package) returns a norm of a vector.参考?normnorm()函数(基础包)返回向量范数。 The norm of interest here is the L 2 norm or, in the parlance of the R help documentation, the "spectral" or "2"-norm.这里感兴趣的范数是 L 2范数,或者用 R 帮助文档的说法,“谱”或“2”范数。 This means that the type argument of the norm() function ought to be set equal to "2" .这意味着norm()函数的type参数应该设置为等于"2" Lastly, the inverse cosine function in R is represented by the acos() function.最后,R 中的反余弦函数由acos()函数表示。

Solution解决方案

Equipped with both the mathematics and the relevant R functions, a prototype function (that is, not production standard) can be put together - using Base package functions - as shown below.配备了数学和相关的 R 函数,原型函数(即非生产标准)可以放在一起 - 使用 Base 包函数 - 如下所示。 If the above information makes sense then the angle() function that follows should be clear without further comment.如果上述信息有意义,那么后面的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)
}

Test the function测试功能

A test to verify that the function works.用于验证该功能是否有效的测试。 Let x = (2,1) and y = (1,2).x = (2,1) 和y = (1,2)。 Dot product between x and y is 4. Euclidean norm of x is sqrt(5). xy之间的点积为4 x的欧几里得范数是SQRT(5)。 Euclidean norm of y is also sqrt(5). y 的欧几里德范数也是 sqrt(5)。 cos theta = 4/5. cos theta = 4/5。 Theta is approximately 0.643 radians. 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

I hope this helps!我希望这有帮助!

For 2D-vectors, the way given in the accepted answer and other ones does not take into account the orientation (the sign) of the angle ( angle(M,N) is the same as angle(N,M) ) and it returns a correct value only for an angle between 0 and pi .对于 2D 向量,在接受的答案中给出的方法和其他方法不考虑角度的方向(符号)( angle(M,N)angle(N,M) )并且它返回仅适用于0pi之间的角度的正确值。

Use the atan2 function to get an oriented angle and a correct value (modulo 2pi ).使用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]) 
}

Check that angle2 gives the correct value:检查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

You should use the dot product.您应该使用点积。 Say you have V ₁ = ( x ₁, y ₁, z ₁) and V ₂ = ( x ₂, y ₂, z ₂), then the dot product, which I'll denote by V ₁· V ₂, is calculated as假设您有V ₁ = ( x ₁, y ₁, z ₁) 和V ₂ = ( x ₂, y ₂, z ₂),则计算点积,我将用V ₁· V ₂ 表示作为

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

What this means is that that sum shown on the left is equal to the product of the absolute values of the vectors times the cosine of the angle between the vectors.这意味着左边显示的总和等于向量的绝对值乘以向量之间角度的余弦的乘积。 the absolute value of the vectors V ₁ and V ₂ are calculated as向量V ₁ 和V ₂ 的绝对值计算如下

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

So, if you rearrange the first equation above, you get所以,如果你重新排列上面的第一个等式,你会得到

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

and you just need the arccos function (or inverse cosine) applied to cos( θ ) to get the angle.并且您只需要将反余弦函数(或反余弦)应用于 cos( θ ) 即可获得角度。

Depending on your arccos function, the angle may be in degrees or radians.根据您的 arccos 函数,角度可能以度或弧度为单位。

(For two dimensional vectors, just forget the z -coordinates and do the same calculations.) (对于二维向量,只需忘记z坐标并进行相同的计算。)

Good luck,祝你好运,

John Doner约翰·多纳

Another solution : the correlation between the two vectors is equal to the cosine of the angle between two vectors.另一种解决方案:两个向量之间的相关性等于两个向量之间夹角的余弦。

so the angle can be computed by acos(cor(u,v))所以角度可以通过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)))

if you install/upload the library(matlib): there is a function called angle(x, y, degree = TRUE) where x and y are vectors.如果您安装/上传库(matlib):有一个名为 angle(x, y, degree = TRUE) 的函数,其中 x 和 y 是向量。 Note: if you have x and y in matrix form, use as.vector(x) and as.vector(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

I think what you need is an inner product.我认为你需要的是一个内积。 For two vectors v,u (in R^n or any other inner-product spaces) <v,u>/|v||u|= cos(alpha) .对于两个向量v,u (在R^n或任何其他内积空间中) <v,u>/|v||u|= cos(alpha) (were alpha is the angle between the vectors) alpha是向量之间的角度)

for more details see:有关更多详细信息,请参阅:

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

If you want to calculate the angle among multiple variables, you can use the following function, which is an extension of the solution provided by @Graeme Walsh.如果要计算多个变量之间的角度,可以使用以下函数,它是@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)
}

In addition, if you mean-centered your input variables and get the cosine values of the result matrix provided above, you will get the exact correlation matrix of the variables.此外,如果您对输入变量进行均值中心化并获得上面提供的结果矩阵的余弦值,您将获得变量的精确相关矩阵。

Here is an application of the function.下面是该函数的一个应用。

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

The traditional approach to obtaining an angle between two vectors (ie acos(sum(a*b) \/ (sqrt(sum(a*a)) * sqrt(sum(b*b))))<\/code> , as presented in some of the other answers) suffers from numerical instability in several corner cases.获得两个向量之间角度的传统方法(即acos(sum(a*b) \/ (sqrt(sum(a*a)) * sqrt(sum(b*b))))<\/code> ,如某些其他答案)在几个极端情况下存在数值不稳定性。 The following code works for n<\/em> -dimensions and in all corner cases (it doesn't check for zero length vectors, but that's easy to add).以下代码适用于n<\/em>维和所有极端情况(它不检查零长度向量,但这很容易添加)。 See notes below.请参阅下面的注释。

# 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