Blockwise Sum of Matrix Elements

Blockwise sum of matrix elements

You can use matrix multiplication for this.

# Computation matrix:

mat <- function(n, r) {
suppressWarnings(matrix(c(rep(1, r), rep(0, n)), n, n/r))
}

Square-matrix example, uses a matrix and its transpose on each side of a:

# Reduce a 4x4 matrix by a factor of 2:

x <- mat(4, 2)
x
## [,1] [,2]
## [1,] 1 0
## [2,] 1 0
## [3,] 0 1
## [4,] 0 1

t(x) %*% a %*% x
## [,1] [,2]
## [1,] 12 15
## [2,] 10 16

Non-square example:

b <- matrix(1:24, 4 ,6)
t(mat(4, 2)) %*% b %*% mat(6, 2)
## [,1] [,2] [,3]
## [1,] 14 46 78
## [2,] 22 54 86

Sum over blocks in a 2D matrix - MATLAB

An alternative way is to reshape the whole matrix into a 4D matrix and sum the elements over first and third dimension:

result = squeeze(sum(sum(reshape(A,26,189,26,189),1),3));

tensorflow: block-wise array/matrix sums

You can do it using tf.reshape and tf.reduce_sum as follows:

import tensorflow as tf
n=tf.constant([1,2,3,4,5,6])
res=tf.reduce_sum(tf.reshape(n,(3,2)),1)
sess=tf.Session()
res.eval(session=sess)

This prints array([ 3, 7, 11])

In the general case, if you want to get the sums of disjoint sequences of k elements, replace tf.reshape(n,(3,2)) with tf.reshape(n,(-1,k)). (The -1 will force it to specify the number of rows to n/k).

How to evaluate the sum of values within array blocks

Simply reshape splitting each of those two axes into two each with shape (5,20) to form a 4D array and then sum reduce along the axes having the lengths 20, like so -

Z_new = Z.reshape(5,20,5,20).sum(axis=(1,3))

Functionally the same, but potentially faster option with np.einsum -

Z_new = np.einsum('ijkl->ik',Z.reshape(5,20,5,20))

Generic block size

Extending to a generic case -

H,W = 5,5 # block-size
m,n = Z.shape
Z_new = Z.reshape(H,m//H,W,n//W).sum(axis=(1,3))

With einsum that becomes -

Z_new = np.einsum('ijkl->ik',Z.reshape(H,m//H,W,n//W))

To compute average/mean across blocks, use mean instead of sum method.

Generic block size and reduction operation

Extending to use reduction operations that have ufuncs supporting multiple axes parameter with axis for reductions, it would be -

def blockwise_reduction(a, height, width, reduction_func=np.sum):
m,n = a.shape
a4D = a.reshape(height,m//height,width,n//width)
return reduction_func(a4D,axis=(1,3))

Thus, to solve our specific case, it would be :

blockwise_reduction(Z, height=5, width=5)

and for a block-wise average computation, it would be -

blockwise_reduction(Z, height=5, width=5, reduction_func=np.mean)

How to dynamically reshape matrix block-wise?

Here's a vectorized approach with reshape and permute -

reshape(permute(reshape(a,size(a,1),4,[]),[1,3,2]),[],4)

Making it generic, we could introduce the number of columns as a parameter. Hence, let ncols be that one. So, the solution becomes -

ncols = 4
reshape(permute(reshape(a,size(a,1),ncols,[]),[1,3,2]),[],ncols)

Sample run -

>> a
a =
20 79 18 82 27 23 59 66 46 21 48 95
96 83 46 49 34 88 23 42 17 27 15 54
11 88 34 92 23 62 86 56 32 32 91 54
>> reshape(permute(reshape(a,size(a,1),4,[]),[1,3,2]),[],4)
ans =
20 79 18 82
96 83 46 49
11 88 34 92
27 23 59 66
34 88 23 42
23 62 86 56
46 21 48 95
17 27 15 54
32 32 91 54

More info on the intuition behind such a General idea for nd to nd transformation, which even though originally was meant for NumPy/Python, extends to any programming paradigm in general.

Shrink data.frame from 8x8 to 4x4 by taking 2x2 spatial averages

From linked post, using @flodel answer, replacing sum with mean:

a <- as.matrix(data)

#convert matrix from char to num, ignore warnings, they are due to NAs
class(a) <- "numeric"

#adapted from @flodel https://stackoverflow.com/a/16884987/680068
res <- tapply(a, list((row(a) + 1L) %/% 2L, (col(a) + 1L) %/% 2L), mean, na.rm = TRUE)

# remove NANs
res[ is.nan(res) ] <- NA
res
# 1 2 3 4
# 1 2 3.00 2.0 1.5
# 2 4 4.00 4.0 3.5
# 3 6 5.75 6.5 6.0
# 4 8 8.50 8.5 NA


Related Topics



Leave a reply



Submit