Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to downsample a numpy array?

I have a 3 dimensional numpy array, with shape Nx64x64. I would like to downsample it across dimensions 1 and 2 by taking the mean, resulting in a new array with shape Nx8x8.

I have a couple of working implementations, but I feel like there must be a neater way of doing it.

I initially tried to use np.split:

def subsample(inparray, n):
    inp = inparray.copy()
    res = np.moveaxis(np.array(np.hsplit(inp, inp.shape[1]/n)), 1, 0)
    res = np.moveaxis(np.array(np.split(res, inp.shape[2]/n, axis=3)), 1, 0)
    res = np.mean(res, axis=(3,4))
    return res

I also tried using plain indexing:

def subsample2(inparray, n):
    res = np.zeros((inparray.shape[0], n, n))
    lin = np.linspace(0, inparray.shape[1], n+1).astype(int)
    bounds = np.stack((lin[:-1], lin[1:]), axis=-1)

    for i, b in enumerate(bounds):
        for j, b2 in enumerate(bounds):
            res[:, i, j] = np.mean(inparray[:, b[0]:b[1], b2[0]:b2[1]], axis=(1,2))
    return res

I had wondered about using itertools.groupby, but it also looked quite involved.

Does anyone know of a clean solution?

like image 861
prdnr Avatar asked Jun 13 '17 17:06

prdnr


People also ask

How do I reduce the size of an array in NP?

If you're running into memory issues because your NumPy arrays are too large, one of the basic approaches to reducing memory usage is compression. By changing how you represent your data, you can reduce memory usage and shrink your array's footprint—often without changing the bulk of your code.

How can I make my NumPy code faster?

By explicitly declaring the "ndarray" data type, your array processing can be 1250x faster. This tutorial will show you how to speed up the processing of NumPy arrays using Cython. By explicitly specifying the data types of variables in Python, Cython can give drastic speed increases at runtime.

Which is faster NumPy array or list?

As predicted, we can see that NumPy arrays are significantly faster than lists.

How do I scale a NumPy array?

Use numpy. abs(x) to convert the elements of array x to their absolute values. Use numpy. amax(a) with this result to calculate the maximum value in a . Divide a number x by the maximum value and multiply by the original array to scale the elements of the original array to be between -x and x .


1 Answers

There is a neat solution in form of the function block_reduce in the scikit-image module (link to docs).

It has a very simple interface to downsample arrays by applying a function such as numpy.mean. The downsampling can be done by different factors for different axes by supplying a tuple with different sizes for the blocks. Here's an example with a 2D array; downsampling only axis 1 by 5 using the mean:

import numpy as np
from skimage.measure import block_reduce

arr = np.stack((np.arange(1,20), np.arange(20,39)))

# array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
#        [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]])

arr_reduced = block_reduce(arr, block_size=(1,5), func=np.mean, cval=np.mean(arr))

# array([[ 3. ,  8. , 13. , 17.8],
#        [22. , 27. , 32. , 33. ]])
like image 157
L_W Avatar answered Sep 16 '22 12:09

L_W