ここにベクトルを (リストか何かで) 示してから、計算を行って、それがどのように機能するかを見てもらえますか?
12 に答える
比較する2つの非常に短いテキストを次に示します。
Julie loves me more than Linda loves me
Jane likes me more than Julie loves me
純粋に単語数の点で(そして語順を無視して)、これらのテキストがどれほど類似しているかを知りたいのです。まず、両方のテキストから単語のリストを作成します。
me Julie loves Linda than more likes Jane
ここで、これらの各単語が各テキストに出現する回数を数えます。
me 2 2
Jane 0 1
Julie 1 1
Linda 1 0
likes 0 1
loves 2 1
more 1 1
than 1 1
しかし、私たちは言葉自体には興味がありません。カウントのこれら2つの垂直ベクトルにのみ関心があります。たとえば、各テキストには「me」の2つのインスタンスがあります。これらの2つのベクトルの1つの関数、つまりそれらの間の角度の正弦を計算することにより、これら2つのテキストが互いにどれだけ近いかを判断します。
ここでも、2つのベクトルは次のとおりです。
a: [2, 0, 1, 1, 0, 2, 1, 1]
b: [2, 1, 1, 0, 1, 1, 1, 1]
それらの間の角度の正弦は約0.822です。
これらのベクトルは8次元です。コサイン類似性を使用することの利点は、視覚化できる人間の能力を超えた質問を、視覚化できる質問に変換することです。この場合、これは約35度の角度と考えることができます。これは、ゼロまたは完全な一致からの「距離」です。
コサイン類似度が「どのように」計算されるか (計算に使用される特定の操作) ではなく、 「なぜ」コサイン類似度が機能するのか (なぜそれが類似性の良い指標を提供するのか)についての洞察を得ることに興味があると思います。後者に関心がある場合は、この投稿で Daniel が示したリファレンスと、関連する SO Questionを参照してください。
方法とさらには理由の両方を説明するには、まず問題を単純化し、2 次元でのみ作業することが役立ちます。これを 2D で取得すると、3 次元で考えるのが簡単になり、もちろんそれ以上の次元を想像するのは難しくなりますが、それまでに線形代数を使用して数値計算を行い、用語で考えるのにも役立ちます。これらを描くことはできませんが、n次元の線/ベクトル/「平面」/「球」の。
したがって、2 つの次元では、テキストの類似性に関しては、「ロンドン」と「パリ」という 2 つの異なる用語に注目し、これらの単語がそれぞれの単語で何回見つかったかを数えることを意味します。比較したい 2 つの文書。これにより、ドキュメントごとに xy 平面上のポイントが得られます。たとえば、Doc1 に Paris が 1 回、London が 4 回含まれている場合、(1,4) のポイントはこのドキュメントを示します (ドキュメントのこの小さな評価に関して)。または、ベクトルで言えば、この Doc1 ドキュメントは、原点から点 (1,4) に向かう矢印になります。このイメージを念頭に置いて、2 つのドキュメントが類似しているとはどういう意味で、これがベクトルにどのように関係するかを考えてみましょう。
非常によく似たドキュメント (再びこの限られた次元のセットに関して) は、パリへの参照の数とロンドンへの参照の数がまったく同じか、またはこれらの参照の比率が同じである可能性があります。パリへの 2 つの参照とロンドンへの 8 つの参照を持つドキュメント Doc2 も非常に似ていますが、テキストが長いか、都市名の繰り返しが多いだけですが、同じ割合です。おそらくどちらのドキュメントもロンドンについてのガイドであり、パリへの言及のみを行っています (そして、その都市がどれほどクールではないか ;-) 冗談です!!!.
現在、あまり類似していないドキュメントにも両方の都市への言及が含まれている可能性がありますが、比率は異なります。おそらく、Doc2 はパリを 1 回だけ引用し、ロンドンを 7 回だけ引用します。
xy 平面に戻ると、これらの架空の文書を描くと、それらが非常に類似している場合、それらのベクトルが重なり合い (一部のベクトルはより長くなる可能性があります)、共通点が少なくなり始めると、これらのベクトルは発散し始めることがわかります。それらの間のより広い角度を持つようにします。
ベクトル間の角度を測定することにより、それらの類似性についての良いアイデアを得ることができ、さらに簡単にするために、この角度のコサインを取ることで、この類似性は、何をどのように説明するかによって異なります。角度が小さいほどコサイン値が大きく (1 に近く) なり、類似度も高くなります。
極端に言えば、Doc1 がパリのみを引用し、Doc2 がロンドンのみを引用している場合、これらの文書にはまったく共通点がありません。Doc1 のベクトルは x 軸に、Doc2 は y 軸に、角度は 90 度、コサイン 0 になります。この場合、これらのドキュメントは互いに直交していると言えます。
次元の追加:
小さな角度 (または大きな余弦) として表現される類似性に対するこの直感的な感覚により、たとえば「アムステルダム」という単語を組み合わせて、3 次元で物事を想像できるようになり、2 つのドキュメントがどのように機能するかを非常によく視覚化できます。それぞれへの参照は、特定の方向に進むベクトルを持ち、この方向が、パリとロンドンをそれぞれ 3 回引用しているが、アムステルダムなどを引用していない文書とどのように比較されるかを見ることができます。 10 または 100 都市のスペース。描くのは難しいですが、概念化するのは簡単です。
式自体について少しだけ述べて、締めくくります。私が言ったように、他の参考文献は計算に関する良い情報を提供します。
まずは二次元。2 つのベクトル間の角度の余弦の式は、三角関数の差 (角度 a と角度 b の間) から導き出されます。
cos(a - b) = (cos(a) * cos(b)) + (sin (a) * sin(b))
この式は内積の式に非常によく似ています。
Vect1 . Vect2 = (x1 * x2) + (y1 * y2)
ここで、最初のベクトルなどの値と値に対応します。唯一の問題は、、cos(a)
などが正確にとの値ではないことです。これらの値は単位円で読み取る必要があるためです。ここで式の分母が機能します。これらのベクトルの長さの積で割ることにより、と座標が正規化されます。x
sin(a)
y
x
y
cos
sin
x
y
これが私のC#での実装です。
using System;
namespace CosineSimilarity
{
class Program
{
static void Main()
{
int[] vecA = {1, 2, 3, 4, 5};
int[] vecB = {6, 7, 7, 9, 10};
var cosSimilarity = CalculateCosineSimilarity(vecA, vecB);
Console.WriteLine(cosSimilarity);
Console.Read();
}
private static double CalculateCosineSimilarity(int[] vecA, int[] vecB)
{
var dotProduct = DotProduct(vecA, vecB);
var magnitudeOfA = Magnitude(vecA);
var magnitudeOfB = Magnitude(vecB);
return dotProduct/(magnitudeOfA*magnitudeOfB);
}
private static double DotProduct(int[] vecA, int[] vecB)
{
// I'm not validating inputs here for simplicity.
double dotProduct = 0;
for (var i = 0; i < vecA.Length; i++)
{
dotProduct += (vecA[i] * vecB[i]);
}
return dotProduct;
}
// Magnitude of the vector is the square root of the dot product of the vector with itself.
private static double Magnitude(int[] vector)
{
return Math.Sqrt(DotProduct(vector, vector));
}
}
}
簡単にするために、ベクトルaとbを減らしています。
Let :
a : [1, 1, 0]
b : [1, 0, 1]
次に、コサイン類似性(シータ):
(Theta) = (1*1 + 1*0 + 0*1)/sqrt((1^2 + 1^2))* sqrt((1^2 + 1^2)) = 1/2 = 0.5
その場合、cos0.5の逆数は60度です。
この Python コードは、アルゴリズムを実装するための私の迅速かつ汚い試みです。
import math
from collections import Counter
def build_vector(iterable1, iterable2):
counter1 = Counter(iterable1)
counter2 = Counter(iterable2)
all_items = set(counter1.keys()).union(set(counter2.keys()))
vector1 = [counter1[k] for k in all_items]
vector2 = [counter2[k] for k in all_items]
return vector1, vector2
def cosim(v1, v2):
dot_product = sum(n1 * n2 for n1, n2 in zip(v1, v2) )
magnitude1 = math.sqrt(sum(n ** 2 for n in v1))
magnitude2 = math.sqrt(sum(n ** 2 for n in v2))
return dot_product / (magnitude1 * magnitude2)
l1 = "Julie loves me more than Linda loves me".split()
l2 = "Jane likes me more than Julie loves me or".split()
v1, v2 = build_vector(l1, l2)
print(cosim(v1, v2))
@Bill Bell の例を使用して、[R] でこれを行う 2 つの方法
a = c(2,1,0,2,0,1,1,1)
b = c(2,1,1,1,1,0,1,1)
d = (a %*% b) / (sqrt(sum(a^2)) * sqrt(sum(b^2)))
または crossprod() メソッドのパフォーマンスを利用する...
e = crossprod(a, b) / (sqrt(crossprod(a, a)) * sqrt(crossprod(b, b)))
Python
これは、コサイン類似度を実装する単純なコードです。
from scipy import linalg, mat, dot
import numpy as np
In [12]: matrix = mat( [[2, 1, 0, 2, 0, 1, 1, 1],[2, 1, 1, 1, 1, 0, 1, 1]] )
In [13]: matrix
Out[13]:
matrix([[2, 1, 0, 2, 0, 1, 1, 1],
[2, 1, 1, 1, 1, 0, 1, 1]])
In [14]: dot(matrix[0],matrix[1].T)/np.linalg.norm(matrix[0])/np.linalg.norm(matrix[1])
Out[14]: matrix([[ 0.82158384]])
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
* @author Xiao Ma
* mail : 409791952@qq.com
*
*/
public class SimilarityUtil {
public static double consineTextSimilarity(String[] left, String[] right) {
Map<String, Integer> leftWordCountMap = new HashMap<String, Integer>();
Map<String, Integer> rightWordCountMap = new HashMap<String, Integer>();
Set<String> uniqueSet = new HashSet<String>();
Integer temp = null;
for (String leftWord : left) {
temp = leftWordCountMap.get(leftWord);
if (temp == null) {
leftWordCountMap.put(leftWord, 1);
uniqueSet.add(leftWord);
} else {
leftWordCountMap.put(leftWord, temp + 1);
}
}
for (String rightWord : right) {
temp = rightWordCountMap.get(rightWord);
if (temp == null) {
rightWordCountMap.put(rightWord, 1);
uniqueSet.add(rightWord);
} else {
rightWordCountMap.put(rightWord, temp + 1);
}
}
int[] leftVector = new int[uniqueSet.size()];
int[] rightVector = new int[uniqueSet.size()];
int index = 0;
Integer tempCount = 0;
for (String uniqueWord : uniqueSet) {
tempCount = leftWordCountMap.get(uniqueWord);
leftVector[index] = tempCount == null ? 0 : tempCount;
tempCount = rightWordCountMap.get(uniqueWord);
rightVector[index] = tempCount == null ? 0 : tempCount;
index++;
}
return consineVectorSimilarity(leftVector, rightVector);
}
/**
* The resulting similarity ranges from −1 meaning exactly opposite, to 1
* meaning exactly the same, with 0 usually indicating independence, and
* in-between values indicating intermediate similarity or dissimilarity.
*
* For text matching, the attribute vectors A and B are usually the term
* frequency vectors of the documents. The cosine similarity can be seen as
* a method of normalizing document length during comparison.
*
* In the case of information retrieval, the cosine similarity of two
* documents will range from 0 to 1, since the term frequencies (tf-idf
* weights) cannot be negative. The angle between two term frequency vectors
* cannot be greater than 90°.
*
* @param leftVector
* @param rightVector
* @return
*/
private static double consineVectorSimilarity(int[] leftVector,
int[] rightVector) {
if (leftVector.length != rightVector.length)
return 1;
double dotProduct = 0;
double leftNorm = 0;
double rightNorm = 0;
for (int i = 0; i < leftVector.length; i++) {
dotProduct += leftVector[i] * rightVector[i];
leftNorm += leftVector[i] * leftVector[i];
rightNorm += rightVector[i] * rightVector[i];
}
double result = dotProduct
/ (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
return result;
}
public static void main(String[] args) {
String left[] = { "Julie", "loves", "me", "more", "than", "Linda",
"loves", "me" };
String right[] = { "Jane", "likes", "me", "more", "than", "Julie",
"loves", "me" };
System.out.println(consineTextSimilarity(left,right));
}
}