Ai đó có thể đưa ra một ví dụ về sự tương tự cosine, theo một cách rất đơn giản, đồ họa?


201

Bài viết tương tự Cosine trên Wikipedia

Bạn có thể hiển thị các vectơ ở đây (trong một danh sách hoặc một cái gì đó) và sau đó làm toán, và cho chúng tôi xem nó hoạt động như thế nào?

Tôi là người mới bắt đầu.


1
Hãy thử chọn một bản sao của Hình học và Ý nghĩa của Widdows ( nhấn.uchicago.edu/presssite/iêu ), tôi đọc nó một lúc trước và ước rằng tôi đã có nó một số năm trước, văn bản giới thiệu tuyệt vời.
Nathan Howell

Câu trả lời:


463

Đây là hai văn bản rất ngắn để so sánh:

  1. Julie loves me more than Linda loves me

  2. Jane likes me more than Julie loves me

Chúng tôi muốn biết các văn bản này giống nhau như thế nào, hoàn toàn về mặt đếm từ (và bỏ qua trật tự từ). Chúng tôi bắt đầu bằng cách lập danh sách các từ trong cả hai văn bản:

me Julie loves Linda than more likes Jane

Bây giờ chúng tôi đếm số lần mỗi từ này xuất hiện trong mỗi văn bản:

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

Chúng tôi không quan tâm đến các từ mặc dù. Chúng tôi chỉ quan tâm đến hai vectơ dọc của số đếm. Chẳng hạn, có hai trường hợp 'tôi' trong mỗi văn bản. Chúng ta sẽ quyết định mức độ gần nhau của hai văn bản này với nhau bằng cách tính một hàm của hai vectơ đó, cụ thể là cosin của góc giữa chúng.

Hai vectơ là, một lần nữa:

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

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

Cosin của góc giữa chúng là khoảng 0,822.

Các vectơ này là 8 chiều. Một ưu điểm của việc sử dụng sự tương tự cosine rõ ràng là nó chuyển đổi một câu hỏi vượt quá khả năng của con người để hình dung thành một câu hỏi có thể. Trong trường hợp này, bạn có thể nghĩ đây là góc khoảng 35 độ, đó là một khoảng cách 'khoảng cách' từ 0 hoặc thỏa thuận hoàn hảo.


12
Điều này thật đúng với gì mà tôi đã tìm kiếm. Chính xác. Đây có được coi là hình thức đơn giản nhất của "mô hình không gian vectơ" không?
TIMEX

2
Tôi thực sự rất vui vì điều này hữu ích với bạn, Alex. Xin lỗi vì sự chậm trễ trong việc đáp ứng. Tôi đã không truy cập StackOverflow trong một thời gian. Trên thực tế đây là một ví dụ về "không gian sản phẩm bên trong". Có một cuộc thảo luận cơ bản trên wikipedia.
Bill Bell

1
Có cách nào để bình thường hóa cho chiều dài tài liệu?
sinθ

1
Bạn phải sử dụng chuẩn hóa độ dài và trước đó, hãy thử sử dụng trọng số tần số nhật ký trên tất cả các vectơ hạn. Nếu bạn đã xử lý các vectơ chuẩn hóa, thì đó là sản phẩm chấm của AB
Ali Gajani

4
Ví dụ chi tiết hơn với việc sử dụng chuẩn hóa độ dài và TF-IDF: site.uottawa.ca/~diana/csi4107/cosine_tf_idf_example.pdf
Mike B.

121

Tôi đoán bạn quan tâm nhiều hơn đến việc hiểu rõ hơn về " tại sao " sự tương tự cosin hoạt động (tại sao nó cung cấp một dấu hiệu tốt về sự tương tự), thay vì " cách " nó được tính toán (các thao tác cụ thể được sử dụng để tính toán). Nếu bạn quan tâm đến vấn đề thứ hai, hãy xem tài liệu tham khảo được chỉ định bởi Daniel trong bài đăng này, cũng như Câu hỏi SO liên quan .

