【问题标题】:How to calculate cosine similarity of 2 vectors when the element of each vectors has different range当每个向量的元素具有不同的范围时如何计算2个向量的余弦相似度
【发布时间】:2012-07-10 09:41:07
【问题描述】:

如何找到两个向量之间的余弦相似度,并且向量的每个元素都有不同的范围? 例如,每个向量有两个元素V = {v[0], v[1]},如{age, height},其中年龄范围为30-70,身高范围为100cm-200cm,给出两个示例向量v1 = {20, 175}, v2 = {35,192}

我知道余弦相似度 (sim) 定义为sim = (v1 dot v2 ) / (|v1| * |v2|),其中 dot 是 v1 和 v2 之间的点积,|v|是向量的大小。但这是基于向量 V 中的每个元素具有相同数据范围的假设,当每个元素具有不同范围时不适用,例如我这里使用的情况。

我能想到的一件事是将权重向量 W = {w[0],w[1]} 应用于每个向量 v1,并在此处使用 v2 来规范化向量中的每个元素。

那是

weighted_sim = ( sum (w[i] * v1[i] * v2[i]) )  / sqrt ( (sum (w[i] *v1[i]^2 ) ) * ( sum (w[i] *v2[i]^2 ) ) )

但是我在这里很难算出权重向量 W。

有人可以帮我吗?非常感谢。

【问题讨论】:

  • 您不会简单地将两个测量值归一化以位于[0,1] 范围内吗?所以标准化年龄是(real_age-30)/(70-30)?当然,这不是简单的乘法“权重”;我首先计算归一化向量,然后计算向量相似度。
  • 感谢您的回答,但归一化取决于数据分布。例如,如果年龄线性分布在 30-40 之间,那么您提到的线性归一化将起作用,否则会在这里产生额外的问题。
  • 哦,好吧,你需要比我能提供的更聪明的答案。
  • 在这方面,您通过缩放一个或其他维度或两个维度所做的一切将是有效地缩放一个维度,尽管这会改变您的 sim 结果,但不会改变一些基本点,例如如果之前是 1,那么之后会是 1。 iof sim1>sim2 before then it will be after。我不知道你之后用你的 sim 做什么,但你可能会发现这没什么大不了的......
  • 谢谢,克里斯。我打算将余弦相似度和欧几里得距离以加权形式组合在一起,以测量两个向量之间的差异。欧几里得距离给出幅度差但不给出角度差。余弦距离在这里有相反的结果。所以我打算在这里以加权形式的距离度量将两者结合在一起。谢谢

标签: java algorithm math


【解决方案1】:

我只是将两个测量值归一化,使其位于 [0,1] 范围内。所以归一化年龄是(real_age-30)/(70-30),归一化身高是(real_height-100)/(200-100)。我注意到您的示例向量 V1 的年龄为 20 岁,超出了您指定的范围。

这些计算不会为您提供可以通过简单乘法应用于原始数据的权重。我会先计算归一化向量,然后计算它们之间的向量相似度。

【讨论】:

  • 感谢您的回答,马克。此外,由于余弦相似度给出了使用两个向量之间的角度差,而欧几里德距离给出了我们两个向量之间的幅度差。有什么方法可以将余弦距离和欧几里得距离以加权形式组合在一起来表示最终的距离度量。谢谢。
  • 我不知道任何广泛使用的组合距离度量的方法,但我希望您能想到一些 ad-hoc 比我可以。
【解决方案2】:

您可能需要标准化,但这需要比两个输入向量更多的数据。当您想要赋予其中一项功能(我认为这是两个功能)比另一项更重要/更不重要时,就会应用加权。

作为示例,我人为地考虑了应用标准化的整个范围(以整数步长),并将您的单个示例与标准化和无程序(即,对数据不做任何事情)进行了比较。结果如下:

(standardization) Similarity: 0.744599          Data: (-1.12599, 0.88339), (-0.259844, 1.47232).
(  normalization) Similarity: 0.978736          Data: (0.166667, 0.75), (0.416667, 0.92).
(           none) Similarity: 0.997788          Data: (20, 175), (35, 192).

至少对我来说,使用标准化的结果更有意义。

这里是生成上述示例的基本代码:

import numpy

def cosine_dist(a, b): # Similarity between a and b
    return sum(a * b) / ((sum(a ** 2) * sum(b ** 2)) ** 0.5)


age_range = [10., 70.]
height_range = [100., 200.]

# Input.
age = numpy.array([20, 35])
height = numpy.array([175, 192])

# Normalization
age_n = numpy.array(age, dtype=float)
height_n = numpy.array(height, dtype=float)
age_n = (age_n - age_range[0]) / (age_range[1] - age_range[0])
height_n = (height_n - height_range[0]) / (height_range[1] - height_range[0])

# Standardization.
all_age = numpy.array(range(*map(int, age_range)))
all_height = numpy.array(range(*map(int, height_range)))
age_s = numpy.array(age, dtype=float)
height_s = numpy.array(height, dtype=float)
age_s = (age_s - all_age.mean()) / all_age.std()
height_s = (height_s - all_height.mean()) / all_height.std()

for name, a, h in [('standardization', age_s, height_s),
        ('normalization', age_n, height_n), ('none', age, height)]:

    data = numpy.array([(a[0], h[0]), (a[1], h[1])])
    data_s = '(%g, %g), (%g, %g)' % (data[0][0], data[0][1], data[1][0], data[1][1])
    print "(%15s) Similarity: %g\t\tData: %s." % (name, cosine_dist(*data),
            data_s)

【讨论】:

    猜你喜欢
    • 2010-10-05
    • 2016-07-11
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 2016-03-08
    • 2019-12-27
    • 2016-03-06
    • 2021-07-19
    相关资源
    最近更新 更多