Interpolate a 3D array in Python
Interpolate a 3D array in Python
I have a 3D NumPy array that looks like this:
arr = np.empty((4,4,5))
arr[:] = np.nan
arr[0] = 1
arr[3] = 4
arr
>>> [[[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]]
[[ nan nan nan nan nan]
[ nan nan nan nan nan]
[ nan nan nan nan nan]
[ nan nan nan nan nan]]
[[ nan nan nan nan nan]
[ nan nan nan nan nan]
[ nan nan nan nan nan]
[ nan nan nan nan nan]]
[[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]]]
I would like to interpolate along axis=0
so that I get the following:
axis=0
>>> [[[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]]
[[ 2. 2. 2. 2. 2.]
[ 2. 2. 2. 2. 2.]
[ 2. 2. 2. 2. 2.]
[ 2. 2. 2. 2. 2.]]
[[ 3. 3. 3. 3. 3.]
[ 3. 3. 3. 3. 3.]
[ 3. 3. 3. 3. 3.]
[ 3. 3. 3. 3. 3.]]
[[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]
[ 4. 4. 4. 4. 4.]]]
I've been looking at the SciPy module and there seems to be methods to do this on a 1D and 2D array, but not 3D like I need - though I may have missed something.
np.apply_along_axis
2 Answers
2
A solution using apply_along_axis
:
apply_along_axis
import numpy as np
def pad(data):
good = np.isfinite(data)
interpolated = np.interp(np.arange(data.shape[0]),
np.flatnonzero(good),
data[good])
return interpolated
arr = np.arange(6, dtype=float).reshape((3,2))
arr[1, 1] = np.nan
print(arr)
new = np.apply_along_axis(pad, 0, arr)
print(arr)
print(new)
output:
[[ 0. 1.]
[ 2. nan]
[ 4. 5.]]
[[ 0. 1.]
[ 2. nan]
[ 4. 5.]]
[[0. 1.]
[2. 3.]
[4. 5.]]
[edit] The first proposed solution:
With some modification of the code from this answer:
import numpy as np
from scipy import interpolate
A = np.empty((4,4,5))
A[:] = np.nan
A[0] = 1
A[3] = 4
indexes = np.arange(A.shape[0])
good = np.isfinite(A).all(axis=(1, 2))
f = interpolate.interp1d(indexes[good], A[good],
bounds_error=False,
axis=0)
B = f(indexes)
print(B)
gives:
[[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[2. 2. 2. 2. 2.]
[2. 2. 2. 2. 2.]
[2. 2. 2. 2. 2.]
[2. 2. 2. 2. 2.]]
[[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]]
[[4. 4. 4. 4. 4.]
[4. 4. 4. 4. 4.]
[4. 4. 4. 4. 4.]
[4. 4. 4. 4. 4.]]]
It works well only if NaNs are all on same slice. The slice in which there is an isolated NaN will be ignored.
Thanks that looks promising - I've changed your reference to 'A' to 'arr' and am getting a TypeError: 'numpy.ndarray' object is not callable. Was your 'A' an array or an ndarray?
– tda
Aug 30 at 10:44
@TD-Asker I changed
arr
for A
in the code, it is a nd-array, I do not get this error, do you still have it?– xdze2
Aug 30 at 13:09
arr
A
From the comment provided by xdze2 and previous answer here, I came up with this:
import numpy as np
def pad(data):
bad_indexes = np.isnan(data)
good_indexes = np.logical_not(bad_indexes)
good_data = data[good_indexes]
interpolated = np.interp(bad_indexes.nonzero()[0], good_indexes.nonzero()[0],
good_data)
data[bad_indexes] = interpolated
return data
arr = np.empty((4,4,5))
arr[:] = np.nan
arr[0] = 25
arr[3] = 32.5
# Apply the pad method to each 0 axis
new = np.apply_along_axis(pad, 0, arr)
The 'pad' method essentially applies the interpolation and the np.apply_along_axis
method ensures that this is applied to the 3D array.
np.apply_along_axis
This function also modify in-place the given array, I don't think this effect is wanted? I added in my answer a solution without this effect, (by performing the interpolation over the whole array even if it not strictly necessary)
– xdze2
Aug 30 at 13:54
That's a good point though I'm having trouble replicating it? You're correct that I do not want to alter the original values so perhaps your suggestion is best. Do you have an example of the code above affecting the original values?
– tda
Aug 30 at 14:42
for example
print(arr); new = np.apply_along_axis(pad, 0, arr); print(arr);
the second print gives the interpolated array instead of the original one– xdze2
Aug 30 at 14:50
print(arr); new = np.apply_along_axis(pad, 0, arr); print(arr);
I see. Apologies I thought you meant the values were changing rather than the in-place array. For me this does not matter, but well spotted and if your answer leaves the original array alone, then it's the accepted answer! Thanks for your help.
– tda
Aug 30 at 15:01
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
maybe this answer: stackoverflow.com/a/12073605/8069403 (use
np.apply_along_axis
)– xdze2
Aug 30 at 10:39