﻿ Resample a Numpy Array - ITCodar

# Resample a Numpy Array

## Resample a numpy array

As `scipy.signal.resample` can be very slow, I searched for other algorithms adapted for audio.

It seems that Erik de Castro Lopo's SRC (a.k.a. Secret Rabbit Code a.k.a. libsamplerate) is one of the best resampling algorithms available.

• It is used by scikit's `scikit.samplerate`, but this library seems to be complicated to install (I gave up on Windows).

• Fortunately, there is an easy-to-use and easy-to-install Python wrapper for `libsamplerate`, made by Tino Wagner: https://pypi.org/project/samplerate/. Installation with `pip install samplerate`. Usage:

``import sampleratefrom scipy.io import wavfilesr, x = wavfile.read('input.wav')  # 48 khz filey = samplerate.resample(x, 44100 * 1.0 / 48000, 'sinc_best')  ``

Interesting reading / comparison of many resampling solutions:
http://signalsprocessed.blogspot.com/2016/08/audio-resampling-in-python.html

Addendum: comparison of spectrograms of a resampled frequency sweep (20hz to 20khz):

1) Original

2) Resampled with libsamplerate / `samplerate` module

3) Resampled with `numpy.interp` ("One-dimensional linear interpolation"):

## Resampling time series data using python/numpy

Possibly something like this does what you need:

``import numpy as npfrom scipy.interpolate import interp1d# The test data.time = np.array([0, 0.0120, 0.0130, 1, 1.02, 1.2, 1.3, 1.32, 2])values = np.array([1, 3, 2, 3, 4, 5, 6, 7, 8])# The new time basis we're aiming for.t_new = np.linspace(0, 2, 21)# Throw away times that we don't like.new_data = [[t, v] for t, v in zip(time, values) if t in t_new]t_clean, v_clean = np.array(new_data).T# Make the interpolator function.func = interp1d(t_clean, v_clean, kind="previous")# Interpolate the data into the new time basis.v_new = func(t_new)``

Now `v_new` is like:

``array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 3., 3., 3., 6., 6., 6., 6.,       6., 6., 6., 8.])``

## Resample a categorical numpy array

I think you can just simple numpy slicing, which is of the format `start:stop:step`. This is constant time and reflects possible changes you might make to the resampled array.
In your case it would be: `labels[0::64000]`

## Resampling a numpy array representing an image

Based on your description, you want `scipy.ndimage.zoom`.

Bilinear interpolation would be `order=1`, nearest is `order=0`, and cubic is the default (`order=3`).

`zoom` is specifically for regularly-gridded data that you want to resample to a new resolution.

As a quick example:

``import numpy as npimport scipy.ndimagex = np.arange(9).reshape(3,3)print 'Original array:'print xprint 'Resampled by a factor of 2 with nearest interpolation:'print scipy.ndimage.zoom(x, 2, order=0)print 'Resampled by a factor of 2 with bilinear interpolation:'print scipy.ndimage.zoom(x, 2, order=1)print 'Resampled by a factor of 2 with cubic interpolation:'print scipy.ndimage.zoom(x, 2, order=3)``

And the result:

``Original array:[[0 1 2] [3 4 5] [6 7 8]]Resampled by a factor of 2 with nearest interpolation:[[0 0 1 1 2 2] [0 0 1 1 2 2] [3 3 4 4 5 5] [3 3 4 4 5 5] [6 6 7 7 8 8] [6 6 7 7 8 8]]Resampled by a factor of 2 with bilinear interpolation:[[0 0 1 1 2 2] [1 2 2 2 3 3] [2 3 3 4 4 4] [4 4 4 5 5 6] [5 5 6 6 6 7] [6 6 7 7 8 8]]Resampled by a factor of 2 with cubic interpolation:[[0 0 1 1 2 2] [1 1 1 2 2 3] [2 2 3 3 4 4] [4 4 5 5 6 6] [5 6 6 7 7 7] [6 6 7 7 8 8]]``

Edit: As Matt S. pointed out, there are a couple of caveats for zooming multi-band images. I'm copying the portion below almost verbatim from one of my earlier answers:

Zooming also works for 3D (and nD) arrays. However, be aware that if you zoom by 2x, for example, you'll zoom along all axes.

``data = np.arange(27).reshape(3,3,3)print 'Original:\n', dataprint 'Zoomed by 2x gives an array of shape:', ndimage.zoom(data, 2).shape``

This yields:

``Original:[[[ 0  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]]]Zoomed by 2x gives an array of shape: (6, 6, 6)``

In the case of multi-band images, you usually don't want to interpolate along the "z" axis, creating new bands.

If you have something like a 3-band, RGB image that you'd like to zoom, you can do this by specifying a sequence of tuples as the zoom factor:

``print 'Zoomed by 2x along the last two axes:'print ndimage.zoom(data, (1, 2, 2))``

This yields:

``Zoomed by 2x along the last two axes:[[[ 0  0  1  1  2  2]  [ 1  1  1  2  2  3]  [ 2  2  3  3  4  4]  [ 4  4  5  5  6  6]  [ 5  6  6  7  7  7]  [ 6  6  7  7  8  8]] [[ 9  9 10 10 11 11]  [10 10 10 11 11 12]  [11 11 12 12 13 13]  [13 13 14 14 15 15]  [14 15 15 16 16 16]  [15 15 16 16 17 17]] [[18 18 19 19 20 20]  [19 19 19 20 20 21]  [20 20 21 21 22 22]  [22 22 23 23 24 24]  [23 24 24 25 25 25]  [24 24 25 25 26 26]]]``

## Resample numpy array with interpolation

I came up with a solution but I am wondering if it is correct from a technical/scientific point of view. Is this good procedure to solve my issue? Practically, it is doing what I want...

``for i in range(len(S_images)):    if S_images[i].shape[1] !=1524:        S_images[i] = scipy.ndimage.zoom(S_images[i], (1, 1524/1525, 1),order=0, mode='nearest')for i in range(len(S_images)):    if S_images[i].shape[2] !=5499:        S_images[i] = scipy.ndimage.zoom(S_images[i], (1, 1, 5499/5500 ),order=0, mode='nearest')for i in range(len(S_images)):    print(S_images[i].shape)(1, 1524, 5499)(1, 1524, 5499)(1, 1524, 5499)(1, 1524, 5499)(1, 1524, 5499)``

## numpy vectorized resampling like pandas DataFrame resample

Here is another way that uses numpy strides under the hood (`a` is your array):

``from skimage.util import view_as_blocksa = view_as_blocks(a, (4,5))``

Now, you can use methods/slicing for parameters you want:

``#maxa.max(-1)[0].T#mina.min(-1)[0].T#lefta[...,0][0].T#righta[...,-1][0].T``

example:

``a#[[ 0  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 39]]output for max#[[ 4  9]# [14 19]# [24 29]# [34 39]]``