由于您使用的是余弦相似度,因此似乎应该对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 函数的等效代码更快。