Để giải thích cả về cách thức và thậm chí nhiều hơn lý do tại sao, ban đầu, nó hữu ích, để đơn giản hóa vấn đề và chỉ hoạt động theo hai chiều. Khi bạn có được điều này ở dạng 2D, sẽ dễ dàng hơn khi nghĩ về nó theo ba chiều và dĩ nhiên khó tưởng tượng hơn ở nhiều chiều khác, nhưng sau đó chúng ta có thể sử dụng đại số tuyến tính để thực hiện các phép tính số và cũng để giúp chúng ta suy nghĩ về các thuật ngữ của các dòng / vectơ / "mặt phẳng" / "hình cầu" theo n chiều, mặc dù chúng ta không thể vẽ chúng.

Vì vậy, theo hai chiều : liên quan đến sự giống nhau về văn bản, điều này có nghĩa là chúng tôi sẽ tập trung vào hai thuật ngữ riêng biệt, nói các từ "London" và "Paris", và chúng tôi sẽ đếm số lần mỗi từ này được tìm thấy trong mỗi từ hai tài liệu chúng tôi muốn so sánh. Điều này cho chúng ta, đối với mỗi tài liệu, một điểm trong mặt phẳng xy. Ví dụ: nếu Doc1 có Paris một lần và London bốn lần, một điểm tại (1,4) sẽ trình bày tài liệu này (liên quan đến việc đánh giá tài liệu nhỏ gọn này). Hoặc, nói về các vectơ, tài liệu Doc1 này sẽ là một mũi tên đi từ điểm gốc đến điểm (1,4). Với hình ảnh này, chúng ta hãy nghĩ về ý nghĩa của hai tài liệu tương tự nhau và điều này liên quan đến các vectơ như thế nào.

RẤT NHIỀU tài liệu tương tự (một lần nữa liên quan đến tập kích thước giới hạn này) sẽ có cùng số lượng tài liệu tham khảo về Paris, VÀ cùng số lượng tài liệu tham khảo đến Luân Đôn, hoặc có thể, chúng có thể có cùng tỷ lệ của các tài liệu tham khảo này. Một Tài liệu, Doc2, với 2 lượt giới thiệu đến Paris và 8 lượt giới thiệu đến London, cũng sẽ rất giống nhau, chỉ với một văn bản dài hơn hoặc bằng cách nào đó lặp đi lặp lại nhiều hơn tên của các thành phố, nhưng theo cùng tỷ lệ. Có lẽ cả hai tài liệu đều là hướng dẫn về Luân Đôn, chỉ thực hiện chuyển các tài liệu tham khảo đến Paris (và thành phố đó không đẹp đến mức nào ;-) Đùa thôi !!!.

Bây giờ, các tài liệu ít giống nhau hơn cũng có thể bao gồm các tham chiếu đến cả hai thành phố, nhưng ở các tỷ lệ khác nhau. Có lẽ Doc2 sẽ chỉ trích dẫn Paris một lần và London bảy lần.

Quay lại mặt phẳng xy của chúng ta, nếu chúng ta vẽ các tài liệu giả định này, chúng ta thấy rằng khi chúng RẤT giống nhau, các vectơ của chúng trùng nhau (mặc dù một số vectơ có thể dài hơn) và khi chúng bắt đầu ít phổ biến hơn, các vectơ này bắt đầu phân kỳ, để có một góc rộng hơn giữa chúng.

Bằng cách đo góc giữa các vectơ, chúng ta có thể biết được sự tương đồng của chúng và để làm cho mọi thứ trở nên dễ dàng hơn, bằng cách lấy Cosine của góc này, chúng ta có một giá trị 0 đến 1 hoặc -1 đến 1 tốt cho thấy sự giống nhau này, tùy thuộc vào những gì và làm thế nào chúng ta chiếm. Góc càng nhỏ, giá trị cosin càng lớn (càng gần 1) và độ tương tự cũng càng cao.

Ở cực điểm, nếu Doc1 chỉ trích dẫn Paris và Doc2 chỉ trích dẫn London, thì các tài liệu hoàn toàn không có gì chung. Doc1 sẽ có vectơ của nó trên trục x, Doc2 trên trục y, góc 90 độ, Cosine 0. Trong trường hợp này, chúng ta sẽ nói rằng các tài liệu này là trực giao với nhau.

