如何使用方法链接向前填充列子集?

How to forward fill a column subset with method chaining?

我有一个包含天数信息的数据框。每天有两个阶段。

df = (pd.DataFrame(dict(
    day=[0, 1, 2],
    phase1=[1, 0, 2],
    phase2=[5, 0, 7],
))

目标是提前两个阶段都为 0 的填充日。预期输出如下所示

out_wanted = pd.DataFrame(dict(
    day=[0, 1, 2],
    phase1=[1, 1, 2],
    phase2=[5, 5, 7],
))

我正在寻找此问题的解决方案,它适用于方法链接。语法应该有点像这样:

out_wanted = (
    df
    .methodA(...)
    .methodB(...)
    .forward_fill_magic()
    .methodC(...)
    .methodD(...)
)

我该怎么做?


更新:

让我们假设 df 有两个名为 dayx 的列,它们可以包含零,我想避免用 nan 替换其中的任何值。我该怎么做?

df = pd.DataFrame(dict(
    day=[0, 1, 2],
    phase1=[1, 0, 2],
    phase2=[5, 0, 7],
    x=[1, 2, 3]
))

当前提出的解决方案给我一个 ValueError

df = (
    df.set_index(["day", "x"])
    .mask(df.eq(0))
    .ffill(downcast= 'infer')
)

-> ValueError: cannot join with no overlapping index names

尝试 set_index /mask /ffill :

df = df.set_index(["day", "x"]).mask(lambda d: d.eq(0)).ffill().reset_index()

ALTERNATIVE_1 :

df = (
    df.set_index(["day", "x"])
    .replace(0,np.nan)
    .ffill(downcast= 'infer')
)

ALTERNATIVE_2 :

df[df.filter(like = 'phase').columns] = df.filter(like= 'phase').mask(df.eq(0)).ffill(downcast='infer')

输出:

     phase1  phase2
day                
0         1       5
1         1       5
2         2       7

这是一个解决方案,无需设置(后来重置)索引并明确选择要填充的列。它也仅在两列都等于 0 时才填充(我认为这是要求的一部分)。

def forward_fillmagic(df, colnames):
    all_zero = df[colnames].eq(0).all(axis=1)
    return df.assign(**{
        colname: df[colname].mask(all_zero).ffill(downcast="infer")
        for colname in colnames
    })

df.pipe(forward_fillmagic, ["phase1", "phase2"])