Может ли кто-нибудь привести пример косинусного сходства, очень простым, графическим способом?
статья о Косинусном сходстве в Википедии
можете ли вы показать векторы здесь (в списке или что-то еще) а потом посчитаем, и посмотрим, как это работает?
Я новичок.
10 ответов:
вот два очень коротких текста для сравнения:
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
нас не интересуют слова хотя и сами. Нас интересует только эти два вертикальных вектора отсчетов. Например, есть два экземпляра "я" в каждом тексте. Мы собираемся решить, насколько близки эти два текста друг к другу другим путем вычисления одной функции этих двух векторов, а именно Косинус угол между ними.
два вектора, опять же:
a: [2, 0, 1, 1, 0, 2, 1, 1] b: [2, 1, 1, 0, 1, 1, 1, 1]
косинус угла между ними составляет около 0.822.
эти векторы 8-мерное. Добродетель использования косинусное сходство очевидно что он преобразует вопрос, что находится за пределами человеческой способности визуализировать в один это возможно. В этом случае вы можете думать об этом как об угле около 35 градусы, которые являются некоторым "расстоянием" от нуля или совершенного соглашения.
Я предполагаю, что вы больше заинтересованы в получении некоторого понимания"почему" косинусное сходство работает (почему оно дает хороший признак сходства), а не"как " вычисляется (конкретные операции, используемые для расчета). Если вы заинтересованы в последнем, см. ссылку, указанную Даниилом в этом посте, а также связанный так вопрос.
чтобы объяснить, как и тем более зачем, она полезно, во-первых, упростить задачу и работать только в двух измерениях. Как только вы получите это в 2D, легче думать об этом в 3 измерениях и, конечно же, труднее представить себе во многих других измерениях, но к тому времени мы можем использовать линейную алгебру для выполнения числовых вычислений, а также помочь нам думать в терминах линий/векторов / "плоскостей" / "сфер" в N измерениях, даже если мы не можем их нарисовать.
Так... в двух измерениях: что касается сходства текста это это означает, что мы сосредоточимся на двух различных терминах, скажем слова "Лондон" и "Париж", и мы посчитаем, сколько раз каждое из этих слов находится в каждом из двух документов, которые мы хотим сравнить. Это дает нам для каждого документа точку в плоскости x-y, например, если бы Doc1 имел Париж один раз, а Лондон четыре раза, точка в (1,4) представила бы этот документ (в отношении этой уменьшительной оценки документов). Или, говоря с точки зрения векторов, этот документ Doc1 будет стрелкой, идущей от начала координат до точки (1,4). Имея в виду это изображение, давайте подумаем о том, что значит быть похожим для двух документов и как это относится к векторам.
очень похожие документы (опять же в отношении этого ограниченного набора измерений) будут иметь то же самое количество ссылок на Париж, и то же самое количество ссылок на Лондон, или, может быть, они могут иметь то же соотношение этих ссылок (скажем, документ Doc2, с 2 ссылками на Париж и 8 ссылками на Лондон, также будет иметь одинаковое соотношение этих ссылок). очень похоже, только, может быть, более длинный текст или как-то более повторяющиеся названия городов, но в той же пропорции: возможно, оба документа являются путеводителями по Лондону, только делая мимолетные ссылки на Париж (и как не круто, что город; -) просто шучу!!!). Теперь менее похожие документы также могут включать ссылки на оба города, но в разных пропорциях, возможно, Doc2 будет ссылаться только на Париж один раз и Лондон 7 раз.
назад в наш X-y самолет, если мы рисуем эти гипотетические документы, мы видим, что когда они очень похожи, их векторы перекрываются (хотя некоторые векторы могут быть длиннее), и поскольку они начинают иметь меньше общего, эти векторы начинают расходиться, чтобы иметь больший угол между ними.
БАМ! путем измерения угол между векторами, мы можем получить хорошее представление о их схожести , и, чтобы сделать вещи еще проще, взяв Косинус из этого угла у нас есть хороший 0 к 1 (или -1 к 1, в зависимости от того, что и как мы счет) значение, которое указывает на это сходство. Чем меньше угол, тем больше (ближе к 1) значение Косинуса, а также тем больше сходство.
вот что мы имеем в виду, когда говорим, что две вещи ортогональны одной еще один)добавление размеров:
Благодаря этому интуитивному ощущению сходства, выраженному в виде малого угла (или большого Косинуса), мы теперь можем представить себе вещи в 3 измерениях, скажем, вводя слово "Амстердам" в микс. И визуализируйте, довольно хорошо, как документ с двумя ссылками каждого будет иметь вектор, идущий в определенном направлении, и мы можем видеть, как это направление будет сравниваться с документом, цитирующим Париж и Лондон 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
затем и обратное, потому что 0.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]
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)); } }
простой 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)); }
два вектора A и B существуют в 2D пространстве или 3D пространстве, угол между этими векторами является COS подобием.
Если угол больше (может достигать Макс 180 градусов), который Cos 180=-1 и минимальный угол составляет 0 градусов. cos 0 =1 означает, что векторы выровнены друг с другом и, следовательно, векторы похожи.
cos 90=0 (что достаточно для вывода о том, что векторы A и B вообще не похожи и поскольку расстояние не может быть отрицательным, значения Косинуса будут лежать от 0 до 1. Следовательно, больше угла подразумевает подразумевает уменьшение сходства (визуализация также имеет смысл)