Создать блок диагональный массив numpy из заданного массива numpy
у меня есть 2-мерный массив NumPy с равным количеством столбцов и строк. Я хотел бы расположить их в больший массив, имеющий меньшие по диагонали. Должна быть возможность указать, как часто стартовая матрица должна быть по диагонали. Например:
a = numpy.array([[5, 7],
[6, 3]])
поэтому, если бы я хотел, чтобы этот массив 2 раза по диагонали, желаемый результат был бы:
array([[5, 7, 0, 0],
[6, 3, 0, 0],
[0, 0, 5, 7],
[0, 0, 6, 3]])
3 раза:
array([[5, 7, 0, 0, 0, 0],
[6, 3, 0, 0, 0, 0],
[0, 0, 5, 7, 0, 0],
[0, 0, 6, 3, 0, 0],
[0, 0, 0, 0, 5, 7],
[0, 0, 0, 0, 6, 3]])
есть ли быстрый способ реализовать это с методы numpy и для произвольных размеров начального массива (все еще считая, что начальный массив имеет одинаковое количество строк и столбцов)?
2 ответов
классический случай numpy.kron
-
np.kron(np.eye(n), a)
образец выполнения -
In [57]: n = 2
In [58]: np.kron(np.eye(n), a)
Out[58]:
array([[ 5., 7., 0., 0.],
[ 6., 3., 0., 0.],
[ 0., 0., 5., 7.],
[ 0., 0., 6., 3.]])
In [59]: n = 3
In [60]: np.kron(np.eye(n), a)
Out[60]:
array([[ 5., 7., 0., 0., 0., 0.],
[ 6., 3., 0., 0., 0., 0.],
[ 0., 0., 5., 7., 0., 0.],
[ 0., 0., 6., 3., 0., 0.],
[ 0., 0., 0., 0., 5., 7.],
[ 0., 0., 0., 0., 6., 3.]])
import numpy as np
from scipy.linalg import block_diag
a = np.array([[5, 7],
[6, 3]])
n = 3
d = block_diag(*([a] * n))
d
array([[5, 7, 0, 0, 0, 0],
[6, 3, 0, 0, 0, 0],
[0, 0, 5, 7, 0, 0],
[0, 0, 6, 3, 0, 0],
[0, 0, 0, 0, 5, 7],
[0, 0, 0, 0, 6, 3]], dtype=int32)
но это похоже на np.решение kron немного быстрее для небольших n.
%timeit np.kron(np.eye(n), a)
12.4 µs ± 95.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit block_diag(*([a] * n))
19.2 µs ± 34.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
однако для n = 300, например, block_diag намного быстрее:
%timeit block_diag(*([a] * n))
1.11 ms ± 32.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit np.kron(np.eye(n), a)
4.87 ms ± 31 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)