Inv*_*anz 11 python arrays numpy
我有一个二维numpy数组,列数和行数相同.我想把它们安排成一个更大的阵列,在对角线上有较小的阵列.应该可以指定起始矩阵在对角线上的频率.例如:
a = numpy.array([[5, 7],
[6, 3]])
Run Code Online (Sandbox Code Playgroud)
所以,如果我想在对角线上对这个数组进行2次,那么所需的输出将是:
array([[5, 7, 0, 0],
[6, 3, 0, 0],
[0, 0, 5, 7],
[0, 0, 6, 3]])
Run Code Online (Sandbox Code Playgroud)
三次:
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]])
Run Code Online (Sandbox Code Playgroud)
有没有一种快速的方法来实现这个与numpy方法和任意大小的起始数组(仍然考虑起始数组具有相同数量的行和列)?
Div*_*kar 17
经典案例numpy.kron-
np.kron(np.eye(r,dtype=int),a) # r is number of repeats
Run Code Online (Sandbox Code Playgroud)
样品运行 -
In [184]: a
Out[184]:
array([[1, 2, 3],
[3, 4, 5]])
In [185]: r = 3 # number of repeats
In [186]: np.kron(np.eye(r,dtype=int),a)
Out[186]:
array([[1, 2, 3, 0, 0, 0, 0, 0, 0],
[3, 4, 5, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 2, 3, 0, 0, 0],
[0, 0, 0, 3, 4, 5, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 2, 3],
[0, 0, 0, 0, 0, 0, 3, 4, 5]])
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
但看起来 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)
Run Code Online (Sandbox Code Playgroud)
但是,例如,对于 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)
Run Code Online (Sandbox Code Playgroud)
对于矩阵的特殊情况,简单的切片比(最慢的)快得多,numpy.kron()并且大部分与numpy.einsum()基于 - 的方法(来自@Divakar 答案)相当。与 相比scipy.linalg.block_diag(),它对于较小的 ,表现更好arr,在某种程度上与块重复次数无关。
block_diag_view()请注意,使用 Numba 可以轻松地进一步提高较小输入的性能,但对于较大输入,性能会更差。
使用 Numba,完全显式循环和并行化 ( block_diag_loop_jit()) 会再次得到类似的结果,就好像block_diag_einsum()重复次数很少一样。
总体而言,性能最佳的解决方案是block_diag_einsum()和block_diag_view()。
import numpy as np
import scipy as sp
import numba as nb
import scipy.linalg
NUM = 4
M = 9
def block_diag_kron(arr, num=NUM):
return np.kron(np.eye(num), arr)
def block_diag_einsum(arr, num=NUM):
rows, cols = arr.shape
result = np.zeros((num, rows, num, cols), dtype=arr.dtype)
diag = np.einsum('ijik->ijk', result)
diag[:] = arr
return result.reshape(rows * num, cols * num)
def block_diag_scipy(arr, num=NUM):
return sp.linalg.block_diag(*([arr] * num))
def block_diag_view(arr, num=NUM):
rows, cols = arr.shape
result = np.zeros((num * rows, num * cols), dtype=arr.dtype)
for k in range(num):
result[k * rows:(k + 1) * rows, k * cols:(k + 1) * cols] = arr
return result
@nb.jit
def block_diag_view_jit(arr, num=NUM):
rows, cols = arr.shape
result = np.zeros((num * rows, num * cols), dtype=arr.dtype)
for k in range(num):
result[k * rows:(k + 1) * rows, k * cols:(k + 1) * cols] = arr
return result
@nb.jit(parallel=True)
def block_diag_loop_jit(arr, num=NUM):
rows, cols = arr.shape
result = np.zeros((num * rows, num * cols), dtype=arr.dtype)
for k in nb.prange(num):
for i in nb.prange(rows):
for j in nb.prange(cols):
result[i + (rows * k), j + (cols * k)] = arr[i, j]
return result
Run Code Online (Sandbox Code Playgroud)
基准NUM = 4:
基准NUM = 400:
绘图是使用以下附加代码从此模板生成的:
def gen_input(n):
return np.random.randint(1, M, (n, n))
def equal_output(a, b):
return np.all(a == b)
funcs = block_diag_kron, block_diag_scipy, block_diag_view, block_diag_jit
input_sizes = tuple(int(2 ** (2 + (3 * i) / 4)) for i in range(13))
print('Input Sizes:\n', input_sizes, '\n')
runtimes, input_sizes, labels, results = benchmark(
funcs, gen_input=gen_input, equal_output=equal_output,
input_sizes=input_sizes)
plot_benchmarks(runtimes, input_sizes, labels, units='ms')
Run Code Online (Sandbox Code Playgroud)
(编辑包括np.einsum()基于 的方法和另一个具有显式循环的 Numba 版本。)
| 归档时间: |
|
| 查看次数: |
4680 次 |
| 最近记录: |