Чи може хтось навести приклад подібності косинусів у дуже простому, графічному вигляді?


201

Стаття про подібність косину у Вікіпедії

Чи можете ви показати тут вектори (у списку чи щось таке), а потім зробити математику, і давайте подивимось, як це працює?

Я початківець.


1
Спробуйте підібрати копію геометрії та значення від Widdows ( press.uchicago.edu/presssite/… ), я прочитав її через деякий час назад і побажав, щоб я мав її кілька років тому, чудовий вступний текст.
Натан Хоуелл

Відповіді:


463

Ось два дуже короткі тексти для порівняння:

  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 градусів, який є деякою "відстані" від нуля або ідеальною згодою.


12
Це саме те, що я шукав. Саме так. Чи вважається це найпростішою формою "векторної космічної моделі"?
TIMEX

2
Я дуже радий, що вам це було корисно, Алекс. Вибачте за затримку у відповіді. Я не відвідував StackOverflow деякий час. Насправді це приклад "внутрішнього простору продукту". Існує основна дискусія у Вікіпедії.
Білл Белл

1
Чи є можливість нормалізувати довжину документа?
sinθ

1
Ви повинні використовувати нормалізацію довжини, а перед цим спробувати використовувати зважування частоти журналу на всіх термінах векторах. Якщо ви вже маєте справу з нормалізованими векторами, то це точковий добуток AB
Алі Гаджані

4
Більш детальний приклад із використанням нормалізації довжини та TF-IDF: site.uottawa.ca/~diana/csi4107/cosine_tf_idf_example.pdf
Майк Б.

121

Я здогадуюсь, що вам більше цікаво зрозуміти " чому " працює подібність косинусу (чому це дає хорошу вказівку на схожість), а не " як " воно обчислюється (конкретні операції, що використовуються для обчислення). Якщо ваш інтерес викликає останнє, дивіться посилання, вказане Даніелем у цій публікації, а також відповідне запитання щодо ТА .

Щоб пояснити, як і тим більше чому, корисно, спочатку корисно спростити проблему і працювати лише в двох вимірах. Як тільки ви отримаєте це в 2D, простіше думати про це в трьох вимірах, і, звичайно, важче уявити собі в багатьох інших вимірах, але до цього часу ми можемо використовувати лінійну алгебру для чисельних обчислень, а також, щоб допомогти нам думати в термінах ліній / векторів / "площин" / "сфер" у n розмірах, хоча ми не можемо їх намалювати.

Отже, у двох вимірах : щодо подібності тексту це означає, що ми зосередимось на двох різних термінах, скажімо слова "Лондон" і "Париж", і ми порахували, скільки разів кожне з цих слів знайдене в кожному з два документи, які ми хочемо порівняти. Це дає нам для кожного документа точку в площині xy. Наприклад, якби Doc1 мав Париж один раз, а Лондон чотири рази, точка (1,4) представила б цей документ (щодо цієї зменшеної оцінки документів). Або, кажучи з точки зору векторів, цей документ Doc1 був би стрілкою, що йде від початкового пункту до точки (1,4). Маючи на увазі це зображення, давайте подумаємо про те, що означає два документи схожими і як це стосується векторів.

ДУЖЕ подібні документи (знову ж таки щодо цього обмеженого набору вимірів) мали б однакову кількість посилань на Париж, І та сама кількість посилань на Лондон, або, можливо, вони могли мати однакове співвідношення цих посилань. Документ, Doc2, що має 2 відхилення до Парижа та 8 відмов у Лондоні, також був би дуже схожим, лише з, можливо, більш довгим текстом чи якось повторюваним назвами міст, але в тій же пропорції. Можливо, обидва документи - це путівники про Лондон, лише посилаючись на Париж (і як неприховано це місто ;-) Просто жартую !!!.

Зараз менш схожі документи можуть також містити посилання на обидва міста, але в різних пропорціях. Можливо, Doc2 цитуватиме Париж лише один раз та Лондон сім разів.

Повернувшись до нашої площини xy, якщо ми складемо ці гіпотетичні документи, ми побачимо, що коли вони ДУЖЕ подібні, їх вектори перекриваються (хоча деякі вектори можуть бути довші), і коли вони починають мати менше спільного, ці вектори починають розходитися, мати ширший кут між ними.

Виміряючи кут між векторами, ми можемо добре уявити їх схожість , а щоб зробити це ще простіше, взявши косинус цього кута, ми маємо приємне значення 0 до 1 або -1 до 1, що вказує на ця схожість, залежно від того, що і як ми пояснюємо. Чим менший кут, тим більший (ближче до 1) величина косинуса, а також більша схожість.

Зрештою, якщо Doc1 цитує лише Париж, а Doc2 цитує лише Лондон, документи не мають нічого спільного. Doc1 мав би свій вектор на осі x, Doc2 на осі y, кут 90 градусів, косинус 0. У цьому випадку ми могли б сказати, що ці документи ортогональні один одному.

Додавання розмірів :
Завдяки цьому інтуїтивному відчуттю подібності, вираженому як малий кут (або великий косинус), ми тепер можемо уявити речі в трьох вимірах, скажімо, ввівши слово "Амстердам" у суміш і досить добре візуалізувати, як документ із двома посилання на кожного мали б вектор, що йде в певному напрямку, і ми можемо побачити, як цей напрямок порівнюватиметься з документом, що цитує Париж та Лондон три рази кожен, але не Амстердам і т. д. Як сказано, ми можемо спробувати уявити цю фантазію місце для 10 або 100 міст. Важко малювати, але легко концептуалізувати.

Я закінчу лише сказавши кілька слів про саму формулу . Як я вже говорив, інші посилання дають хорошу інформацію про розрахунки.

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


25

Ось моя реалізація в 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));
        }
    }
}

це дивовижне дякую, що мені сподобалось, як ви пояснили
величину

Це чудово, але що робити, якщо ми працюємо з файлами або рядками.
Талха

21

Для простоти я скорочую вектор 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 градусам.


18

Цей код 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))

Чи можете ви пояснити, чому ви використовували набір у рядку "all_items = set (counter1.keys ()). Union (set (counter2.keys ()))".
Ghos3t

@ Ghos3t, тобто отримати список відмінних слів з обох документів
Робота

7

Використовуючи приклад @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)))

5

Це простий 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
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));
}
}

3

Простий код 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));
  }

1
Це не "простий, графічний спосіб", але все ж просто код. Хоча й інші допустили таку ж помилку: /
Skrylar

-1

Два вектори A і B існують у двовимірному просторі або в просторі 3D, кут між цими векторами є кос подібним.

Якщо кут більше (може досягати максимуму 180 градусів), це Cos 180 = -1, а мінімальний кут - 0 градус. cos 0 = 1 означає, що вектори вирівняні один до одного, отже, вектори схожі.

cos 90 = 0 (що достатньо для висновку, що вектори A і B зовсім не схожі, і оскільки відстань не може бути від'ємною, значення косинусів буде лежати від 0 до 1. Отже, більший кут передбачає зменшення подібності (візуалізація також має сенс)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.