为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在使用 DataFrameGroupBy.agg 时可以访问传递给聚合函数的系列

为什么在使用 DataFrameGroupBy.agg 时可以访问传递给聚合函数的系列

皈依舞 2021-10-10 16:45:14
我在玩弄我无法解释的对象apply和agg方法时进行了观察DataFrameGroupBy。介绍我理解以下代码,但它作为问题的介绍可能很有用。我正在分组 DataFrame my_df   key col0 col10    1    A    B1    1    C    D2    2    E    F3    2    G    H按'key'列然后apply按函数def func(df):      return ''.join(df['col0'] + df['col1'])产生>>> my_df.groupby('key').apply(func)key1    ABCD2    EFGHdtype: object这按预期工作。我可以访问列'col0','col1'因为func使用时传递给的“分组块”apply是数据帧。题我不明白为什么KeyError在使用agg而不是apply使用相同的功能时会引发no 。>>> my_df.groupby('key').agg(func)                                          col0  col1key            1    ABCD  ABCD2    EFGH  EFGH据我了解,当使用aggthen 时,func会Series 为 的每一列的每个组传递一个my_df,因此df参数应该是类型Series,并且尝试执行df['col0']并且df['col1']应该生成一个KeyError.为什么会agg产生结果?我的在哪里KeyError?研究我确认,df是Series不能被索引与df['col0']和df['col1']与调试。然而my_df.groupby('key').agg(func)神奇的作品。设置:from IPython.core.debugger import Pdbimport sysdef set_trace():    Pdb().set_trace(sys._getframe().f_back)def func(df):     set_trace()     return ''.join(df['col0'] + df['col1'])用法:>>> my_df.groupby('key').agg(func)> <ipython-input-258-9f34bde72bce>(9)func()      6       7 def func(df):      8      set_trace()----> 9      return ''.join(df['col0'] + df['col1'])     10 ipdb> type(df)<class 'pandas.core.series.Series'>ipdb> df0    A1    CName: col0, dtype: objectipdb> df['col0']*** KeyError: 'col0'ipdb> df['col1']*** KeyError: 'col1'
查看完整描述

2 回答

?
守候你守候我

TA贡献1802条经验 获得超10个赞

它实际上确实引发了一个KeyError你可以在包装访问时看到的try/except:


In [23]: def func(df): 

    ...:     print(type(df))

    ...:     print(df)

    ...:     print()

    ...:     try:

    ...:         df['col0']

    ...:     except KeyError:

    ...:         print('[Error]')

    ...:     return ''.join(df['col0'] + df['col1'])

    ...: 

    ...:

In [24]: df.groupby('key').agg(func)

<class 'pandas.core.series.Series'>

0    A

1    C

Name: col0, dtype: object

[Error]


<class 'pandas.core.series.Series'>

0    A

1    C

Name: col0, dtype: object

[Error]


<class 'pandas.core.series.Series'>

0    A

1    C

Name: 1, dtype: object

[Error]


<class 'pandas.core.frame.DataFrame'>

   key col0 col1

0    1    A    B

1    1    C    D


<class 'pandas.core.frame.DataFrame'>

   key col0 col1

2    2    E    F

3    2    G    H

这KeyError似乎被调用函数排除在外,因此它被静音。


检查一些源代码表明agg实际上调用了这个函数。从这里它首先进入这个函数,它返回Noneifarg是一个函数(这是我们的情况)。最后它会在这里的地方try / except Exception进行。


查看完整回答
反对 回复 2021-10-10
?
猛跑小猪

TA贡献1858条经验 获得超8个赞

agg将整个 DataFrame 传递给func. 从文档中,


func : 函数、字符串、字典或字符串/函数列表 用于聚合数据的函数。如果是函数,则必须在传递 DataFrame 或传递给DataFrame.apply.


我相信这意味着该函数实际上是由 调度的apply,已知它对整个 DataFrame 进行操作。


你可以print在里面通过一个简单的调用来公开它func:


def func(df):

    print(type(df))

    return ''.join(df['col0'] + df['col1']) 

df.groupby('key').agg(func)

<class 'pandas.core.series.Series'>

<class 'pandas.core.series.Series'>

<class 'pandas.core.series.Series'>

<class 'pandas.core.frame.DataFrame'>

<class 'pandas.core.frame.DataFrame'>

Out[87]: 

     col0  col1

key            

1    ABCD  ABCD

2    EFGH  EFGH

所以它确实得到了两个 DataFrame 调用。但它也有 3 个带有 Series 参数的调用,我无法解释为什么会这样,也许是一个错误(我无法在任何地方看到它的记录)。


好吧,仔细想想,这是我能想到的最好的办法。现在,agg不确定您的函数想要如何处理数据,因此它将尝试两种方法并使用首先作为系列工作的任何输出。这似乎是一个实现细节,但 Series 是第一个用于传入数据的方法。如果这不起作用,则回退是传递一个 DataFrame 并希望它成功。让我看看我是否可以让它在一个例子中工作......


from itertools import count

c = count(0)


def func(x):

    i = next(c)

    print(i, type(x))

    if i <3:

        return 'xyz'

    return ((df['col0'] + df['col1']).tolist())


df.groupby('key').agg(func)


0 <class 'pandas.core.series.Series'>

1 <class 'pandas.core.series.Series'>

2 <class 'pandas.core.series.Series'>

3 <class 'pandas.core.series.Series'>

Out[126]: 

    col0              col1

key                       

1    xyz               xyz

2    xyz  [AB, CD, EF, GH]

接下来,改变循环条件,我们有:


def func(x):

    i = next(c)

    print(i, type(x))

    if i in {0, 1}:

        return 'xyz'

    return ((x['col0'] + x['col1']).tolist())


df.groupby('key').agg(func)


0 <class 'pandas.core.series.Series'>

1 <class 'pandas.core.series.Series'>

2 <class 'pandas.core.series.Series'>

3 <class 'pandas.core.series.Series'>

4 <class 'pandas.core.series.Series'>

5 <class 'pandas.core.frame.DataFrame'>

6 <class 'pandas.core.frame.DataFrame'>

Out[157]: 

    col0 col1

key          

1     AB   CD

2     EF   GH

并且,更改i in {0, 1}为i in {0, 4},


0 <class 'pandas.core.series.Series'>

1 <class 'pandas.core.series.Series'>

2 <class 'pandas.core.series.Series'>

3 <class 'pandas.core.series.Series'>

4 <class 'pandas.core.frame.DataFrame'>

5 <class 'pandas.core.frame.DataFrame'>

Out[158]: 

    col0 col1

key          

1    xyz  xyz

2     EF   GH

请注意函数类型的数量如何根据每次返回的内容而变化。


查看完整回答
反对 回复 2021-10-10
  • 2 回答
  • 0 关注
  • 172 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号