如何在numpy,scipy中进行多维矩阵乘法

时间:2016-07-28 19:25:03

标签: python numpy matrix scipy

我有一个形状为(8,9)的scipy稀疏矩阵和另一个形状为(9,12,17)的数组。我希望将这些乘以这样我得到一个大小为矩阵/数组(8,12,17),其中(8,9)矩阵实际上只乘以第一维。我是否必须使用Kronecker产品才能做到这一点,或者是否有一种简单的方法?

4 个答案:

答案 0 :(得分:2)

如果m1是2d稀疏矩阵,则m1.A是其密集数组形式。实际上,dinmensions写了einsum表达式。

np.einsum('ij,jkl->ikl', m1.A, m2)

例如:

In [506]: M = sparse.random(8, 9, 0.1)
In [507]: A = np.ones((9, 12, 17))
In [508]: np.einsum('ij,jkl->ikl', M.A, A).shape
Out[508]: (8, 12, 17)

答案 1 :(得分:1)

正如hpaulj在评论中所说,最简单的方法是使用密集矩阵np.einsum

>>> a = np.random.randn(8, 9)
>>> b = np.random.randn(9, 12, 17)
>>> c = np.einsum('ij,jkl->ikl', a, b)
>>> c.shape
(8, 12, 17)

答案 2 :(得分:1)

@Divakar建议np.tensordot,@ hpaulj和@Praveen建议np.einsum。另一种方法是转置轴:

(a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))

对于您引用的小尺寸,np.einsum和换位似乎更快。但是一旦你开始按比例增加轴的尺寸,np.tensordot就会胜过另外两个。

import numpy as np

m, n, k, l = 8, 9, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))

%timeit np.tensordot(a, b, axes=([1], [0]))
# => 10000 loops, best of 3: 22 µs per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 100000 loops, best of 3: 10.1 µs per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 100000 loops, best of 3: 11.1 µs per loop

m, n, k, l = 8, 900, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))

%timeit np.tensordot(a, b, axes=([1], [0]))
# => 1000 loops, best of 3: 198 µs per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 1000 loops, best of 3: 868 µs per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 1000 loops, best of 3: 907 µs per loop

m, n, k, l = 8, 90000, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))

%timeit np.tensordot(a, b, axes=([1], [0]))
# => 10 loops, best of 3: 21.7 ms per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 10 loops, best of 3: 164 ms per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 10 loops, best of 3: 166 ms per loop

答案 3 :(得分:0)

以下是我可以使用它的几种方法。第二个似乎更好,我测试时快了大约12倍。

def multiply_3D_dim_zero_slow(matrix, array):
shape = array.shape
final_shape = (matrix.shape[0], array.shape[1], array.shape[2])
result = np.zeros(final_shape)
for i in xrange(shape[1]):
    for j in xrange(shape[2]):
        result[:, i, j] = matrix * array[:, i, j]
return result.reshape(final_shape)

这是一个更快的版本,它使用reshape将多维数组转换为2D数组。

def multiply_3D_dim_zero(matrix, array):
shape = array.shape
final_shape = (matrix.shape[0], array.shape[1], array.shape[2])
array_reshaped = array.reshape(shape[0], shape[1] * shape[2])
return (matrix * array_reshaped).reshape(final_shape)ode here

这只适用于第一个维度,这是我需要的,但可以概括。