Dapatkah seseorang memberikan contoh kesamaan cosinus, dengan cara yang sangat sederhana dan grafis?


201

Artikel Kesamaan Cosine di Wikipedia

Bisakah Anda menunjukkan vektor di sini (dalam daftar atau sesuatu) dan kemudian menghitungnya, dan biarkan kami melihat cara kerjanya?

Saya seorang pemula.


1
Coba ambil salinan Geometri dan Makna oleh Widdows ( press.uchicago.edu/presssite/... ), saya membacanya beberapa waktu lalu dan berharap saya memilikinya beberapa tahun yang lalu, teks pengantar yang bagus.
Nathan Howell

Jawaban:


463

Berikut adalah dua teks yang sangat singkat untuk dibandingkan:

  1. Julie loves me more than Linda loves me

  2. Jane likes me more than Julie loves me

Kami ingin tahu betapa miripnya teks-teks ini, murni dalam hal jumlah kata (dan mengabaikan urutan kata). Kita mulai dengan membuat daftar kata-kata dari kedua teks:

me Julie loves Linda than more likes Jane

Sekarang kami menghitung berapa kali setiap kata ini muncul di setiap teks:

   me   2   2
 Jane   0   1
Julie   1   1
Linda   1   0
likes   0   1
loves   2   1
 more   1   1
 than   1   1

Kami tidak tertarik dengan kata-kata itu sendiri. Kami hanya tertarik pada dua vektor vertikal penghitungan tersebut. Misalnya, ada dua contoh 'saya' di setiap teks. Kita akan memutuskan seberapa dekat kedua teks ini satu sama lain dengan menghitung satu fungsi dari dua vektor tersebut, yaitu kosinus sudut antara keduanya.

Kedua vektor tersebut adalah:

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

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

Cosinus dari sudut di antara mereka adalah sekitar 0,822.

Vektor ini 8-dimensi. Sebuah kebajikan menggunakan kesamaan cosinus jelas bahwa itu mengkonversi pertanyaan yang melampaui kemampuan manusia untuk memvisualisasikan ke yang bisa. Dalam hal ini Anda dapat menganggap ini sebagai sudut sekitar 35 derajat yang merupakan 'jarak' dari nol atau kesepakatan sempurna.


12
Ini persis apa yang saya cari. Persis. Apakah ini dianggap sebagai bentuk paling sederhana dari "model ruang vektor"?
TIMEX

2
Saya sangat senang ini bermanfaat bagi Anda, Alex. Maaf atas keterlambatan dalam merespons. Saya belum mengunjungi StackOverflow dalam beberapa saat. Sebenarnya ini adalah contoh dari "ruang produk dalam". Ada diskusi dasar tentang wikipedia.
Bill Bell

1
Apakah ada cara untuk menormalkan panjang dokumen?
sinθ

1
Anda harus menggunakan normalisasi panjang dan sebelum itu, cobalah untuk menggunakan pembobotan frekuensi log pada semua vektor istilah. Jika Anda sudah berurusan dengan vektor yang dinormalisasi, maka itu adalah produk titik AB
Ali Gajani

4
Contoh yang lebih rinci dengan penggunaan normalisasi panjang dan TF-IDF: site.uottawa.ca/~diana/csi4107/cosine_tf_idf_example.pdf
Mike B.

121

Saya kira Anda lebih tertarik untuk mendapatkan beberapa wawasan tentang " mengapa " persamaan cosinus bekerja (mengapa ini memberikan indikasi kesamaan yang baik), daripada " bagaimana " itu dihitung (operasi spesifik yang digunakan untuk perhitungan). Jika Anda tertarik pada yang terakhir, lihat referensi yang ditunjukkan oleh Daniel di pos ini, serta Pertanyaan SO terkait .

