Pandas使用groupby填充fillna。

28

我正在尝试使用具有相似列值的行来进行值填充/插补。

例如,我有这个数据框:

one | two | three
1      1     10
1      1     nan
1      1     nan
1      2     nan
1      2     20
1      2     nan
1      3     nan
1      3     nan
我想使用列 onetwo 的键值,如果列three不是完全为NaN,则从具有相似键的行中填充现有值到列'3'的值。 这是我的预期结果:
one | two | three
1      1     10
1      1     10
1      1     10
1      2     20
1      2     20
1      2     20
1      3     nan
1      3     nan

您可以看到键1和3没有包含任何值,因为现有值不存在。

我尝试使用groupby+fillna()

df['three'] = df.groupby(['one','two'])['three'].fillna()

我尝试使用向前填充,但出现了错误。

我已经尝试了向前填充,但结果很奇怪。 它填充的是第二列而不是第一列。 我正在使用以下代码进行向前填充:

df['three'] = df.groupby(['one','two'], sort=False)['three'].ffill()
2个回答

71

如果每个组中只有一个非NaN值,则使用ffill(向前填充)和bfill(向后填充)来填充每个组,因此需要对每个组应用applylambda

df['three'] = df.groupby(['one','two'], sort=False)['three']
                .apply(lambda x: x.ffill().bfill())
print (df)
   one  two  three
0    1    1   10.0
1    1    1   10.0
2    1    1   10.0
3    1    2   20.0
4    1    2   20.0
5    1    2   20.0
6    1    3    NaN
7    1    3    NaN

但如果每个组有多个值并且需要用某个常数(例如组的平均值)替换 NaN

print (df)
   one  two  three
0    1    1   10.0
1    1    1   40.0
2    1    1    NaN
3    1    2    NaN
4    1    2   20.0
5    1    2    NaN
6    1    3    NaN
7    1    3    NaN

df['three'] = df.groupby(['one','two'], sort=False)['three']
                .apply(lambda x: x.fillna(x.mean()))
print (df)
   one  two  three
0    1    1   10.0
1    1    1   40.0
2    1    1   25.0
3    1    2   20.0
4    1    2   20.0
5    1    2   20.0
6    1    3    NaN
7    1    3    NaN

2
@jezrael:你在回答中强制使用apply的原因是什么?我问这个问题是因为我尝试了直接使用ffillbfill,并且它返回了正确的结果:df['three'] = df.groupby(['one', 'two'])['three'].ffill().bfill() - Andy L.
3
@Andy L. 它的工作是正确的,因为最后一组只是 NaN 组。如果将示例数据更改为仅包含 NaN 组(从 10 更改为 NaN),则您的解决方案会失败。原因是最后一个 bfill 不是按组而是按返回的 groupby + ffill Series 进行操作。 - jezrael
1
啊,我忘记了 bfill 是从输出序列中的 ffill 进行回填,而不是从 groupby 进行回填。感谢您的答案。 - Andy L.
1
请问,如何将 df['three'] = df.groupby(['one','two'], sort=False)['three'].apply(lambda x: x.ffill().bfill()) 应用于多个列 three, four, five, etc 而不仅仅是 three,需要按 onetwo 进行分组并填充缺失值? - ah bon
2
@ahbon - 使用 cols = ['three','four','five']df[cols] = df.groupby(['one','two'], sort=False)[cols].apply(lambda x: x.ffill().bfill()) - jezrael
显示剩余8条评论

2

您可以按包含缺失值的列进行排序,然后进行分组并向前填充:

df.sort_values('three', inplace=True)
df['three'] = df.groupby(['one','two'])['three'].ffill()

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