熊猫从零到下一个有效值内插NaN

时间:2020-04-30 18:59:06

标签: python pandas dataframe interpolation

我正在寻找一种将缺失值(NaN)从零线性插值到下一个有效值的方法。

例如:

     A    B   C   D  E
0  NaN  2.0 NaN NaN  0
1  3.0  4.0 NaN NaN  1
2  NaN  NaN NaN NaN  5
3  NaN  3.0 NaN NaN  4

给出该表,我希望输出看起来像这样:

     A    B   C   D  E
0  NaN  2.0   0   0  0
1  3.0  4.0   0 0.5  1
2  NaN  NaN NaN NaN  5
3  NaN  3.0   0   2  4

我尝试使用fillna仅将下一个NaN填充为有效值0,然后对整个数据帧进行线性插值。 我在这里面临的问题是,使用fillna指定值和限制不会影响连续的NaN,但会限制要填充的列总数。

如果可能的话,由于我正在处理大型数据框,因此请仅提出解决方案,而无需手动遍历每一行。

谢谢。

1 个答案:

答案 0 :(得分:2)

这是一种将有效数字后的第一个NaN替换为0的方法,然后将按行进行插值。我在末尾添加了额外的行,以说明同一行上多个填充,仅填充一个值或以NaN条纹结尾的行的行为。

样本数据

     A    B   C   D  E
0  NaN  2.0 NaN NaN  0
1  3.0  4.0 NaN NaN  1
2  NaN  NaN NaN NaN  5
3  NaN  3.0 NaN NaN  4
4  3   NaN  7  NaN   5
5  NaN  4   7  NaN   6
6  NaN  4   7  NaN  NaN
7  5   NaN  5  NaN  NaN

代码

m = (df.notnull().cummax(axis=1) & df.isnull()).astype(int).diff(axis=1).fillna(0)
update = m.where(m.eq(1) & m.loc[:, ::-1].cummin(axis=1).eq(-1)).replace(1, 0)

df.update(update)  # Add in 0s

df = df.interpolate(axis=1, limit_area='inside')

     A    B    C    D    E
0  NaN  2.0  0.0  0.0  0.0
1  3.0  4.0  0.0  0.5  1.0
2  NaN  NaN  NaN  NaN  5.0
3  NaN  3.0  0.0  2.0  4.0
4  3.0  0.0  7.0  0.0  5.0
5  NaN  4.0  7.0  0.0  6.0
6  NaN  4.0  7.0  NaN  NaN
7  5.0  0.0  5.0  NaN  NaN

工作方式:

(df.notnull().cummax(1) & df.isnull())  # True for streaks of null after non-null
#       A      B      C      D      E
#0  False  False   True   True  False
#1  False  False   True   True  False
#2  False  False  False  False  False
#3  False  False   True   True  False
#4  False   True  False   True  False
#5  False  False  False   True  False
#6  False  False  False   True   True
#7  False   True  False   True   True

# Taking the diff then allows you to find only the first NaN after any non-null.
# I.e. flagged by `1`
(df.notnull().cummax(1) & df.isnull()).astype(int).diff(axis=1).fillna(0)
#     A    B    C    D    E
#0  0.0  0.0  1.0  0.0 -1.0
#1  0.0  0.0  1.0  0.0 -1.0
#2  0.0  0.0  0.0  0.0  0.0
#3  0.0  0.0  1.0  0.0 -1.0
#4  0.0  1.0 -1.0  1.0 -1.0
#5  0.0  0.0  0.0  1.0 -1.0
#6  0.0  0.0  0.0  1.0  0.0
#7  0.0  1.0 -1.0  1.0  0.0

# The update DataFrame is a like-indexed DF with 0s where they get filled.
# The reversed cummin ensures fills only if there's a non-null value after the 0.
m.where(m.eq(1) & m.loc[:, ::-1].cummin(1).eq(-1)).replace(1, 0)
#    A    B    C    D   E
#0 NaN  NaN  0.0  NaN NaN
#1 NaN  NaN  0.0  NaN NaN
#2 NaN  NaN  NaN  NaN NaN
#3 NaN  NaN  0.0  NaN NaN
#4 NaN  0.0  NaN  0.0 NaN
#5 NaN  NaN  NaN  0.0 NaN
#6 NaN  NaN  NaN  NaN NaN
#7 NaN  0.0  NaN  NaN NaN