Untuk menjelaskan bagaimana dan terlebih lagi mengapa, ada baiknya, pada awalnya, untuk menyederhanakan masalah dan hanya bekerja dalam dua dimensi. Setelah Anda mendapatkan ini dalam 2D, lebih mudah untuk memikirkannya dalam tiga dimensi, dan tentu saja lebih sulit untuk membayangkan dalam banyak dimensi lagi, tetapi pada saat itu kita dapat menggunakan aljabar linier untuk melakukan perhitungan numerik dan juga untuk membantu kita berpikir dalam hal garis / vektor / "pesawat" / "bola" dalam dimensi n, meskipun kita tidak bisa menggambar ini.

Jadi, dalam dua dimensi : berkenaan dengan kesamaan teks, ini berarti bahwa kami akan fokus pada dua istilah yang berbeda, ucapkan kata "London" dan "Paris", dan kami akan menghitung berapa kali masing-masing kata ini ditemukan di masing-masing dua dokumen yang ingin kita bandingkan. Ini memberi kita, untuk setiap dokumen, titik di bidang xy. Sebagai contoh, jika Doc1 memiliki Paris sekali, dan London empat kali, suatu titik di (1,4) akan menyajikan dokumen ini (berkaitan dengan evaluasi dokumen yang sangat kecil ini). Atau, berbicara dalam hal vektor, dokumen Doc1 ini akan menjadi panah dari titik asal ke titik (1,4). Dengan mengingat gambar ini, mari kita pikirkan apa artinya dua dokumen menjadi serupa dan bagaimana hubungannya dengan vektor.

SANGAT dokumen yang serupa (sekali lagi berkaitan dengan set dimensi terbatas ini) akan memiliki jumlah referensi yang sama ke Paris, DAN jumlah referensi yang sama ke London, atau mungkin, mereka dapat memiliki rasio referensi yang sama. Dokumen, Doc2, dengan 2 rujukan ke Paris dan 8 rujukan ke London, juga akan sangat mirip, hanya dengan teks yang mungkin lebih panjang atau entah bagaimana lebih berulang dari nama kota, tetapi dalam proporsi yang sama. Mungkin kedua dokumen adalah panduan tentang London, hanya membuat referensi ke Paris (dan betapa tidak kerennya kota itu ;-) Hanya bercanda !!!.

Sekarang, dokumen yang kurang serupa mungkin juga menyertakan referensi ke kedua kota, tetapi dalam proporsi yang berbeda. Mungkin Doc2 hanya akan mengutip Paris sekali dan London tujuh kali.

Kembali ke bidang xy kita, jika kita menggambar dokumen hipotetis ini, kita melihat bahwa ketika mereka SANGAT mirip, vektor mereka tumpang tindih (meskipun beberapa vektor mungkin lebih panjang), dan ketika mereka mulai memiliki kurang kesamaan, vektor ini mulai menyimpang, untuk memiliki sudut yang lebih lebar di antara mereka.

Dengan mengukur sudut antara vektor, kita bisa mendapatkan ide yang bagus tentang kesamaan mereka , dan untuk membuat segalanya lebih mudah, dengan mengambil Cosine dari sudut ini, kita memiliki nilai 0 ke 1 atau -1 ke 1 yang bagus yang mengindikasikan kesamaan ini, tergantung pada apa dan bagaimana kita menjelaskannya. Semakin kecil sudutnya, semakin besar (lebih dekat ke 1) nilai kosinus, dan juga semakin tinggi kesamaannya.

Pada ekstremnya, jika Doc1 hanya mengutip Paris dan Doc2 hanya mengutip London, dokumen itu sama sekali tidak memiliki kesamaan. Doc1 akan memiliki vektor pada sumbu x, Doc2 pada sumbu y, sudut 90 derajat, Cosine 0. Dalam hal ini kita akan mengatakan bahwa dokumen-dokumen ini ortogonal satu sama lain.

