numpy 不使用循环对矩阵中每3个元素求和的优化方法

jtw3ybtb  于 2023-11-18  发布在  其他
关注(0)|答案(4)|浏览(176)

的阵列的示例

array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 2,  6,  8,  3,  5,  6,  8,  9,  1,  2]])

字符串
我想要一种不使用循环而得到这个结果的有效方法:

result = array([[6, 9, 12, 15, 18, 21, 24, 27],
       [16, 17, 16, 14, 19, 23, 18, 12]])


其中前3个元素被求和(1+2+3),然后求和(2+3+4),依此类推。

i7uaboj4

i7uaboj41#

Numpy包含滑动窗口视图:

from numpy.lib.stride_tricks import sliding_window_view

x = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 6, 8, 3, 5, 6, 8, 9, 1, 2]])

out = sliding_window_view(x, 3, axis=-1).sum(axis=-1)
print(out)

字符串
打印:

[[ 6  9 12 15 18 21 24 27]
 [16 17 16 14 19 23 18 12]]

um6iljoc

um6iljoc2#

对于每3个元素的特定情况,以下1行代码就足够了

result = arr[:, :-2] + arr[:, 1:-1] + arr[:, 2:]

字符串
但是,对于每个n元素的更一般情况,请考虑以下内容

n = 3
arr = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                [2, 6, 8, 3, 5, 6, 8, 9, 1, 2]])


我们可以先求出所有行的累计和

row_cumsum = np.cumsum(arr, axis=1)
# [[ 1  3  6 10 15 21 28 36 45 55]
#  [ 2  8 16 19 24 30 38 47 48 50]]


创建一个数组,该数组在此累积数组的开始处有一列为0,但没有最后n

trimmed = np.hstack((np.zeros((row_cumsum.shape[0], 1), dtype=int), row_cumsum[:,:-n]))
# [[ 0  1  3  6 10 15 21 28]
#  [ 0  2  8 16 19 24 30 38]]


然后简单地从我们的累积数组的第n列减去这个修剪数组

results =  row_cumsum[:, n-1:] - trimmed
# [[ 6 10 15 21 28 36 45 55]      [[ 0  1  3  6 10 15 21 28]
#  [16 19 24 30 38 47 48 50]]  -   [ 0  2  8 16 19 24 30 38]]
#
# = [[ 6  9 12 15 18 21 24 27]
#    [16 17 16 14 19 23 18 12]]

kx1ctssn

kx1ctssn3#

a = np.array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 2,  6,  8,  3,  5,  6,  8,  9,  1,  2]])

字符串
您可以通过以下方式获取元素:

first_value = tuple(zip(a[0],a[0][1:],a[0][2:]))

((1, 2, 3),
 (2, 3, 4),
 (3, 4, 5),
 (4, 5, 6),
 (5, 6, 7),
 (6, 7, 8),
 (7, 8, 9),
 (8, 9, 10))

list(map(sum, first_value))
#[6, 9, 12, 15, 18, 21, 24, 27]

x

second_value = tuple(zip(a[1],a[1][1:],a[1][2:]))

((2, 6, 8),
 (6, 8, 3),
 (8, 3, 5),
 (3, 5, 6),
 (5, 6, 8),
 (6, 8, 9),
 (8, 9, 1),
 (9, 1, 2))

list(map(sum, second_value))
#[16, 17, 16, 14, 19, 23, 18, 12]
np.array([list(map(sum, first_value)),list(map(sum, second_value))])
#array([[ 6,  9, 12, 15, 18, 21, 24, 27],
       [16, 17, 16, 14, 19, 23, 18, 12]])

的字符串
方法二:
使用numpy slicing:
第一元件

a[0][:-2] + a[0][1:][:-1] + a[0][2:]

#output
array([ 6,  9, 12, 15, 18, 21, 24, 27])


二元件

a[1][:-2] + a[1][1:][:-1] + a[1][2:]

#output
array([16, 17, 16, 14, 19, 23, 18, 12])


或者正如@Ignatius所建议的那样

a[:,:-2] + a[:,1:-1] + a[:,2:]

#output
array([[ 6,  9, 12, 15, 18, 21, 24, 27],
       [16, 17, 16, 14, 19, 23, 18, 12]])

e3bfsja2

e3bfsja24#

您可以使用bottleneck库,如Numpy sliding_window_view()文档中的注解所建议:

>>> a = np.array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
...               [ 2,  6,  8,  3,  5,  6,  8,  9,  1,  2]])
>>> bottleneck.move_sum(a, 3)
array([[nan, nan,  6.,  9., 12., 15., 18., 21., 24., 27.],
       [nan, nan, 16., 17., 16., 14., 19., 23., 18., 12.]])

字符串
或者,如果您想要精确的输出类型和大小:

>>> bottleneck.move_sum(a, 3)[:,2:].astype(int)
array([[ 6,  9, 12, 15, 18, 21, 24, 27],
       [16, 17, 16, 14, 19, 23, 18, 12]])


缺点:返回一个由NaN填充的相同大小的浮点数数组。
优点:Neat. Very fast:

>>> %timeit sliding_window_view(a, 3, axis=-1).sum(axis=-1)
19.4 µs ± 489 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
>>> %timeit a[:,:-2] + a[:,1:-1] + a[:,2:]
2.31 µs ± 138 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
>>> %timeit bottleneck.move_sum(a, 3)[:,2:].astype(int)
776 ns ± 2.32 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
>>> %timeit bottleneck.move_sum(a, 3)
254 ns ± 40.8 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

相关问题