Pandas的groupby在1.1.0版本中使用fillna后会丢失分组列

6

我有一段pandas代码,曾经在1.0.5版本中能够运行。以下是我问题的一个简化、自包含的示例:

import pandas as pd

df = pd.DataFrame(data=[
    ('bk1', 10),
    ('bk1', None),
    ('bk1', 13),
    ('bk1', None),
    ('bk2', None),
    ('bk2', 14),
    ('bk3', 12),
    ('bk3', None),
], columns=('book', 'price'))


grouped = df.groupby(['book'], as_index=False, sort=False)
df = grouped.fillna(method='ffill')

print(df)

在这个例子中,我们有一份图书销售清单,其中一些价格缺失。我们试图通过使用前一行来填补缺失的数据,其中该行是相同的书。
在 Pandas 1.0.5 中,这将生成一个包含两列的数据框:
  book  price
0  bk1   10.0
1  bk1   10.0
2  bk1   13.0
3  bk1   13.0
4  bk2    NaN
5  bk2   14.0
6  bk3   12.0
7  bk3   12.0

在Pandas 1.1.0版本中,这将删除书籍列,使输出不可用。
   price
0   10.0
1   10.0
2   13.0
3   13.0
4    NaN
5   14.0
6   12.0
7   12.0

我已阅读了版本1.1.0的更新说明,但未找到任何有关此更改的说明。

问题:

  1. 这是Pandas中的错误还是我依赖于未定义的行为?
  2. 是否有更自然的方式来表达这个问题?

你可能会问的问题:

  1. 为什么不在groupby之外使用fillna?

    在这个例子中,第一行bk2没有价格,但用前一行填充它是没有意义的,因为前一行是bk1的价格。

  2. 为什么使用ffill而不是删除NA值?

    我的真实代码与时间序列数据一起工作,ffill是表达最新观察结果的最自然方式。


这不是 bug....ffill 是通过前一个非 NaN 值填充 NaN,bk2,NaN 显示在第一个位置,因此它不会被填充。 - BENY
这是有意为之的。我不想让ffill在组之间填充。请参见“您可能会问的问题#1”。问题在于缺少列。 - Nick ODell
2个回答

8

解决方法

groupby可以表示为:

df = grouped.apply(lambda df: df.fillna(method='ffill'))

这将在两个版本中均可正常工作。

原因

这个问题可能与此更改相关,尽管它发生在不同的版本中:

DataFrameGroupBy的方法 ffillbfillpadbackfill以前在返回值中包括组标签,在其他groupby转换中不一致。现在只返回填充的值。(GH21521)

(来源。)


1
“transform”可以同样在此处使用,并进行赋值。我敢说,在这种情况下它会比apply更快。不过你确实发现了问题的根源。 df["price"] = grouped.transform("ffill") - sammywemmy

5
你可以采用不同于Nick ODell提出的解决方案的方法来解决这个问题,方法是使用 update 函数。
df.update(df.groupby(['book']).ffill())
print(df)
Out[1]: 
  book  price
0  bk1   10.0
1  bk1   10.0
2  bk1   13.0
3  bk1   13.0
4  bk2    NaN
5  bk2   14.0
6  bk3   12.0
7  bk3   12.0

这在两个版本中都有效。

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