1

我有以下数组(向量): l=[[0.483, 0.923], [0.781, 0.188], [0.446, 0.564, 0.796]]

我编写了以下代码行来计算向量之间的余弦相似度,并收到以下错误消息:ValueError:矩阵未对齐。

import numpy as np
import numpy.linalg as LA
l=[[0.483, 0.923], [0.781, 0.188], [0.446, 0.564, 0.796]]
cx = lambda a, b : round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 2)
for v in l:
   for y in l:
    cosine=cx(v,y)
    print cosine

在将数组调整为相等长度(l=[[0.483, 0.923], [0.781, 0.188], [0.446, 0.564]])时,我的代码运行良好。

现在的问题是如何在不调整数组形状的情况下使我的代码工作?(即如何对齐矩阵)。感谢您的任何建议。

4

1 回答 1

3

由于您使用的是余弦相似度,因此似乎应该对a和进行几何解释b。(余弦相似度是找到两个向量之间夹角的余弦)。

长度为 2 的向量可以认为存在于 中xy-plane,长度为 3 的向量可以认为存在于 中xyz-space。所以平面中的向量可以被认为是 中的[0.4, 0.9]3 维向量[0.4, 0.9, 0]xyz-space

如果这是合理的,那么取 2D 向量和 3D 向量之间的内积相当于在简单地删除第三个分量后取内积(因为任何乘以 0 为 0)。

因此,您可以这样定义cx

def cx(a, b) :
    a, b = (a, b) if len(a) < len(b) else (b, a)
    b = b[:len(a)]
    try:
        assert any(a)
        assert any(b)
    except AssertionError:
        print('either a or b is zero')
        # return 0  or 
        # raise 
    return round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 2)

通过填充缺失值,您将获得更好的性能,l以便将其制成 NumPy 数组。然后您可以一次将 NumPy 操作应用于整个数组并消除双 Python for-loops

def cosine_similarity(l):
    inner = np.einsum('ij,kj -> ik', l, l)
    norm = np.sqrt(np.einsum('ij -> i', l*l))
    return inner/(norm*norm[:, np.newaxis])

def to_3d(l):
    return np.array([row+[0]*(3-len(row)) for row in l])

np.set_printoptions(precision=2)
print(cosine_similarity(to_3d(l)))

产量

[[ 1.    0.66  0.66]
 [ 0.66  1.    0.53]
 [ 0.66  0.53  1.  ]]

和....相比

def cx(a, b) :
    a, b = (a, b) if len(a) < len(b) else (b, a)
    b = b[:len(a)]
    return round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 2)

def using_cx():
    for v in l:
       for y in l:
        cosine=cx(v,y)

timeit 显示速度提高了 11 倍:

In [90]: %timeit using_cx()
1000 loops, best of 3: 380 us per loop

In [91]: %timeit cosine_similarity(to_3d(l))
10000 loops, best of 3: 32.6 us per loop

计算仍然是二次方的——如果您希望比较l. 但它更快,因为 NumPy 函数是用 C 编写的,这往往比在 Python 循环中调用 Python 函数的等效代码更快。

于 2013-07-30T12:14:07.600 回答