在 Pandas 中填充空值直到某一列的值

4
我有一个时间序列数据框。我想用前一个值填充缺失的值。但是,我只想填充缺失的值直到达到某个特定值。这个值记录在另一列中。因此,我想填充的列对于每一行都不同。我该怎么做?
给定这个数据框。
import numpy as np
import pandas as pd
df = pd.DataFrame([[1, 2 ,np.nan,np.nan,np.nan , 2009], [1, 3 , np.nan , np.nan , np.nan , 2010], [4, np.nan , 7 , np.nan,np.nan , 2011]], columns=[2007,2008,2009,2010,2011 , fill_until])

输入数据框

2007    2008    2009    2010    2011  fill_until 
 1       2       NaN    NaN     NaN   2009
 1       3       NaN    NaN     NaN   2010
 4       Nan     7      NaN     NaN   2011    

输出数据框架:
2007    2008    2009    2010    2011
 1       2       2      NaN      NaN
 1       3       3        3      NaN
 4       4       7        7        7
2个回答

6
使用 ffill + where -
m = df.columns[:-1].values <= df.fill_until.values[:, None]
df.iloc[:, :-1].ffill(axis=1).where(m)

   2007  2008  2009  2010  2011
0   1.0   2.0   2.0   NaN   NaN
1   1.0   3.0   3.0   3.0   NaN
2   4.0   4.0   7.0   7.0   7.0

细节

使用 NumPy 的广播机制,根据 fill_until 列生成一个要填充的值的掩码。

m = df.columns[:-1].values <= df.fill_until.values[:, None]

或者,
m = (df.columns[:-1].values[:, None] <= df.fill_until.values).T

m    
array([[ True,  True,  True, False, False],
       [ True,  True,  True,  True, False],
       [ True,  True,  True,  True,  True]], dtype=bool)

现在,将除了最后一列以外的所有部分切出来,并沿着第一个轴使用ffill函数。
i = df.iloc[:, :-1].ffill(axis=1)
i

   2007  2008  2009  2010  2011
0   1.0   2.0   2.0   2.0   2.0
1   1.0   3.0   3.0   3.0   3.0
2   4.0   4.0   7.0   7.0   7.0

现在,使用之前计算的掩码 m 来使用 df.where 掩盖 i 的值 -
i.where(m)

   2007  2008  2009  2010  2011
0   1.0   2.0   2.0   NaN   NaN
1   1.0   3.0   3.0   3.0   NaN
2   4.0   4.0   7.0   7.0   7.0

另外,可以使用mask,反转m-
i.mask(~m)

   2007  2008  2009  2010  2011
0   1.0   2.0   2.0   NaN   NaN
1   1.0   3.0   3.0   3.0   NaN
2   4.0   4.0   7.0   7.0   7.0

1
加1,不错的一个 ;) - jezrael
@jezrael 你也一样! - cs95

4
你可以按照以下步骤操作:
  • 首先,从fill_until列创建索引
  • 使用numpy广播创建掩码
  • 使用mask和应用方法为ffill(与ffill相同)的fillna
  • 最后,进行reset_index并为了保持相同的列顺序添加reindex
df = pd.DataFrame([[1, 2 ,np.nan,np.nan,10 , 2009], 
                   [1, 3 , np.nan , np.nan , np.nan , 2010], 
                   [4, np.nan , 7 , np.nan,np.nan , 2011]], 
                   columns=[2007,2008,2009,2010,2011 , 'fill_until'])
print (df)
   2007  2008  2009  2010  2011  fill_until
0     1   2.0   NaN   NaN  10.0        2009
1     1   3.0   NaN   NaN   NaN        2010
2     4   NaN   7.0   NaN   NaN        2011

df1 = df.set_index('fill_until')
m = df1.columns.values <= df1.index.values[:, None]
print (m)
[[ True  True  True False False]
 [ True  True  True  True False]
 [ True  True  True  True  True]]

df =  df1.mask(m, df1.ffill(axis=1)).reset_index().reindex(columns=df.columns)
print (df)
   2007  2008  2009  2010  2011  fill_until
0     1   2.0   2.0   NaN  10.0        2009
1     1   3.0   3.0   3.0   NaN        2010
2     4   4.0   7.0   7.0   7.0        2011

嘿,看看我的答案,完全一样。 - cs95
是的,我已经检查过了,不,它是不同的 - mask + set_index + reindex + reset_index。 - jezrael
我的答案也有掩码...如果你往下滚动的话。 :) - cs95
好的,请给我一会儿。 - jezrael
没关系,请慢慢来。 - cs95
1
是的,我对此感到满意。 :-) - cs95

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接