带3d阵列的Numpy点积

带3d阵列的Numpy点积,numpy,Numpy,我有两个阵列: 形状(2466、2498、9)的数据,其中尺寸为(资产、日期、返回) 形状的相关矩阵(24662466)(对角线上有0) 我想得到与预期收益相等的点积,即每个资产的收益乘以相关矩阵。它应该给出与数据相同的形状 我试过: data.transpose([1, 2, 0]) @ correlation_matrix 但这只是挂起我的电脑(一直持续了10分钟,而且还在计算) 我还尝试: np.einsum('ijk,lm->ijk', data, correlation_m

我有两个阵列:

  • 形状
    (2466、2498、9)
    数据
    ,其中尺寸为
    (资产、日期、返回)
  • 形状的相关矩阵(24662466)(对角线上有0)
我想得到与预期收益相等的点积,即每个
资产的
收益
乘以
相关矩阵
。它应该给出与
数据
相同的形状

我试过:

data.transpose([1, 2, 0]) @ correlation_matrix
但这只是挂起我的电脑(一直持续了10分钟,而且还在计算)

我还尝试:

np.einsum('ijk,lm->ijk', data, correlation_matrix)
但是我对einsum不太熟悉,这也挂起了

我做错了什么?

对于您的
.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)
shaped
数据的乘法量是
p*np.prod(c.shape)==p*(q*r*p)==p**2*q*r
。在您的例子中,这是
136\u716\u549\u192
乘法。您还需要大约相同数量的新增设备,因此我们的运营规模接近2700亿。如果你想要更多的速度,你可以考虑使用GPU来进行计算。 这是2600的加速,包括内存分配、初始化和CPU/GPU复制时间!(一个更现实的基准测试会带来更大的加速。)

使用
.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)
shaped
数据的乘法量是
p*np.prod(c.shape)==p*(q*r*p)==p**2*q*r
。在您的例子中,这是
136\u716\u549\u192
乘法。您还需要大约相同数量的新增设备,因此我们的运营规模接近2700亿。如果你想要更多的速度,你可以考虑使用GPU来进行计算。
这是2600的加速,包括内存分配、初始化和CPU/GPU复制时间!(更现实的基准会带来更大的加速。)

有不同的方法来实现此产品:

# 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

使用此产品有不同的方法:

# 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

假设你的
einsum
有效,你可以只做
data*correlation\u matrix.sum()
。如果事情悬而未决或耗时太长,请后退一步,测试更小的东西。在用大数组强调内存之前,请确保代码对小数组执行了您想要的操作。您的
einsum
只需对
correlation\u matrix
的所有值求和,然后将
data
乘以结果标量。这可能不是你想要的。假设你的
einsum
有效,你可以只做
data*correlation\u matrix.sum()
。如果事情悬而未决或耗时过长,请后退一步,测试更小的东西。在用大数组强调内存之前,请确保代码对小数组执行了您想要的操作。您的
einsum
只需对
correlation\u matrix
的所有值求和,然后将
data
乘以结果标量。这可能不是你想要的。哇,这真是难以置信的加速!你有什么样的GPU?这可能值得投资;)@cjm2671有点“过时”——NVIDIA GTX 1060 6GB(5年前购买时为300美元)。不过,你可能会以比现在出售的这张卡更便宜的价格买到一款更新的图形卡。如果你想要CUDA计算,我建议你坚持使用NVIDIA。好吧,看起来他们在易趣上现在大约30美元,这似乎是一项值得投资的投资!谢谢!:)哇,真是难以置信的加速!你有什么样的GPU?这可能值得投资;)@cjm2671有点“过时”——NVIDIA GTX 1060 6GB(5年前购买时为300美元)。不过,你可能会以比现在出售的这张卡更便宜的价格买到一款更新的图形卡。如果你想要CUDA计算,我建议你坚持使用NVIDIA。好吧,看起来他们在易趣上现在大约30美元,这似乎是一项值得投资的投资!谢谢!:)