我有一个二维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方法和起始数组的任意大小(仍然认为起始数组具有相同数量的行和列)是否有一种快速实现方法?
答案 0 :(得分:13)
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.]])
答案 1 :(得分:3)
private void addNewMarker(POI placeInfo){
mMap.setInfoWindowAdapter(new CustomInfoWindow(MapsActivity.this,placeInfo.getPhotos()));
try {
String snippet = "ID: " + placeInfo.getID() + "\nCategory: "+ placeInfo.getCategory();
mMarker = mMap.addMarker(new MarkerOptions()
.title(placeInfo.getPOI_name())
.position(new LatLng(placeInfo.getLatitude(),placeInfo.getLongitude()))
.snippet(snippet));
}catch (NullPointerException e){
Log.e(TAG, "moveCamera: NullPointerException thrown: " + e.getMessage() );
}
}
但看起来np.kron解决方案对于小n来说要快一点。
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)
然而,对于n = 300,例如,block_diag要快得多:
%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)
答案 2 :(得分:3)
对于矩阵的特殊情况,简单的切片比DataGrid
(最慢的)要快得多,并且大多与基于StructureID Target Val Measured Val
'A' 2 1.8
'A' 2 1.5
'B' 4 4.6
'C' 1 2.5
'C' 1 2.3
'C' 1 2.2
. . .
. . .
的方法(来自@Divakar答案)相当。
与 StructureID Correct Target Val
'A' 1.5
'B' 3.0
'C' 2.2
'D' 1.0
. .
. .
相比,它在较小的numpy.kron()
上表现更好,在某种程度上与块重复次数无关。
请注意,使用Numba可以轻松改善numpy.einsum()
在较小输入上的性能,但是对于较大输入,则性能会变差。
使用Numba,如果重复次数很少,则完全显式循环和并行化(scipy.linalg.block_diag()
)会再次获得与arr
类似的结果。
总体而言,性能最高的解决方案是block_diag_view()
和block_diag_loop_jit()
。
block_diag_einsum()
block_diag_einsum()
的基准:
block_diag_view()
的基准:
使用以下附加代码从this template生成了图:
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
(已编辑,包括基于NUM = 4
的方法和具有显式循环的另一个Numba版本。)