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 withpip install samplerate
. Usage:import samplerate
from scipy.io import wavfile
sr, x = wavfile.read('input.wav') # 48 khz file
y = 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 np
from 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 np
import scipy.ndimage
x = np.arange(9).reshape(3,3)
print 'Original array:'
print x
print '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', data
print '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_blocks
a = view_as_blocks(a, (4,5))
Now, you can use methods/slicing for parameters you want:
#max
a.max(-1)[0].T
#min
a.min(-1)[0].T
#left
a[...,0][0].T
#right
a[...,-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]]
Related Topics
How to Write a Lambda Function That Is Conditional on Two Variables (Columns) in Python
How to Install Tesseract for Python on Anaconda
Counting the Number of Duplicates in a List
How to Skip Blank Line While Reading CSV File Using Python
Converting Json into Newline Delimited Json in Python
Python3: Remove a Substring Between Two Delimiting Char
Replace Empty Strings With None/Null Values in Dataframe
Python - How to Sort a List of Alpha and Numeric Values
Json.Loads() Decodes Only With Raw String Literal
Reading Contents of a Gzip File from a Aws S3 in Python
How to Click on an Element from the Dropdown Menu Through Python and Selenium
Python Replace Single Quotes Except Apostrophes
How to Count the Number of Files in a Directory Using Python
Iterate Over Worksheets, Rows, Columns
How to Split an Array According to Conditional Statement
Python:Compare Two CSV Files and Print Out Differences
Robot Framework Using Python, Key Press Without Selecting Any Button or Element in the Page