分组的 Pandas DataFrame 中,前两个组的 apply 函数被执行了两次。

3

我想获取每种动物中体重最大的动物的大小。以下是测试代码:

import numpy as np
import pandas as pd

print('numpy version =', np.__version__)
print('pandas version =', pd.__version__)
print()


def get_size_with_max_weight(subf):
    print(subf)
    return subf['size'][subf['weight'].idxmax()]

df = pd.DataFrame({'animal': 'cat dog cat fish dog cat cat'.split(),
                   'size': list('SSMMMLL'),
                   'weight': [8, 10, 11, 1, 20, 12, 12],
                   'adult': [False] * 5 + [True] * 2})

print(df)
print()


gf = df.groupby('animal').apply(get_size_with_max_weight)
print()
print(gf)

但是当我尝试在DataFrame组中运行apply函数时,每个组应该只被执行一次。但是当使用idxmax()函数作为索引与另一列一起调用时,我发现前两个组的apply函数被执行了两次。以下是输出内容:

numpy version = 1.18.5
pandas version = 1.0.5

  animal size  weight  adult
0    cat    S       8  False
1    dog    S      10  False
2    cat    M      11  False
3   fish    M       1  False
4    dog    M      20  False
5    cat    L      12   True
6    cat    L      12   True

  animal size  weight  adult
0    cat    S       8  False
2    cat    M      11  False
5    cat    L      12   True
6    cat    L      12   True
  animal size  weight  adult
1    dog    S      10  False
4    dog    M      20  False
  animal size  weight  adult
0    cat    S       8  False
2    cat    M      11  False
5    cat    L      12   True
6    cat    L      12   True
  animal size  weight  adult
1    dog    S      10  False
4    dog    M      20  False
  animal size  weight  adult
3   fish    M       1  False

animal
cat     L
dog     M
fish    M
dtype: object

您可以看到,组cat/dog被打印了两次。如果我不使用idxmax()函数,这种情况就不会出现。问题出在哪里?


1
我知道这不是问题,但在pandas 1.3.2中,这种不可重复的行为无法再现。 - Henry Ecker
1
这可能与1.1.0版本中的错误修复有关DataFrame上的apply和applymap仅对第一行/列进行评估 - Henry Ecker
1
你是对的 Henry。我刚刚将 pandas 升级到 1.3.2,问题已经解决了。非常感谢你! - gelu
1个回答

1
这不是一个bug,而是设计如此。
函数apply需要知道组的形状。由于前两个组的形状不同,它会将它们分别打印两次,第一次获取形状,第二次运行代码。
在pandas版本1.1.0中已经修复了这个问题,详见[文档]的"What's New"页面。

apply and applymap on DataFrame evaluates first row/column only once¶

Previous behavior:

df.apply(func, axis=1)
a    1
b    3
Name: 0, dtype: int64
a    1
b    3
Name: 0, dtype: int64
a    2
b    6
Name: 1, dtype: int64
Out[4]:
   a  b
0  1  3
1  2  6

New behavior:

df.apply(func, axis=1)
a    1
b    3
Name: 0, Length: 2, dtype: int64
a    2
b    6
Name: 1, Length: 2, dtype: int64
Out[79]: 
   a  b
0  1  3
1  2  6

[2 rows x 2 columns]

在GitHub上也提到了这里


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