我有一个时间序列,其中每个观察值代表自上次观察以来的某些事物的总量,如果在该时间步长中没有观察到,那么该值被报告为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回填和插值方法,但没有发现任何我想要的东西。
答案 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.bincount
和pd.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
选项中,我使用groupby
和size
来计算这些群组的大小。
第二个选项使用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