web-dev-qa-db-ja.com

Rの2つのベクトル間の角度

2つのベクトル間の角度を計算するために、プログラミング言語 [〜#〜] r [〜#〜] で最も効率的な方法は何ですか?

29
Christian

このPDF の5ページによると、sum(a*b)は、ベクトルabsqrt(sum(a * a))は、ベクトルaのノルムを見つけるためのRコマンドであり、acos(x)は、逆余弦のRコマンドです。したがって、2つのベクトル間の角度を計算するRコードは次のようになります。

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

私の答えは2つの部分で構成されています。パート1は数学です-スレッドのすべてのリーダーを明確にし、続くRコードを理解可能にすることです。パート2はRプログラミングです。

パート1-数学

2つのベクトルxyの内積は、次のように定義できます。

enter image description here

ここで||x||ユークリッドノルム(Lとも呼ばれる)2 ベクトルのノルム)x

ドット積の定義を操作すると、以下を取得できます。

enter image description here

ここで、thetaはラジアンで表されたベクトルxyの間の角度です。 thetaは、0からpiまでの閉区間にある値を取ることができることに注意してください。

シータ自体を解くと、次のようになります。

enter image description here

パート2-Rコード

数学をRコードに変換するには、2つの行列(ベクトル)計算を実行する方法を知る必要があります。ドット積とユークリッドノルム(これはLとして知られる特定のタイプのノルムです)2 規範)。また、逆余弦関数cosのR等価を知る必要があります。-1

上から。 _?"%*%"_を参照すると、_%*%_演算子を使用して内積(内積とも呼ばれます)を計算できます。 _?norm_を参照すると、norm()関数(基本パッケージ)はベクトルのaノルムを返します。ここで重要なのはLです2 ノルム、またはRヘルプドキュメントの用語では、「スペクトル」または「2」ノルム。これは、norm()関数のtype引数を_"2"_と等しく設定する必要があることを意味します。最後に、Rの逆余弦関数はacos()関数で表されます。

ソリューション

数学と関連するR関数の両方を備えたプロトタイプ関数(つまり、プロダクション標準ではない)は、以下に示すように、ベースパッケージ関数を使用して組み合わせることができます。上記の情報が理にかなっている場合は、後続の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。シータは約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
_

これが役に立てば幸いです!

19
Graeme Walsh

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
12

ドット積を使用する必要があります。あなたが持っているとしましょう[〜#〜] v [〜#〜]₁=(x₁、y₁、z₁)および[〜#〜] v [〜#〜]₂=(x₂、y₂、z₂)の場合は、ドット積です[〜#〜] v [〜#〜]₁・[〜#〜] v [〜 #〜]₂、次のように計算されます

[〜#〜] v [〜#〜]₁・[〜#〜] v [〜#〜]₂= x₁・x₂+ y₁・y₂+ z₁・z₂= | [〜#〜] v [〜#〜]₁|・| [〜#〜] v [〜#〜]₂|・cos(θ);

これは、左側に示されている合計が、ベクトルの絶対値にベクトル間の角度の余弦を掛けた積に等しいことを意味しています。ベクトルの絶対値[〜#〜] v [〜#〜]₁および[〜#〜] v [〜#〜]₂は次のように計算されます

| [〜#〜] v [〜#〜]₁| =√(x₁²+ y₁²+ z₁²)、および
| [〜#〜] v [〜#〜]₂| =√(x₂²+ y₂²+ z₂²)、

したがって、上記の最初の方程式を並べ替えると、

cos(θ)=(x₁・x₂+ y₁・y =₂+ z₁・z₂)÷(| [〜#〜] v [〜#〜]₁|・|- [〜#〜] v [〜#〜]₂|)、

角度を取得するには、cos(θ)にarccos関数(または逆余弦)を適用するだけです。

Arccos関数に応じて、角度は度またはラジアンになります。

(2次元ベクトルの場合は、z-coordinatesを忘れて、同じ計算を行います。)

幸運を、

ジョン・ドナー

7
John R Doner

別の解決策:2つのベクトル間の相関は、2つのベクトル間の角度の余弦に等しい。

したがって、角度は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)))
5
Mohamed

必要なのはインナーです。 2つのベクトル_v,u_(_R^n_またはその他の内積空間)<v,u>/|v||u|= cos(alpha)の場合。 (alphaはベクトル間の角度でした)

詳細については、以下を参照してください。

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

1
Guy