Интерполяция Pandas, заменяющая NaNs после последней точки данных, но не до первой точки данных

при использовании Pandas interpolate () для заполнения значений NaN следующим образом:

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'

, почему панды заменяют значения в индексе 5 и 6 на 3s, но оставляют значения в 0 и 1 как есть?

могу ли я изменить это поведение? Я бы хотел оставить Нэн в индексе 5 и 6.

(на самом деле, я хотел бы сделать линейную экстраполяцию, чтобы заполнить все 0, 1, 5 и 6, но это другой вопрос. Бонусные очки, если вы ответите на него тоже!)

2 ответов


внутри интерполировать метод использует параметр "limit", который позволяет избежать распространения заполнения более определенного порога.

>>>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

по умолчанию, ограничение применяется в прямом направлении. В обратном направлении существует ограничение по умолчанию, равное нулю. Вот почему ваши первые шаги не заполняются методом. Можно изменить направление, используя параметр 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

заполнить первые шаги и последние шаги вашего фрейма данных, вы можете установить ненулевое значение для "limit" и "limit_direction" в "both":

>>> 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

тема была обсуждена здесь


этой interpolate поведение у панд выглядит странно. Вы можете использовать для получения ожидаемого результата. Для линейной экстраполяции можно написать простую функцию для выполнения этой задачи.

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