Может ли кто-нибудь привести пример сходства косинусов очень простым графическим способом? - PullRequest
182 голосов
/ 17 ноября 2009

Статья о сходстве косинусов в Википедии

Можете ли вы показать векторы здесь (в списке или что-то) а затем посчитаем, и посмотрим, как это работает?

Я новичок.

Ответы [ 10 ]

424 голосов
/ 17 ноября 2009

Вот два очень коротких текста для сравнения:

  1. Julie loves me more than Linda loves me

  2. 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

Нам не интересны сами слова. Мы заинтересованы только в эти два вертикальных вектора отсчетов. Например, есть два случая «Я» в каждом тексте. Мы собираемся решить, насколько близки эти два текста к каждому другой путем вычисления одной функции из этих двух векторов, а именно косинуса угол между ними.

Два вектора снова:

a: [2, 0, 1, 1, 0, 2, 1, 1]

b: [2, 1, 1, 0, 1, 1, 1, 1]

Косинус угла между ними составляет около 0,822.

Эти векторы 8-мерные. Преимущество использования косинусного сходства явно что он превращает вопрос, который находится за пределами человеческой способности визуализировать в один это может быть. В этом случае вы можете думать об этом как угол около 35 градусов, что является некоторым «расстоянием» от нуля или идеального соглашения.

110 голосов
/ 17 ноября 2009

Полагаю, вас больше интересует понимание ", почему ", косинусное сходство работает (почему оно дает хороший признак сходства), а не ", как"рассчитывается (конкретные операции, используемые для расчета). Если вас интересует последнее, см. Ссылку, указанную Даниэлем в этом посте, а также соответствующий вопрос SO .

Чтобы объяснить как и даже более того, почему, полезно, во-первых, упростить проблему и работать только в двух измерениях. Как только вы получите это в 2D, вам будет легче думать об этом в трех измерениях, и, конечно, сложнее представить это во многих других измерениях, но к тому времени мы сможем использовать линейную алгебру для выполнения численных расчетов, а также, чтобы помочь нам мыслить в терминах линий / векторов / "плоскостей" / "сфер" в n измерениях, хотя мы не можем их нарисовать.

Итак, в двух измерениях : в отношении сходства текста это означает, что мы сосредоточимся на двух разных терминах, скажем слова «Лондон» и «Париж», и посчитаем, сколько раз каждое из этих слов встречается в каждом из двух документов, которые мы хотим сравнить. Это дает нам для каждого документа точку в плоскости x-y. Например, если у Doc1 был Париж один раз, а Лондон - четыре, точка (1,4) представила бы этот документ (в отношении этой крошечной оценки документов). Или, говоря с точки зрения векторов, этот документ Doc1 будет стрелкой, идущей от начала координат к точке (1,4). Имея это в виду, давайте подумаем о том, что означает, что два документа должны быть похожими, и как это относится к векторам.

ОЧЕНЬ похожие документы (опять же, в отношении этого ограниченного набора измерений) будут иметь такое же количество ссылок на Париж, И то же самое число ссылок на Лондон, или, может быть, они могут иметь такое же соотношение этих ссылок , Документ, Doc2, с 2 ссылками на Париж и 8 ссылками на Лондон, также будет очень похож, только с, возможно, более длинным текстом или как-то более повторяющимся из названий городов, но в той же пропорции. Может быть, оба документа являются путеводителями по Лондону, в которых содержатся лишь мимолетные ссылки на Париж (и как не круто этот город ;-) Просто шучу !!!.

Теперь менее похожие документы могут также включать ссылки на оба города, но в разных пропорциях. Может быть, Doc2 только один раз процитирует Париж, а Лондон - семь.

Возвращаясь к нашей плоскости xy, , если мы рисуем эти гипотетические документы, мы видим, что, когда они ОЧЕНЬ похожи, их векторы перекрываются (хотя некоторые векторы могут быть длиннее), и когда они начинают иметь меньше в общем, эти векторы начинают расходиться, чтобы иметь более широкий угол между ними.

