我需要计算两组向量之间的成对距离,但我只需要知道这些成对距离的一小部分,当我的两组向量足够大时,这个比例将小于0.01。
这是我当前的解决方案,其中包含一个小示例。A
和B
是两组向量,M
存储我需要保留的向量对。A
和B
中的行数通常要大得多还值得一提的是,M
在每行中至少有一个非零值,但某些列可能只包含零。
import numpy as np
A = np.array([[1, 2], [2, 3], [3, 4]]) # (3, 2)
B = np.array([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]) # (5, 2)
M = np.array([[0, 0, 0, 1, 0], [1, 1, 0, 0, 0], [0, 0, 0, 0, 1]]) # (3, 5)
diff = A[:,None] - B[None,:] # (3, 5, 2)
distances = np.linalg.norm(diff, ord=2, axis=2) # (3, 5)
masked_distances = distances * M # (3, 5)
字符串
这段代码可以工作,但是它计算了很多我不需要的范数,所以它执行了很多不必要的计算,特别是当A
和B
变得更大的时候。有没有更有效的方法来只计算我需要的范数?我愿意接受其他软件包的建议。
我曾考虑过使用稀疏数组来计算masked_distances
,但我在scipy中使用超过2维的稀疏数组(即diff
)时遇到了问题。
我也试过创建一个向量化函数,这也是可行的,但是当A
和B
增长到有数千条记录时,速度会更慢。
def conditional_diff(a, b, m):
if m:
return a-b
else:
return 0
conditional_diff_vec = np.vectorize(conditional_diff, otypes=[float])
masked_diff = conditional_diff_vec(A[:,None], B[None,:], M[:,:,None])
masked_distances = norm(masked_diff, ord=2, axis=2)
型
1条答案
按热度按时间lxkprmvk1#
我会用numba构造一个Compressed Sparse Row matrix来解决这个问题。CSR矩阵允许我避免使用内存来表示矩阵中的许多零。
Numba允许我使用显式循环而不会损失太多性能。这允许我使用
if
来避免计算未使用的距离。字符串
几点注意事项:
np.linalg.norm(A[i] - B[i])
快,但仍然返回相同的结果,这就是为什么euclidean_distance()
函数存在的原因。masked_distance()
负责设置算法。masked_distance_inner()
是所有速度关键的东西。型
确切的加速比取决于所涉及的矩阵的大小和掩码的稀疏程度。例如,我对长度为1000的向量进行了基准测试,发现了1000倍的加速比。
np.allclose()
检查了这个算法与原始算法的正确性。float32
代替float64
。如果你知道矩阵的维数小于231,并且定义的元素永远不会超过231,你可以用int32
代替int64
。