Interpolación de pandas que reemplaza NaNs después del último punto de datos, pero no antes del primer punto de datos

Al usar pandas interpolate () para llenar valores de NaN como este:

In [1]: s = pandas.Series([np.nan, np.nan, 1, np.nan, 3, np.nan, np.nan]) In [2]: s.interpolate() Out[2]: 0 NaN 1 NaN 2 1 3 2 4 3 5 3 6 3 dtype: float64 In [3]: pandas.version.version Out[3]: '0.16.2' 

, ¿por qué las pandas reemplazan los valores en el índice 5 y 6 con 3, pero dejan los valores en 0 y 1 como están?

¿Puedo cambiar este comportamiento? Me gustaría dejar NaN en el índice 5 y 6.

(De hecho, me gustaría que se realice una extrapolación lineal para completar todos los 0, 1, 5 y 6, pero esa es una pregunta diferente. ¡Puntos de bonificación si también la contestas!)

Internamente, el método de interpolación utiliza un parámetro ‘límite’ que evita la propagación de llenado más que un umbral específico.

 >>>df=pd.DataFrame( [0, np.nan, np.nan, np.nan, np.nan,np.nan, 2] ) >>>df df 0 0 0 1 NaN 2 NaN 3 NaN 4 NaN 5 NaN 6 2 >>>df.interpolate(limit=2) 0 0 0.000000 1 0.333333 2 0.666667 3 NaN 4 NaN 5 NaN 6 2.000000 

Por defecto, la limitación se aplica en la dirección de avance. En la dirección hacia atrás, hay un límite predeterminado que se establece en cero. Es por esto que sus primeros pasos no están llenos de método. Uno puede cambiar la dirección usando el parámetro ‘limit_direction’.

 df.interpolate(limit=2, limit_direction='backward') 0 0 0.000000 1 NaN 2 NaN 3 NaN 4 1.333333 5 1.666667 6 2.000000 

Para completar los primeros pasos y los últimos pasos de su dataframe, debe establecer un valor distinto de cero para ‘límite’ y ‘dirección_límite’ a ‘ambos’:

 >>> df=pd.DataFrame( [ np.nan, np.nan, 0, np.nan, 2, np.nan,8,5,np.nan, np.nan] ) >>> df 0 0 NaN 1 NaN 2 0 3 NaN 4 2 5 NaN 6 8 7 5 8 NaN 9 NaN >>> df.interpolate(method='spline', order=1, limit=10, limit_direction='both') 0 0 -3.807382 1 -2.083581 2 0.000000 3 1.364022 4 2.000000 5 4.811625 6 8.000000 7 5.000000 8 4.937632 9 4.138735 

El tema ha sido discutido aquí.

Este comportamiento de interpolate en pandas parece extraño. Puede usar scipy.interpolate.interp1d lugar de producir el resultado esperado. Para la extrapolación lineal, se puede escribir una función simple para hacer esta tarea.

 import pandas as pd import numpy as np import scipy as sp s = pd.Series([np.nan, np.nan, 1, np.nan, 3, np.nan, np.nan]) # interpolate using scipy # =========================================== s_no_nan = s.dropna() func = sp.interpolate.interp1d(s_no_nan.index.values, s_no_nan.values, kind='linear', bounds_error=False) s_interpolated = pd.Series(func(s.index), index=s.index) Out[107]: 0 NaN 1 NaN 2 1 3 2 4 3 5 NaN 6 NaN dtype: float64 # extrapolate using user-defined func # =========================================== def my_extrapolate_func(scipy_interpolate_func, new_x): x1, x2 = scipy_interpolate_func.x[0], scipy_interpolate_func.x[-1] y1, y2 = scipy_interpolate_func.y[0], scipy_interpolate_func.y[-1] slope = (y2 - y1) / (x2 - x1) return y1 + slope * (new_x - x1) s_extrapolated = pd.Series(my_extrapolate_func(func, s.index.values), index=s.index) Out[108]: 0 -1 1 0 2 1 3 2 4 3 5 4 6 5 dtype: float64