首页 > 解决方案 > 带有 3d 数组的 Numpy 点积

问题描述

我有两个数组:

我想得到等于预期回报的点积,即returns每个asset乘以correlation_matrix. 它应该给出与 相同的形状data

我试过了:

data.transpose([1, 2, 0]) @ correlation_matrix

但这只是挂起我的电脑(已经运行了 10 分钟并数着数)。

我也试过:

np.einsum('ijk,lm->ijk', data, correlation_matrix)

但我不太熟悉einsum,这也挂起。

我究竟做错了什么?

标签: numpy

解决方案


使用您的.transpose((1, 2, 0))数据,正确的形式是:

"ijs,sk"  # -> ijk

因为对于张量AB,我们可以写:

C_{ijk} = Σ_s A_{ijs} * B_{sk}

如果您想避免事先转置数据,您可以置换索引:

"sij,sk"  # -> ijk

验证:

p, q, r = 2466, 2498, 9

a = np.random.randint(255, size=(p, q, r))
b = np.random.randint(255, size=(p, p))

c1 = a.transpose((1, 2, 0)) @ b
c2 = np.einsum("sij,sk", a, b)

>>> np.all(c1 == c2)
True

计算shape所需的乘法量为. 在你的情况下,那是乘法。您还需要大约相同数量的添加,这样我们就可以进行近 2700 亿次操作。如果您想要更快的速度,您可以考虑通过cupy使用 GPU 进行计算。(p, q, r)datap * np.prod(c.shape) == p * (q * r * p) == p**2 * q * r136_716_549_192

def with_np():
    p, q, r = 2466, 2498, 9
    a = np.random.randint(255, size=(p, q, r))
    b = np.random.randint(255, size=(p, p))
    c1 = a.transpose((1, 2, 0)) @ b
    c2 = np.einsum("sij,sk", a, b)

def with_cp():
    p, q, r = 2466, 2498, 9
    a = cp.random.randint(255, size=(p, q, r))
    b = cp.random.randint(255, size=(p, p))
    c1 = a.transpose((1, 2, 0)) @ b
    c2 = cp.einsum("sij,sk", a, b)

>>> timeit(with_np, number=1)
513.066

>>> timeit(with_cp, number=1)
0.197

这是 2600 倍的加速,包括内存分配、初始化和 CPU/GPU 复制时间!(更现实的基准会提供更大的加速。)


推荐阅读