【发布时间】:2019-06-24 12:55:45
【问题描述】:
我想仅针对特定索引有效地计算两个低秩矩阵 A 和 B 的点积。通常,A 和 B 的形状为 (100, 10000),我只想获得 A.T @ B 条目的 1%。
我已经尝试使用 Numba 库,但它似乎比计算密集点积 np.dot(A.T, B) 慢得多。
【问题讨论】:
我想仅针对特定索引有效地计算两个低秩矩阵 A 和 B 的点积。通常,A 和 B 的形状为 (100, 10000),我只想获得 A.T @ B 条目的 1%。
我已经尝试使用 Numba 库,但它似乎比计算密集点积 np.dot(A.T, B) 慢得多。
【问题讨论】:
你可以使用einsum:
import numpy as np
def direct():
return (A.T@B)[iy, ix]
def einsum():
return np.einsum('ij,ij->j',A[:,iy],B[:,ix])
def make(M,N,p):
global A,B,iy,ix
A,B = (np.random.randint(0,10,(M,N)) for _ in "AB")
iy,ix = np.random.randint(0,N,(2,int(N*N*p)))
from time import time
make(100,10000,0.01)
T=[]
T.append(time())
d = direct()
T.append(time())
e = einsum()
T.append(time())
print("results equal: ",np.allclose(d,e))
print("direct {:.6f} einsum {:.6f}".format(*np.diff(T)))
示例运行:
results equal: True
direct 18.463711 einsum 1.947425
【讨论】:
如果您想要点积的结果数组的子集,只需在使用点之前获取子集。即,如果您想要输出的“左上”10x10 矩阵,只需执行
np.dot(A.T[:10,:], B[:, :10])
如果你想要一些特定的索引,你可以使用更花哨的索引。例如,如果你想要索引 3、5 和 29,你可以这样做:
indices = np.array([3, 5, 29]).reshape(-1, 1)
inner_all = np.arange(A.shape[0]).reshape(-1, 1)
result = np.dot(A.T[indices, inner_all.T], B[inner_all, indices.T])
如果您只需要第一行的第 1、3 和 5 列:
rows = np.array([1]).reshape(-1, 1)
columns = rows = np.array([1, 3, 5]).reshape(-1, 1)
inner_all = np.arange(A.shape[0]).reshape(-1, 1)
result = np.dot(A.T[rows, inner_all.T], B[inner_all, columns.T])
【讨论】: