web-dev-qa-db-ja.com

2つのベクトルのコサイン類似度を計算するにはどうすればよいですか?

ベクトル間のコサイン類似性を見つけるにはどうすればよいですか?

2行のテキスト間の関連性を測定するには、類似性を見つける必要があります。

たとえば、次のような2つの文があります。

ユーザーインターフェースシステム

ユーザーインターフェースマシン

…およびtF-idfの後のそれぞれのベクトル、続いて[1,0.5]および[0.5,1]などのLSIを使用した正規化。

これらのベクトル間のスミア性を測定するにはどうすればよいですか?

31
shiva
public class CosineSimilarity extends AbstractSimilarity {

  @Override
  protected double computeSimilarity(Matrix sourceDoc, Matrix targetDoc) {
    double dotProduct = sourceDoc.arrayTimes(targetDoc).norm1();
    double eucledianDist = sourceDoc.normF() * targetDoc.normF();
    return dotProduct / eucledianDist;
  }
}

私は最近、大学の情報検索ユニットでtf-idfをいくつかやりました。 Jama:Java Matrix Package を使用するこのコサイン類似性メソッドを使用しました。

完全なソースコードについては、 IR Math with Java:Similarity Measures を参照してください。これは、いくつかの異なる類似性測定をカバーする非常に優れたリソースです。

20
Mark Davidson

このような単純なタスクのためにサードパーティのライブラリに依存することを避けたい場合、単純なJava実装:

public static double cosineSimilarity(double[] vectorA, double[] vectorB) {
    double dotProduct = 0.0;
    double normA = 0.0;
    double normB = 0.0;
    for (int i = 0; i < vectorA.length; i++) {
        dotProduct += vectorA[i] * vectorB[i];
        normA += Math.pow(vectorA[i], 2);
        normB += Math.pow(vectorB[i], 2);
    }   
    return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}

この関数は、2つのベクトルの長さが同じであると想定していることに注意してください。安全のために明示的に確認することをお勧めします。

50
Alphaaa

http://en.wikipedia.org/wiki/Cosine_similarity をご覧ください。

ベクトルAとBがある場合.

類似性は次のように定義されます。

cosine(theta) = A . B / ||A|| ||B||

For a vector A = (a1, a2), ||A|| is defined as sqrt(a1^2 + a2^2)

For vector A = (a1, a2) and B = (b1, b2), A . B is defined as a1 b1 + a2 b2;

So for vector A = (a1, a2) and B = (b1, b2), the cosine similarity is given as:

  (a1 b1 + a2 b2) / sqrt(a1^2 + a2^2) sqrt(b1^2 + b2^2)

例:

A = (1, 0.5), B = (0.5, 1)

cosine(theta) = (0.5 + 0.5) / sqrt(5/4) sqrt(5/4) = 4/5
32
Toon Krijthe

Javaのマトリックスコードの場合、 Colt ライブラリを使用することをお勧めします。

_DoubleMatrix1D a = new DenseDoubleMatrix1D(new double[]{1,0.5}});
DoubleMatrix1D b = new DenseDoubleMatrix1D(new double[]{0.5,1}});
double cosineDistance = a.zDotProduct(b)/Math.sqrt(a.zDotProduct(a)*b.zDotProduct(b))
_

上記のコードは、ノルムの計算にBlas.dnrm2()メソッドまたはAlgebra.DEFAULT.norm2()のいずれかを使用するように変更することもできます。まったく同じ結果がより読みやすく、味に依存します。

5
Nick Fortescue

しばらく前にテキストマイニングを使用していたとき、Javaで広範囲のさまざまなメトリックを提供する SimMetrics ライブラリを使用していました。さらに必要な場合は、常に R and CRAN が必要です。

しかし、Wikipediaの説明からコーディングするのは簡単な作業であり、いい練習になる可能性があります。

2
Anonymous
def cosineSimilarity(vectorA: Vector[Double], vectorB: Vector[Double]):Double={
    var dotProduct = 0.0
    var normA = 0.0
    var normB = 0.0
    var i = 0

    for(i <- vectorA.indices){
        dotProduct += vectorA(i) * vectorB(i)
        normA += Math.pow(vectorA(i), 2)
        normB += Math.pow(vectorB(i), 2)
    }

    dotProduct / (Math.sqrt(normA) * Math.sqrt(normB))
}

def main(args: Array[String]): Unit = {
    val vectorA = Array(1.0,2.0,3.0).toVector
    val vectorB = Array(4.0,5.0,6.0).toVector
    println(cosineSimilarity(vectorA, vectorA))
    println(cosineSimilarity(vectorA, vectorB))
}

スカラ版

0
裴帅帅

Map(dimension -> magnitude)を使用したベクトルのスパース表現については、scala=バージョン(Java 8)で同様のことができます)

def cosineSim(vec1:Map[Int,Int],
              vec2:Map[Int,Int]): Double ={
  val dotProduct:Double = vec1.keySet.intersect(vec2.keySet).toList
    .map(dim => vec1(dim) * vec2(dim)).sum
  val norm1:Double = vec1.values.map(mag => mag * mag).sum
  val norm2:Double = vec2.values.map(mag => mag * mag).sum
  return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2))
}
0
Thamme Gowda