Pandas groupby(),agg() - 如何在没有多索引的情况下返回结果?

问题描述 投票:0回答:4

我有一个数据框:

pe_odds[ [ 'EVENT_ID', 'SELECTION_ID', 'ODDS' ] ]
Out[67]: 
     EVENT_ID  SELECTION_ID   ODDS
0   100429300       5297529  18.00
1   100429300       5297529  20.00
2   100429300       5297529  21.00
3   100429300       5297529  22.00
4   100429300       5297529  23.00
5   100429300       5297529  24.00
6   100429300       5297529  25.00

当我使用 groupby 和 agg 时,我得到了一个多索引的结果:

pe_odds.groupby( [ 'EVENT_ID', 'SELECTION_ID' ] )[ 'ODDS' ].agg( [ np.min, np.max ] )
Out[68]: 
                         amin   amax
EVENT_ID  SELECTION_ID              
100428417 5490293        1.71   1.71
          5881623        1.14   1.35
          5922296        2.00   2.00
          5956692        2.00   2.02
100428419 603721         2.44   2.90
          4387436        4.30   6.20
          4398859        1.23   1.35
          4574687        1.35   1.46
          4881396       14.50  19.00
          6032606        2.94   4.20
          6065580        2.70   5.80
          6065582        2.42   3.65
100428421 5911426        2.22   2.52

我曾尝试使用 as_index 返回没有 multi_index 的结果:

pe_odds.groupby( [ 'EVENT_ID', 'SELECTION_ID' ], as_index=False )[ 'ODDS' ].agg( [ np.min, np.max ], as_index=False )

但它仍然给我一个多索引。

我可以使用.reset_index(),但是很慢:

pe_odds.groupby( [ 'EVENT_ID', 'SELECTION_ID' ] )[ 'ODDS' ].agg( [ np.min, np.max ] ).reset_index()

pe_odds.groupby( [ 'EVENT_ID', 'SELECTION_ID' ] )[ 'ODDS' ].agg( [ np.min, np.max ] ).reset_index()
Out[69]: 
     EVENT_ID  SELECTION_ID   amin   amax
0   100428417       5490293   1.71   1.71
1   100428417       5881623   1.14   1.35
2   100428417       5922296   2.00   2.00
3   100428417       5956692   2.00   2.02
4   100428419        603721   2.44   2.90
5   100428419       4387436   4.30   6.20

如何在没有多索引的情况下使用 groupby 和/或 agg 函数的参数返回结果。而且不必求助于使用 reset_index() ?

python pandas group-by aggregate multi-index
4个回答
48
投票

低于电话:

>>> gr = df.groupby(['EVENT_ID', 'SELECTION_ID'], as_index=False)
>>> res = gr.agg({'ODDS':[np.min, np.max]})
>>> res
    EVENT_ID SELECTION_ID ODDS     
                          amin amax
0  100429300      5297529   18   25
1  100429300      5297559   30   38

返回具有多索引的框架。如果您不希望列是多索引的,您可以这样做:

>>> res.columns = list(map(''.join, res.columns.values))
>>> res
    EVENT_ID  SELECTION_ID  ODDSamin  ODDSamax
0  100429300       5297529        18        25
1  100429300       5297559        30        38

2
投票

也可以使用

pipe
方法、
set_axis
和链接(我认为这更具可读性)删除列上的 multi_index。

(
pe_odds
.groupby(by=['EVENT_ID', 'SELECTION_ID'] )
.agg([ np.min, np.max ])
.pipe(lambda x: x.set_axis(x.columns.map('_'.join), axis=1))
)

这是没有重置索引的输出。

                        ODDS_amin  ODDS_amax
EVENT_ID  SELECTION_ID                      
100429300 5297529            18.0       25.0
100429300 5297559            30.0       38.0

1
投票

我已经采纳了 Kim 的评论并将其优化(您根本不需要使用 .to_flat_index())到下面的代码中。我相信这是最pythonic(易于理解)和优雅的方法:

df.columns = ["_".join(col_name).rstrip('_') for col_name in df.columns]   

示例用法是:

>>> df.columns = ["_".join(col_name).rstrip('_') for col_name in df.columns]
>>> df
    EVENT_ID  SELECTION_ID  ODDS_amin  ODDS_amax
0  100429300       5297529        18        25
1  100429300       5297559        30        38

0
投票

这是一个适用于

columns
index
的通用解决方案(部分灵感来自@Manuel Bolívar 的回答):

def join_levels(df, delim='_', axis=0):
    return (
        df.set_axis(
            df.axes[axis].map(delim.join),
            axis=axis
        )
    )

然后使用它(例如):

res = (
    pe_odds
    .groupby(['EVENT_ID', 'SELECTION_ID'])
    .agg([np.min, np.max])
    .pipe(join_levels, axis=1)
    # ...
)

为了使用名称空间组织这样的函数,我喜欢将它们收集在一个访问器中,例如(稍作修改):

@pd.api.extensions.register_dataframe_accessor("custom")
class _MyAccessor:
    def __init__(self, pandas_obj: pd.DataFrame):
        self._obj = pandas_obj

    def join_levels(self, delim='_', axis=0):
        return (
            self._obj.set_axis(
                self._obj.axes[axis].map(delim.join),
                axis=axis
            )
        )

然后你可以这样做:

res = (
    pe_odds
    .groupby(['EVENT_ID', 'SELECTION_ID'])
    .agg([np.min, np.max])
    .custom.join_levels(axis=1)
    # ...
)

NB:为了保持代码整洁,您可以将任何访问器放在模块(

.py
文件)的某个地方。只是
import
那个模块和所有的访问器都神奇地可用。

© www.soinside.com 2019 - 2024. All rights reserved.