Existe-t-il un moyen rapide de remplacer toutes les valeurs NaN dans un tableau numpy par (disons) les valeurs interpolées linéairement ?
Par exemple,
[1 1 1 nan nan 2 2 nan 0]
serait converti en
[1 1 1 1.3 1.6 2 2 1 0]
Existe-t-il un moyen rapide de remplacer toutes les valeurs NaN dans un tableau numpy par (disons) les valeurs interpolées linéairement ?
Par exemple,
[1 1 1 nan nan 2 2 nan 0]
serait converti en
[1 1 1 1.3 1.6 2 2 1 0]
Définissons tout d'abord une simple fonction d'aide afin de rendre plus simple la gestion des indices et des indices logiques de l'alphabet. NaNs :
import numpy as np
def nan_helper(y):
"""Helper to handle indices and logical indices of NaNs.
Input:
- y, 1d numpy array with possible NaNs
Output:
- nans, logical indices of NaNs
- index, a function, with signature indices= index(logical_indices),
to convert logical indices of NaNs to 'equivalent' indices
Example:
>>> # linear interpolation of NaNs
>>> nans, x= nan_helper(y)
>>> y[nans]= np.interp(x(nans), x(~nans), y[~nans])
"""
return np.isnan(y), lambda z: z.nonzero()[0]
Maintenant, le nan_helper(.)
peut maintenant être utilisé comme :
>>> y= array([1, 1, 1, NaN, NaN, 2, 2, NaN, 0])
>>>
>>> nans, x= nan_helper(y)
>>> y[nans]= np.interp(x(nans), x(~nans), y[~nans])
>>>
>>> print y.round(2)
[ 1. 1. 1. 1.33 1.67 2. 2. 1. 0. ]
---
Bien qu'il puisse d'abord sembler un peu exagéré de spécifier une fonction séparée pour faire juste ce genre de choses :
>>> nans, x= np.isnan(y), lambda z: z.nonzero()[0]
cela finira par rapporter des dividendes.
Ainsi, chaque fois que vous travaillez avec des données liées aux NaNs, il suffit d'encapsuler toutes les fonctionnalités (liées aux NaNs) nécessaires, dans une ou plusieurs fonctions d'aide spécifiques. Votre code de base sera plus cohérent et plus lisible, car il suivra des idiomes facilement compréhensibles.
L'interpolation est en effet un bon contexte pour voir comment la gestion des NaN est effectuée, mais des techniques similaires sont également utilisées dans d'autres contextes.
@fmonegaglia, malheureusement ce script n'interpole que sur un axe des tableaux 2D, ce n'est pas une interpolation 2D. Le besoin d'interpolation sur les NaNs dans les tableaux 2D a un problème scipy : github.com/scipy/scipy/issues/1682
D'après le numéro référencé, vous pouvez utiliser directement la fonction convolve d'Astropy.
Il suffit d'utiliser numpy logical et there where statement pour appliquer une interpolation 1D.
import numpy as np
from scipy import interpolate
def fill_nan(A):
'''
interpolate to fill nan values
'''
inds = np.arange(A.shape[0])
good = np.where(np.isfinite(A))
f = interpolate.interp1d(inds[good], A[good],bounds_error=False)
B = np.where(np.isfinite(A),A,f(inds))
return B
Pour les données bidimensionnelles, l'outil SciPy's griddata
fonctionne assez bien pour moi :
>>> import numpy as np
>>> from scipy.interpolate import griddata
>>>
>>> # SETUP
>>> a = np.arange(25).reshape((5, 5)).astype(float)
>>> a
array([[ 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.]])
>>> a[np.random.randint(2, size=(5, 5)).astype(bool)] = np.NaN
>>> a
array([[ nan, nan, nan, 3., 4.],
[ nan, 6., 7., nan, nan],
[ 10., nan, nan, 13., nan],
[ 15., 16., 17., nan, 19.],
[ nan, nan, 22., 23., nan]])
>>>
>>> # THE INTERPOLATION
>>> x, y = np.indices(a.shape)
>>> interp = np.array(a)
>>> interp[np.isnan(interp)] = griddata(
... (x[~np.isnan(a)], y[~np.isnan(a)]), # points we know
... a[~np.isnan(a)], # values we know
... (x[np.isnan(a)], y[np.isnan(a)])) # points to interpolate
>>> interp
array([[ nan, nan, nan, 3., 4.],
[ nan, 6., 7., 8., 9.],
[ 10., 11., 12., 13., 14.],
[ 15., 16., 17., 18., 19.],
[ nan, nan, 22., 23., nan]])
Je l'utilise sur des images 3D, en opérant sur des coupes 2D (4000 coupes de 350x350). L'ensemble de l'opération prend encore environ une heure :/
Il serait peut-être plus facile de changer la façon dont les données sont générées en premier lieu, mais sinon.. :
bad_indexes = np.isnan(data)
Créer un tableau booléen indiquant où se trouvent les nans.
good_indexes = np.logical_not(bad_indexes)
Créer un tableau booléen indiquant où se trouvent les bonnes valeurs
good_data = data[good_indexes]
Une version restreinte des données originales excluant les nans.
interpolated = np.interp(bad_indexes.nonzero(), good_indexes.nonzero(), good_data)
Passez tous les mauvais index par interpolation.
data[bad_indexes] = interpolated
Remplacer les données originales par les valeurs interpolées.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
8 votes
Je m'excuse d'écrire sur un vieux fil de discussion, mais je pense que la confusion en vaut la peine. Une manière plus simple est d'utiliser pandas et numpy :
pd.DataFrame([1, 3, 4, np.nan, 6]).interpolate().values.ravel().tolist()
7 votes
J'ai trouvé
pd.Series([1, 3, 4, np.nan, 6]).interpolate.get_values().tolist()
encore plus courte.0 votes
À partir de pandas 1.2.4 :
pd.Series([1, 3, 4, np.nan, 6]).interpolate().tolist()
encore plus court