通过在具有pandas的时间序列中的先前NaN之间分布值来回填值

时间:2018-05-09 13:14:14

标签: python pandas dataframe time-series interpolation

我有一个时间序列,其中每个观察值代表自上次观察以来的某些事物的总量,如果在该时间步长中没有观察到,那么该值被报告为NaN。格式示例:

Timestep  Value
1          10
2          NaN
3          NaN
4          9
5          NaN
6          NaN
7          NaN
8          16
9          NaN
10         NaN

我想做的是在它之前在NaN上分配观察值。例如,像[5,NaN,NaN,6]这样的序列将变为[5,2,2,2],最终观察值6分布在最后2个NaN值上。应用于上述数据帧所需的输出将是:

Timestep  Value
1          10
2          3
3          3
4          3
5          4
6          4
7          4
8          4
9          NaN
10         NaN

我已经尝试过使用一些pandas回填和插值方法,但没有发现任何我想要的东西。

2 个答案:

答案 0 :(得分:7)

transform

df.Value.bfill().div(
    df.groupby(df.Value.notna()[::-1].cumsum()).Value.transform('size')
)

0    10.0
1     3.0
2     3.0
3     3.0
4     4.0
5     4.0
6     4.0
7     4.0
8     NaN
9     NaN
Name: Value, dtype: float64

np.bincountpd.factorize

a = df.Value.notna().values
f, u = pd.factorize(a[::-1].cumsum()[::-1])

df.Value.bfill().div(np.bincount(f)[f])

0    10.0
1     3.0
2     3.0
3     3.0
4     4.0
5     4.0
6     4.0
7     4.0
8     NaN
9     NaN
Name: Value, dtype: float64

替代短版本。这是有效的,因为cumsum自然地告诉了我factorize做了什么。

a = df.Value.notna().values[::-1].cumsum()[::-1]
df.Value.bfill().div(np.bincount(a)[a])

详细

在上面的两个选项中,我们需要确定空值的位置,并在反向序列上使用cumsum来定义组。在transform选项中,我使用groupbysize来计算这些群组的大小。

第二个选项使用bin计数和切片来获得相同的系列。

感谢@ScottBoston提醒我提及反转元素[::-1]

答案 1 :(得分:4)

计算累积 NA,然后我们执行update

s=df.Value.notnull().cumsum().shift(1)
df.Value.update(df.Value.bfill()/s.groupby(s).transform('count'))
df
Out[885]: 
   Timestep  Value
0         1   10.0
1         2    3.0
2         3    3.0
3         4    3.0
4         5    4.0
5         6    4.0
6         7    4.0
7         8    4.0
8         9    NaN
9        10    NaN