TIM*_*MEX 190 text data-mining cosine-similarity
你能在这里(列表或其他东西)显示向量然后进行数学运算,让我们看看它是如何工作的?
我是初学者.
Bil*_*ell 441
这里有两个非常短的文本要比较:
Julie loves me more than Linda loves me
Jane likes me more than Julie loves me
我们想知道这些文本有多相似,纯粹是按字数统计(并忽略字序).我们首先列出两个文本中的单词:
me Julie loves Linda than more likes Jane
Run Code Online (Sandbox Code Playgroud)
现在我们计算每个单词在每个文本中出现的次数:
me 2 2
Jane 0 1
Julie 1 1
Linda 1 0
likes 0 1
loves 2 1
more 1 1
than 1 1
Run Code Online (Sandbox Code Playgroud)
我们对这些词本身并不感兴趣.我们只关注那两个垂直向量的计数.例如,每个文本中有两个"我"实例.我们将通过计算这两个向量的一个函数,即它们之间角度的余弦来决定这两个文本之间的接近程度.
这两个载体再次:
a: [2, 0, 1, 1, 0, 2, 1, 1]
b: [2, 1, 1, 0, 1, 1, 1, 1]
Run Code Online (Sandbox Code Playgroud)
它们之间角度的余弦约为0.822.
这些矢量是8维的.使用余弦相似性的一个优点显然是它将一个超出人类能力的问题转换为可视化的问题.在这种情况下,你可以把它想象成大约35度的角度,这是零距离或完全一致的"距离".
mjv*_*mjv 112
我猜你更感兴趣的是深入了解余弦相似性的" 原因 "(为什么它提供了相似性的良好指示),而不是计算它的" 方式 "(用于计算的具体操作).如果您对后者感兴趣,请参阅Daniel在本文中指出的参考文献,以及相关的SO问题.
为了解释原因如何以及更多原因,首先,简化问题并仅在二维中起作用是有用的.一旦你在2D中得到它,就更容易在三个维度中考虑它,当然在更多维度中更难想象,但到那时我们可以使用线性代数进行数值计算,并帮助我们用术语思考在n维中的线/矢量/"飞机"/"球体",即使我们无法绘制这些.
所以... 在两个维度上:关于文本相似性,这意味着我们将关注两个不同的术语,比如"伦敦"和"巴黎"这两个词,我们会计算这些词在每个词中找到的次数.我们希望比较的两份文件中的每一份.这为我们提供了每个文档在xy平面上的一个点,例如,如果Doc1有一次巴黎,而伦敦有四次,则(1,4)点会出现这个文档(关于文档的这种小的评估) .或者,就向量而言,这个Doc1文档将是从原点到点的箭头(1,4).考虑到这个图像,让我们考虑两个文档相似的含义以及它与向量的关系.
非常类似的文件(再次关于这个有限的维度)将具有与巴黎相同数量的引用,并且对伦敦的引用数量相同,或者可能,它们可以具有相同的这些引用的比例(例如,文件Doc2,其中2个参考到巴黎,8个参考到伦敦,也会非常相似,可能只是更长的文本或某种程度上更重复的城市名称,但是相同比例:也许这两个文件都是关于伦敦的指南,只是制作通过对巴黎的引用(以及那个城市是多么酷;-)开个玩笑!!!).现在不那么相似的文件,也可能包含对这两个城市的引用,但不同的比例,也许Doc2只会引用巴黎一次和伦敦7次.
回到我们的xy平面,如果我们绘制这些假设文档,我们看到当它们非常相似时它们的向量重叠(尽管一些向量可能更长),并且当它们开始具有较少的共同点时,这些向量开始发散,到他们之间有更大的角度.
巴姆!通过测量矢量之间的角度,我们可以很好地了解它们的相似性,并且为了使事情更容易,通过取这个角度的余弦,我们有一个很好的0到1(或-1到1,取决于什么以及我们如何解释表明这种相似性的价值.角度越小,余弦值越大(越接近1),相似度越大.
在极端情况下,如果Doc1仅引用巴黎,Doc2仅引用伦敦,那么这些文件绝对没有任何共同之处.Doc1将在x轴上具有矢量,在y轴上具有Doc2,角度为90度,余弦为0.(当我们说两个事物彼此正交时,我们的意思是 BTW )
添加尺寸:
通过这种直观的相似性表达为小角度(或大余弦),我们现在可以想象三维中的事物,比如在混合中引入"阿姆斯特丹"这个词.并且很好地想象一个具有两个参考文件的文档如何在特定方向上有一个向量,我们可以看到这个方向如何与一个引用巴黎和伦敦三次但不是阿姆斯特丹等的文档进行比较.如上所述我们可以尝试和想象这个10或100个城市的奇特空间,很难画,但很容易概念化.
我将简单地谈谈公式本身.如所述其他参考文献提供关于计算的良好信息.
再次首先在2个维度.两个矢量之间角度余弦的公式是从三角差(角度a和角度b之间)导出的
cos(a - b) = (cos(a) * cos(b)) + (sin (a) * sin(b))
Run Code Online (Sandbox Code Playgroud)
此公式看起来非常类似于点积公式:
Vect1 . Vect2 = (x1 * x2) + (y1 * y2)
Run Code Online (Sandbox Code Playgroud)
其中cos(a)匹配第一个向量的x值和sin(a)y值.唯一的问题是x,y等不完全是cos和sin值,因为这些值需要在单位圆上读取.这就是公式的分母所在的位置:通过除以这些向量的长度乘积,x和y坐标变为标准化.
tra*_*nmq 23
这是我在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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 20
为简单起见,我正在减少向量a和b:
Let :
a : [1, 1, 0]
b : [1, 0, 1]
Run Code Online (Sandbox Code Playgroud)
然后余弦相似度(Theta):
(Theta) = (1*1 + 1*0 + 0*1)/sqrt((1^2 + 1^2))* sqrt((1^2 + 1^2)) = 1/2 = 0.5
Run Code Online (Sandbox Code Playgroud)
那么cos 0.5的倒数是60度.
Vic*_*Yan 17
这个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))
Run Code Online (Sandbox Code Playgroud)
使用@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)))
Run Code Online (Sandbox Code Playgroud)
或利用crossprod()方法的表现......
e = crossprod(a, b) / (sqrt(crossprod(a, a)) * sqrt(crossprod(b, b)))
Run Code Online (Sandbox Code Playgroud)
这是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]])
Run Code Online (Sandbox Code Playgroud)