3

There are 2D arrays of numbers as outputs of some numerical processes in the form of 1x1, 3x3, 5x5, ... shaped, that correspond to different resolutions.

In a stage an average i.e., 2D array value in the shape nxn needs to be produced. If the outputs were in consistency of shape i.e., say all in 11x11 the solution was obvious, so:

element_wise_mean_of_all_arrays.

For the problem of this post however the arrays are in different shapes so the obvious way does not work!

I thought it might be some help by using kron function however it didn't. For example, if array is in shape of 17x17 how to make it 21x21. So for all others from 1x1,3x3,..., to build a constant-shaped array, say 21x21. Also it can be the case that the arrays are smaller and bigger in shape compared to the target shape. That is an array of 31x31 to be shruk into 21x21.

You could imagine the problem as a very common task for images, being shrunk or extended.

What are possible efficient approaches to do the same jobs on 2D arrays, in Python, using numpy, scipy, etc?

Updates: Here is a bit optimized version of the accepted answer bellow:


def resize(X,shape=None):
    if shape==None:
        return X
    m,n = shape
    Y = np.zeros((m,n),dtype=type(X[0,0]))
    k = len(X)
    p,q = k/m,k/n
    for i in xrange(m):
        Y[i,:] = X[i*p,np.int_(np.arange(n)*q)]
    return Y

It works perfectly, however do you all agree it is the best choice in terms of the efficiency? If not any improvement?


# Expanding ---------------------------------

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

>>> resize(X,[7,11])
[[1 1 1 1 2 2 2 2 3 3 3]
 [1 1 1 1 2 2 2 2 3 3 3]
 [1 1 1 1 2 2 2 2 3 3 3]
 [4 4 4 4 5 5 5 5 6 6 6]
 [4 4 4 4 5 5 5 5 6 6 6]
 [7 7 7 7 8 8 8 8 9 9 9]
 [7 7 7 7 8 8 8 8 9 9 9]]

# Shrinking ---------------------------------

>>> X = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]]

>>> resize(X,(2,2))
[[ 1  3]
 [ 9 11]]

Final note: that the code above easily could be translated to Fortran for the highest performance possible.

Developer
  • 8,258
  • 8
  • 49
  • 58

1 Answers1

2

I'm not sure I understand exactly what you are trying but if what I think the simplest way would be:

wanted_size = 21
a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
b = numpy.zeros((wanted_size, wanted_size))

for i in range(wanted_size):
    for j in range(wanted_size):
        idx1 = i * len(a) / wanted_size
        idx2 = j * len(a) / wanted_size
        b[i][j] = a[idx1][idx2]

You could maybe replace the b[i][j] = a[idx1][idx2] with some custom function like the average of a 3x3 matrix centered in a[idx1][idx2] or some interpolation function.

Bogdan
  • 8,017
  • 6
  • 48
  • 64
  • Thanks; your answer works well. I did some optimizations and put the new one (defined as a function) in the question. After a while if there was not a better solution in terms of the efficiency, this could be of course my choice. – Developer Jan 24 '12 at 10:43
  • I'm also curious of a more efficient way but I don't see a way you can build a n*m matrix where each element needs to be computed without doing at least n*m computations. – Bogdan Jan 24 '12 at 12:25
  • With `Fortran` version of the code (above in the question) that I developed based on your answer, the performance is outstanding. Thus I accepted your answer for its simplicity in implementation. – Developer Jan 25 '12 at 00:23