Menambahkan dimensi :
Dengan rasa intuitif untuk kesamaan yang diekspresikan sebagai sudut kecil (atau kosinus besar), kita sekarang dapat membayangkan berbagai hal dalam 3 dimensi, katakan dengan membawa kata "Amsterdam" ke dalam campuran, dan memvisualisasikan dengan baik bagaimana dokumen dengan dua referensi untuk masing-masing akan memiliki vektor pergi ke arah tertentu, dan kita dapat melihat bagaimana arah ini akan dibandingkan dengan dokumen yang mengutip Paris dan London masing-masing tiga kali, tetapi tidak Amsterdam, dll. Seperti dikatakan, kita dapat mencoba dan membayangkan mewah ini ruang untuk 10 atau 100 kota. Sulit untuk menggambar, tetapi mudah dikonsep.

Saya akan menyelesaikan hanya dengan mengatakan beberapa kata tentang formula itu sendiri . Seperti yang telah saya katakan, referensi lain memberikan informasi yang baik tentang perhitungan.

Pertama dalam dua dimensi. Rumus untuk Cosinus sudut antara dua vektor berasal dari perbedaan trigonometri (antara sudut a dan sudut b):

cos(a - b) = (cos(a) * cos(b)) + (sin (a) * sin(b))

Formula ini terlihat sangat mirip dengan formula produk titik:

Vect1 . Vect2 =  (x1 * x2) + (y1 * y2)

di mana cos(a)sesuai dengan xnilai dan sin(a)yang ynilai, untuk vektor pertama, dll Satu-satunya masalah adalah bahwa x, y, dll tidak persis cosdan sinnilai-nilai, nilai-nilai ini perlu dibaca pada lingkaran satuan. Di situlah penyebut rumus dimulai: dengan membaginya dengan produk dari panjang vektor-vektor ini, koordinat xdan ymenjadi dinormalisasi.


25

Inilah implementasi saya di 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));
        }
    }
}

ini luar biasa terima kasih saya suka bagaimana Anda menjelaskan Magnitude =)
liminal18

Itu bagus tetapi bagaimana jika kita bekerja dengan file atau string.
Talha

21

Untuk kesederhanaan, saya mengurangi vektor a dan b:

Let :
    a : [1, 1, 0]
    b : [1, 0, 1]

Kemudian cosine similarity (Theta):

 (Theta) = (1*1 + 1*0 + 0*1)/sqrt((1^2 + 1^2))* sqrt((1^2 + 1^2)) = 1/2 = 0.5

maka kebalikan dari cos 0,5 adalah 60 derajat.


18

Kode Python ini adalah upaya cepat dan kotor saya untuk mengimplementasikan algoritma:

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))

Bisakah Anda menjelaskan mengapa Anda menggunakan set di baris "all_items = set (counter1.keys ()). Union (set (counter2.keys ()))".
Ghos3t

@ Ghos3t, yaitu untuk mendapatkan daftar kata-kata yang berbeda dari kedua dokumen
Jobs

7

Menggunakan contoh @Bill Bell, dua cara untuk melakukan ini di [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)))

atau mengambil keuntungan dari kinerja metode crossprod () ...

e = crossprod(a, b) / (sqrt(crossprod(a, a)) * sqrt(crossprod(b, b)))

5

Ini adalah Pythonkode sederhana yang mengimplementasikan kesamaan cosinus.

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

Kode JAVA sederhana untuk menghitung kesamaan cosinus

/**
   * 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
Ini bukan "sederhana, cara grafis" tetapi hanya kode. Meskipun orang lain telah melakukan kesalahan yang sama juga: /
Skrylar

-1

Dua Vektor A dan B ada dalam ruang 2D atau ruang 3D, sudut antara vektor tersebut adalah kesamaan.

Jika sudut lebih (bisa mencapai maks 180 derajat) yaitu Cos 180 = -1 dan sudut minimum adalah 0 derajat. cos 0 = 1 menyiratkan vektor selaras satu sama lain dan oleh karena itu vektornya sama.

cos 90 = 0 (yang cukup untuk menyimpulkan bahwa vektor A dan B tidak sama sekali dan karena jarak tidak boleh negatif, nilai-nilai kosinus akan terletak dari 0 hingga 1. Oleh karena itu, lebih banyak sudut menyiratkan menyiratkan mengurangi kesamaan (memvisualisasikan juga itu) masuk akal)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.