我有两个数组:
data
的{{1}},其中尺寸为(2466, 2498, 9)
。(asset, date, returns)
的形状correlation_matrix
(对角线为0)我想得到等于预期收益的点积,即每个(2466, 2466)
的{{1}}乘以returns
。它的形状应与asset
相同。
我尝试过:
correlation_matrix
但这只是挂起了我的PC(经过10分钟并开始计数)。
我也尝试过:
data
但是我对data.transpose([1, 2, 0]) @ correlation_matrix
不太熟悉,并且它也挂起了。
我在做什么错了?
答案 0 :(得分:2)
使用您的.transpose((1, 2, 0))
数据,正确的格式为:
"ijs,sk" # -> ijk
由于有了张量A
和B
,我们可以这样写:
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
计算(p, q, r)
形data
所需的乘法的数量为p * np.prod(c.shape) == p * (q * r * p) == p**2 * q * r
。在您的情况下,就是136_716_549_192
乘法。您还需要大约相同数量的加法,因此使我们的操作量接近2700亿次。如果您想提高速度,可以考虑通过cupy使用GPU进行计算。
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复制时间在内的! (更现实的基准将提供更大的加速。)
答案 1 :(得分:1)
有多种方法可以制作此产品:
# as you already suggested:
data.transpose([1, 2, 0]) @ correlation_matrix
# using einsum
np.einsum('ijk,il', data, correlation_matrix)
# using tensordot to explicitly specify the axes to sum over
np.tensordot(data, correlation_matrix, axes=(0,0))
所有这些都应给出相同的结果。对于我来说,一些小型矩阵的时间大致相同。因此,您的问题在于大量数据,而不是效率低下的实现。
A=np.arange(100*120*9).reshape((100, 120, 9))
B=np.arange(100**2).reshape((100,100))
timeit('A.transpose([1,2,0])@B', globals=globals(), number=100)
# 0.747475513999234
timeit("np.einsum('ijk,il', A, B)", globals=globals(), number=100)
# 0.4993825999990804
timeit('np.tensordot(A, B, axes=(0,0))', globals=globals(), number=100)
# 0.5872082839996438