Измеряя угол между векторами, мы можем получить хорошее представление об их сходстве и, чтобы сделать вещи еще проще, взяв Cosine этого угла, мы получим хорошее значение от 0 до 1 или от -1 до 1, которое указывает на это сходство, в зависимости от того, что и как мы учитываем. Чем меньше угол, тем больше (ближе к 1) значение косинуса, а также выше сходство.

В крайнем случае, если в Doc1 упоминается только Париж, а в Doc2 - только Лондон, документы не имеют абсолютно ничего общего. Doc1 будет иметь свой вектор на оси x, Doc2 на оси y, угол 90 градусов, косинус 0. В этом случае мы бы сказали, что эти документы ортогональны друг другу.

Добавление размеров :
Благодаря этому интуитивному ощущению сходства, выраженному в виде небольшого угла (или большого косинуса), мы можем теперь представить вещи в 3-х измерениях, скажем, введя слово «Амстердам» в микс, и довольно хорошо представить, как документ с двумя ссылками на каждый будет иметь вектор, движущийся в определенном направлении, и мы можем увидеть, как это направление будет сравниваться с документом, в котором каждый раз упоминаются Париж и Лондон, но не Амстердам и т. д. Как уже говорилось, мы можем попытаться представить себе это причудливое пространство для 10 или 100 городов. Сложно рисовать, но легко осмыслить.

В заключение я скажу несколько слов о самой формуле . Как я уже сказал, другие ссылки дают хорошую информацию о расчетах.

Первый в двух измерениях. Формула для косинуса угла между двумя векторами получается из тригонометрической разности (между углом 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 нормализуются.

22 голосов
/ 17 ноября 2009

Вот моя реализация в 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));
        }
    }
}
19 голосов
/ 26 декабря 2012

Для простоты я сокращаю вектор 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

тогда обратное значение cos 0.5 равно 60 градусам.

14 голосов
/ 19 февраля 2013

Этот код 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))
7 голосов
/ 03 октября 2013

Используя пример @Bill Bell, два способа сделать это в [R]

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)))
4 голосов
/ 03 марта 2014

Это простой 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]])
3 голосов
/ 29 июля 2013
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));
}
}
2 голосов
/ 21 октября 2016

Простой код JAVA для расчета косинусного сходства

/**
   * Method to calculate cosine similarity of vectors
   * 1 - exactly similar (angle between them is 0)
   * 0 - orthogonal vectors (angle between them is 90)
   * @param vector1 - vector in the form [a1, a2, a3, ..... an]
   * @param vector2 - vector in the form [b1, b2, b3, ..... bn]
   * @return - the cosine similarity of vectors (ranges from 0 to 1)
   */
  private double cosineSimilarity(List<Double> vector1, List<Double> vector2) {

    double dotProduct = 0.0;
    double normA = 0.0;
    double normB = 0.0;
    for (int i = 0; i < vector1.size(); i++) {
      dotProduct += vector1.get(i) * vector2.get(i);
      normA += Math.pow(vector1.get(i), 2);
      normB += Math.pow(vector2.get(i), 2);
    }
    return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
  }
0 голосов
/ 22 сентября 2018

Два вектора A и B существуют в 2D-пространстве или 3D-пространстве, угол между этими векторами равен cos подобию.

Если угол больше (может достигать макс. 180 градусов), то есть Cos 180 = -1, а минимальный угол равен 0 градусов. cos 0 = 1 подразумевает, что векторы выровнены друг с другом и, следовательно, векторы похожи.

cos 90 = 0 (этого достаточно, чтобы сделать вывод, что векторы A и B совсем не похожи, и, поскольку расстояние не может быть отрицательным, значения косинуса будут лежать от 0 до 1. Следовательно, больший угол подразумевает уменьшение сходства визуализация также имеет смысл)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...