Pandas 每个零值后的常量值

Pandas Constant Values after each Zero Value

假设我有以下数据框:

    values
0      4
1      0
2      2
3      3
4      0
5      8
6      5
7      1
8      0
9      4
10     7

我想找到一个 pandas 向量化函数(最好使用 groupby),它将所有非零值替换为该非零值块中的第一个非零值,即可以给我的东西

    values   new
0      4      4
1      0      0
2      2      2
3      3      2
4      0      0
5      8      8
6      5      8
7      1      8
8      0      0
9      4      4
10     7      4

有什么好的方法可以实现吗?

为 select 具有零的行及其后续行创建一个布尔掩码,然后将此布尔掩码与 where 一起使用以将剩余值替换为 NaN,然后使用前向填充向前传播值。

m = df['values'].eq(0)
df['new'] = df['values'].where(m | m.shift()).ffill().fillna(df['values'])

结果

print(df)

    values  new
0        4  4.0
1        0  0.0
2        2  2.0
3        3  2.0
4        0  0.0
5        8  8.0
6        5  8.0
7        1  8.0
8        0  0.0
9        4  4.0
10       7  4.0

以下函数应该可以为您完成这项工作。查看函数中的注释以了解解决方案的工作流程。

import pandas as pd

def ffill_nonZeros(values):
    # get the values that are not equal to 0
    non_zero = values[df['values'] != 0]

    # get their indexes
    non_zero_idx = non_zero.index.to_series()

    # find where indexes are consecutive
    diff = non_zero_idx.diff()
    mask = diff == 1

    # using the mask make all places in non_zero where the change is consecutive equal None
    non_zero[mask] = None

    # fill forward (replace all None values with previous valid value)
    new_non_zero = non_zero.fillna(method='ffill')

    # put new values back in their indexs
    new = values.copy()
    new[new_non_zero.index] = new_non_zero

    return new

现在将此函数应用于您的数据:

df = pd.DataFrame([4, 0, 2, 3, 0, 8, 5, 1, 0, 4, 7], columns=['values'])
df['new'] = ffill_nonZeros(df['values'])
print(df)

输出:

    values  new
0        4    4
1        0    0
2        2    2
3        3    2
4        0    0
5        8    8
6        5    8
7        1    8
8        0    0
9        4    4
10       7    4

获取零的行,以及紧随其后的行:

zeros = df.index[df['values'].eq(0)]
after_zeros = zeros.union(zeros +1)

获取需要前向填充的行:

replace = df.index.difference(after_zeros)
replace = replace[replace > zeros[0]]

replace 上设置值并向前填充:

df['new'] = df['values']
df.loc[replace, 'new'] = np.nan
df.ffill()


values  new
0   4   4.0
1   0   0.0
2   2   2.0
3   3   2.0
4   0   0.0
5   8   8.0
6   5   8.0
7   1   8.0
8   0   0.0
9   4   4.0
10  7   4.0