Pandas 在最后一个数据点之后但不在第一个数据点之前替换 NaN 的插值
Pandas interpolation replacing NaNs after the last data point, but not before the first data point
当使用 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'
,为什么pandas将索引5和6处的值替换为3s,而将0和1处的值保留原样?
我可以改变这种行为吗?我想在索引 5 和 6 处保留 NaN。
(实际上,我希望它进行线性外推以填充所有 0、1、5 和 6,但这是一个不同的问题。如果你也回答它,加分!)
interpolate
pandas 中的这种行为看起来很奇怪。您可以使用 scipy.interpolate.interp1d
来产生预期的结果。对于线性外推,可以编写一个简单的函数来完成此任务。
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
在内部,interpolate 方法使用 '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
已讨论该主题here
当使用 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'
,为什么pandas将索引5和6处的值替换为3s,而将0和1处的值保留原样?
我可以改变这种行为吗?我想在索引 5 和 6 处保留 NaN。
(实际上,我希望它进行线性外推以填充所有 0、1、5 和 6,但这是一个不同的问题。如果你也回答它,加分!)
interpolate
pandas 中的这种行为看起来很奇怪。您可以使用 scipy.interpolate.interp1d
来产生预期的结果。对于线性外推,可以编写一个简单的函数来完成此任务。
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
在内部,interpolate 方法使用 '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
已讨论该主题here