3

The problem is very similar to that in How to evaluate the sum of values within array blocks, where I need to sum up elements in a matrix by blocks. What is different here is that the blocks could have different sizes. For example, given a 4-by-5 matrix

1 1 | 1 1 1
----|------
1 1 | 1 1 1
1 1 | 1 1 1
1 1 | 1 1 1

and block sizes 1 3 along the rows and 2 3 along the columns, the result should be a 2-by-2 matrix:

2 3
6 9

Is there a way of doing this without loops?

Rainn
  • 315
  • 1
  • 9

1 Answers1

2

Seems like a good fit to use np.add.reduceat to basically sum along rows and then along cols -

def sum_blocks(a, row_sizes, col_sizes):
    # Sum rows based on row-sizes
    s1 = np.add.reduceat(a,np.r_[0,row_sizes[:-1].cumsum()],axis=0)

    # Sum cols from row-summed output based on col-sizes
    return np.add.reduceat(s1,np.r_[0,col_sizes[:-1].cumsum()],axis=1)

Sample run -

In [45]: np.random.seed(0)
    ...: a = np.random.randint(0,9,(4,5))

In [46]: a
Out[46]: 
array([[5, 0, 3, 3, 7],
       [3, 5, 2, 4, 7],
       [6, 8, 8, 1, 6],
       [7, 7, 8, 1, 5]])

In [47]: row_sizes = np.array([1,3])
    ...: col_sizes = np.array([2,3])

In [48]: sum_blocks(a, row_sizes, col_sizes)
Out[48]: 
array([[ 5, 13],
       [36, 42]])
Divakar
  • 218,885
  • 19
  • 262
  • 358