【问题标题】:Vector Space Model: Cosine Similarity vs Euclidean Distance向量空间模型:余弦相似度与欧几里得距离
【发布时间】:2013-10-24 23:19:45
【问题描述】:

我有分类文本的语料库。从这些我创建向量。每个向量对应一个文档。向量分量是本文档中的单词权重,计算为 TFIDF 值。接下来,我构建了一个模型,其中每个类都由一个向量表示。模型具有与语料库中的类一样多的向量。模型向量的分量被计算为取自此类向量的所有分量值的平均值。对于未分类的向量,我通过计算这些向量之间的余弦来确定与模型向量的相似性。

问题:

1) 我可以使用未分类向量和模型向量之间的欧几里得距离来计算它们的相似度吗?

2) 为什么欧几里得距离不能作为相似度度量,而不是两个向量之间夹角的余弦值,反之亦然?

谢谢!

【问题讨论】:

标签: vector distance euclidean-distance trigonometry


【解决方案1】:

考虑这一点的一种非正式但相当直观的方式是考虑向量的两个分量:方向幅度

方向是向量的“偏好”/“风格”/“情感”/“潜在变量”,而幅度是它对那个方向的强度方向。

在对文档进行分类时,我们希望根据它们的整体情绪对其进行分类,因此我们使用角距离。

欧几里得距离容易受到文档被它们的 L2 范数(大小,在二维情况下)而不是方向聚类的影响。 IE。具有完全不同方向的向量将被聚类,因为它们与原点的距离相似。

【讨论】:

  • "[with Euclidean distance] 具有完全不同方向的向量将被聚类,因为它们与原点的距离相似" -> 这是真的吗?在极端情况下,考虑两个具有相同大小的截然相反的向量:即使它们与原点的距离相同,它们之间的欧几里得距离也会很大。
  • @xenocyon 考虑它们到原点的幅度很小的情况
  • 如果您有三个文档的情绪为-1、1、100,哪两个更接近:前两个还是后两个?我认为只有当你知道你正在处理的具体问题时才有可能回答。
  • 我认为值得关注的是,如果它们的规范,则 应该 聚集在一起的 2 个向量(因为它们“指向同一方向”)不会与欧几里得距离一致明显不同,例如如果一个文档包含多次出现的密钥标记,而另一个不包含。
【解决方案2】:

我将按相反的顺序回答问题。对于第二个问题,余弦相似度和欧几里得距离是衡量向量相似度的两种不同方法。前者测量向量相对于原点的相似性,而后者测量沿向量的特定兴趣点之间的距离。您可以单独使用,将它们组合并同时使用,或者查看许多其他方法中的一种来确定相似性。有关更多信息,请参阅 Michael Collins 讲座中的 these 幻灯片。

您的第一个问题不是很清楚,但是无论您是在比较文档还是您的“模型”(传统上将其描述为集群),您都应该能够使用任一度量来找到两个向量之间的距离,其中模型是所有聚类的总和)。

【讨论】:

    【解决方案3】:

    计算时间明智(python):

    import time
    import numpy as np
    
    for i in range(10):
        start = time.time() 
        for i in range(10000):
            a, b = np.random.rand(100), np.random.rand(100) 
            np.dot(a, b) / ( np.linalg.norm(a) * np.linalg.norm(b))
        print 'Cosine similarity took', time.time() - start
    
        start = time.time() 
        for i in range(10000):
            a, b = np.random.rand(100), np.random.rand(100) 
            2 * (1 - np.dot(a, b) / ( np.linalg.norm(a) * np.linalg.norm(b)))
        print 'Euclidean from 2*(1 - cosine_similarity) took', time.time() - start
    
    
        start = time.time() 
        for i in range(10000):
            a, b = np.random.rand(100), np.random.rand(100) 
            np.linalg.norm(a-b)
        print 'Euclidean Distance using np.linalg.norm() took', time.time() - start
    
    
        start = time.time() 
        for i in range(10000):
            a, b = np.random.rand(100), np.random.rand(100) 
            np.sqrt(np.sum((a-b)**2))
        print 'Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took', time.time() - start
        print '--------------------------------------------------------'
    

    [出]:

    Cosine similarity took 0.15826010704
    Euclidean from 2*(1 - cosine_similarity) took 0.179041862488
    Euclidean Distance using np.linalg.norm() took 0.10684299469
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.113723039627
    --------------------------------------------------------
    Cosine similarity took 0.161732912064
    Euclidean from 2*(1 - cosine_similarity) took 0.178358793259
    Euclidean Distance using np.linalg.norm() took 0.107393980026
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.111194849014
    --------------------------------------------------------
    Cosine similarity took 0.16274189949
    Euclidean from 2*(1 - cosine_similarity) took 0.178978919983
    Euclidean Distance using np.linalg.norm() took 0.106336116791
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.111373186111
    --------------------------------------------------------
    Cosine similarity took 0.161939144135
    Euclidean from 2*(1 - cosine_similarity) took 0.177414178848
    Euclidean Distance using np.linalg.norm() took 0.106301784515
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.11181807518
    --------------------------------------------------------
    Cosine similarity took 0.162333965302
    Euclidean from 2*(1 - cosine_similarity) took 0.177582979202
    Euclidean Distance using np.linalg.norm() took 0.105742931366
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.111120939255
    --------------------------------------------------------
    Cosine similarity took 0.16153883934
    Euclidean from 2*(1 - cosine_similarity) took 0.176836967468
    Euclidean Distance using np.linalg.norm() took 0.106392860413
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.110891103745
    --------------------------------------------------------
    Cosine similarity took 0.16018986702
    Euclidean from 2*(1 - cosine_similarity) took 0.177738189697
    Euclidean Distance using np.linalg.norm() took 0.105060100555
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.110497951508
    --------------------------------------------------------
    Cosine similarity took 0.159607887268
    Euclidean from 2*(1 - cosine_similarity) took 0.178565979004
    Euclidean Distance using np.linalg.norm() took 0.106383085251
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.11084485054
    --------------------------------------------------------
    Cosine similarity took 0.161075115204
    Euclidean from 2*(1 - cosine_similarity) took 0.177822828293
    Euclidean Distance using np.linalg.norm() took 0.106630086899
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.110257148743
    --------------------------------------------------------
    Cosine similarity took 0.161051988602
    Euclidean from 2*(1 - cosine_similarity) took 0.181928873062
    Euclidean Distance using np.linalg.norm() took 0.106360197067
    Euclidean Distance using np.sqrt(np.sum((a-b)**2)) took 0.111301898956
    --------------------------------------------------------
    

    【讨论】:

    • 所以计算时间明智,你是说欧几里得更好..?
    • 从这些结果来看,计算时间似乎没有显着差异。因此,在决定使用哪种方法时,不能以计算时间为指导。
    【解决方案4】:

    我建议确定在给定应用程序中哪种距离测量更好的唯一可靠方法是同时尝试两种方法,看看哪一种能提供更令人满意的结果。我猜在大多数情况下,效果的差异不会很大,但在您的特定应用中可能并非如此。

    【讨论】:

      猜你喜欢
      • 2012-08-20
      • 2016-01-01
      • 2010-12-22
      • 2018-02-10
      • 2018-04-20
      • 2017-12-12
      • 2020-06-18
      • 2017-09-27
      • 2010-10-31
      相关资源
      最近更新 更多