Thêm kích thước :
Với cảm giác trực quan này cho sự tương đồng được thể hiện dưới dạng một góc nhỏ (hoặc cosin lớn), giờ đây chúng ta có thể tưởng tượng mọi thứ trong 3 chiều, nói bằng cách đưa từ "Amsterdam" vào hỗn hợp và hình dung khá rõ cách một tài liệu có hai các tham chiếu đến mỗi cái sẽ có một vectơ đi theo một hướng cụ thể và chúng ta có thể thấy hướng này sẽ so sánh với một tài liệu trích dẫn Paris và London ba lần mỗi lần, nhưng không phải Amsterdam, v.v. Như đã nói, chúng ta có thể thử và tưởng tượng ra điều lạ mắt này không gian cho 10 hoặc 100 thành phố. Thật khó để vẽ, nhưng dễ khái niệm hóa.

Tôi sẽ kết thúc chỉ bằng cách nói vài lời về công thức . Như tôi đã nói, các tài liệu tham khảo khác cung cấp thông tin tốt về các tính toán.

Đầu tiên trong hai chiều. Công thức cho Cosine của góc giữa hai vectơ được lấy từ chênh lệch lượng giác (giữa góc a và góc b):

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

Công thức này trông rất giống với công thức sản phẩm chấm:

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

nơi cos(a)tương ứng với các xgiá trị và sin(a)các ygiá trị, cho vector đầu tiên, vv Vấn đề duy nhất, đó là x, yvv là không chính xác cossingiá trị, cho những giá trị này cần phải được đọc trên vòng tròn đơn vị. Đó là nơi mẫu số của công thức bắt đầu: bằng cách chia cho tích của độ dài của các vectơ này, tọa độ xytọa độ trở nên chuẩn hóa.


25

Đây là triển khai của tôi trong 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));
        }
    }
}

điều này thật tuyệt vời cảm ơn bạn Tôi yêu cách bạn giải thích Độ lớn =)
liminal18

Điều đó thật tuyệt nhưng nếu chúng ta làm việc với các tệp hoặc chuỗi.
Talha

21

Để đơn giản tôi đang giảm vectơ a và b:

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

Sau đó, sự tương tự cosine (Theta):

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

sau đó nghịch đảo của cos 0,5 là 60 độ.


18

Mã Python này là nỗ lực nhanh chóng và bẩn thỉu của tôi để thực hiện thuật toán:

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

Bạn có thể giải thích lý do tại sao bạn sử dụng tập hợp trong dòng "all_items = set (counter1.keys ()). Union (set (counter2.keys ()))".
Ghos3t

@ Ghos3t, nghĩa là lấy danh sách các từ riêng biệt từ cả hai tài liệu
Việc làm

7

Sử dụng ví dụ @Bill Bell, hai cách để làm điều này trong [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)))

hoặc tận dụng hiệu suất của phương thức crossprod () ...

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

5

Đây là một Pythonmã đơn giản thực hiện sự tương tự cosine.

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

Mã JAVA đơn giản để tính tương tự cosine

/**
   * 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
Đó không phải là "cách đơn giản, đồ họa" mà chỉ là mã. Mặc dù những người khác cũng mắc lỗi tương tự: /
Skrylar

-1

Hai vectơ A và B tồn tại trong không gian 2D hoặc không gian 3D, góc giữa các vectơ đó là độ tương tự cos.

Nếu góc nhiều hơn (có thể đạt tối đa 180 độ) là Cos 180 = -1 và góc tối thiểu là 0 độ. cos 0 = 1 ngụ ý các vectơ được liên kết với nhau và do đó các vectơ tương tự nhau.

cos 90 = 0 (đủ để kết luận rằng các vectơ A và B hoàn toàn không giống nhau và vì khoảng cách không thể âm, các giá trị cosine sẽ nằm từ 0 đến 1. Do đó, nhiều góc ngụ ý làm giảm sự tương tự (cũng hình dung ra nó có ý nghĩa)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.