python - 子数组的总和

标签 python optimization numpy

我有一个二维整数数组,我想求和它的二维子数组。两个数组都可以具有任意维度,尽管我们可以假设子数组将比总数组小几个数量级。

python 中的引用实现很简单:

def sub_sums(arr, l, m):
    result = np.zeros((len(arr) // l, len(arr[0]) // m))
    rows = len(arr) // l * l
    cols = len(arr[0]) // m * m
    for i in range(rows):
        for j in range(cols):
            result[i // l, j // m] += arr[i, j]
    return result

问题是我如何使用 numpy 做到最好,希望在 python 中完全没有任何循环。对于 1d 数组 cumsumr_ 可以工作,我可以使用它和一些循环来实现 2d 的解决方案,但我仍在学习 numpy 并且我正在几乎可以肯定有一些更聪明的方法。

示例输出:

arr = np.asarray([range(0, 5),
                  range(4, 9),
                  range(8, 13),
                  range(12, 17)])
result = sub_sums(arr, 2, 2)

给出:

[[ 0  1  2  3  4]
 [ 4  5  6  7  8]
 [ 8  9 10 11 12]
 [12 13 14 15 16]]

[[ 10.  18.]
 [ 42.  50.]]

最佳答案

有一个blockshaped function它做的事情非常接近你想要的:

In [81]: arr
Out[81]: 
array([[ 0,  1,  2,  3,  4],
       [ 4,  5,  6,  7,  8],
       [ 8,  9, 10, 11, 12],
       [12, 13, 14, 15, 16]])

In [82]: blockshaped(arr[:,:4], 2,2)
Out[82]: 
array([[[ 0,  1],
        [ 4,  5]],

       [[ 2,  3],
        [ 6,  7]],

       [[ 8,  9],
        [12, 13]],

       [[10, 11],
        [14, 15]]])

In [83]: blockshaped(arr[:,:4], 2,2).shape
Out[83]: (4, 2, 2)

一旦你有了“blockshaped”数组,你就可以通过整形(所以一个 block 中的数字沿着一个轴排列)然后调用 sum 方法来获得所需的结果轴。

因此,通过对 blockshaped 函数稍作修改,您可以像这样定义 sub_sums:

import numpy as np

def sub_sums(arr, nrows, ncols):
    h, w = arr.shape
    h = (h // nrows)*nrows
    w = (w // ncols)*ncols
    arr = arr[:h,:w]
    return (arr.reshape(h // nrows, nrows, -1, ncols)
               .swapaxes(1, 2)
               .reshape(h // nrows, w // ncols, -1).sum(axis=-1))

arr = np.asarray([range(0, 5),
                  range(4, 9),
                  range(8, 13),
                  range(12, 17)])

print(sub_sums(arr, 2, 2))

产量

[[10 18]
 [42 50]]

编辑:Ophion 提供了一个很好的改进——在求和之前使用 np.einsum 而不是 reshape :

def sub_sums_ophion(arr, nrows, ncols):
    h, w = arr.shape
    h = (h // nrows)*nrows
    w = (w // ncols)*ncols
    arr = arr[:h,:w]
    return np.einsum('ijkl->ik', arr.reshape(h // nrows, nrows, -1, ncols))

In [105]: %timeit sub_sums(arr, 2, 2)
10000 loops, best of 3: 112 µs per loop

In [106]: %timeit sub_sums_ophion(arr, 2, 2)
10000 loops, best of 3: 76.2 µs per loop

关于python - 子数组的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21220942/

相关文章:

python - 为什么我的 "def __str__(self)"函数在 Django 中不起作用

python - 如何在python中解析wordpress分类数据库内容

android - 将 Android RelativeLayout 与 Gone Views 相结合

c++ - 添加与比较

python - 预期是二维数组,却得到了一维数组, reshape 数据

python - Theano 元素明智的最大值

Python读取文本文件并保持打开状态

python - 如何在 Flask 中传递 "WTF object"

python - 在 lmfit 中,minimum() 和residual() 函数如何协同工作

python - OpenCV 估计 Affine3D 失败并显示神秘的错误消息