在Pandas聚合函数中命名返回列?

2024-04-24 19:51:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Pandas的groupby功能有问题。我读过the documentation,但我看不到如何将聚合函数应用于多个列并且具有这些列的自定义名称。

这非常接近,但返回的数据结构具有嵌套的列标题:

data.groupby("Country").agg(
        {"column1": {"foo": sum()}, "column2": {"mean": np.mean, "std": np.std}})

(即,我想取第2列的平均值和标准值,但将这些列返回为“平均值”和“标准值”)

我错过了什么?


Tags: the函数功能名称标题数据结构pandasdata
3条回答

如果希望具有类似于JMP的行为,请创建列标题,以保留可以使用的多索引中的所有信息:

newidx = []
for (n1,n2) in df.columns.ravel():
    newidx.append("%s-%s" % (n1,n2))
df.columns=newidx

它将更改您的数据帧:

    I                       V
    mean        std         first
V
4200.0  25.499536   31.557133   4200.0
4300.0  25.605662   31.678046   4300.0
4400.0  26.679005   32.919996   4400.0
4500.0  26.786458   32.811633   4500.0

    I-mean      I-std       V-first
V
4200.0  25.499536   31.557133   4200.0
4300.0  25.605662   31.678046   4300.0
4400.0  26.679005   32.919996   4400.0
4500.0  26.786458   32.811633   4500.0

对于熊猫>;=0.25

命名返回聚合列的功能是reintroduced in the master branch,目标是pandas 0.25。新语法是.agg(new_col_name=('col_name', 'agg_func')。上面链接的PR的详细示例:

In [2]: df = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
   ...:                    'height': [9.1, 6.0, 9.5, 34.0],
   ...:                    'weight': [7.9, 7.5, 9.9, 198.0]})
   ...:

In [3]: df
Out[3]:
  kind  height  weight
0  cat     9.1     7.9
1  dog     6.0     7.5
2  cat     9.5     9.9
3  dog    34.0   198.0

In [4]: df.groupby('kind').agg(min_height=('height', 'min'), 
                               max_weight=('weight', 'max'))
Out[4]:
      min_height  max_weight
kind
cat          9.1         9.9
dog          6.0       198.0

也可以将多个lambda表达式与此语法和我前面(下面)根据this PR建议的两步重命名语法一起使用。同样,复制PR中的示例:

In [2]: df = pd.DataFrame({"A": ['a', 'a'], 'B': [1, 2], 'C': [3, 4]})

In [3]: df.groupby("A").agg({'B': [lambda x: 0, lambda x: 1]})
Out[3]:
         B
  <lambda> <lambda 1>
A
a        0          1

然后.rename(),或者一次性:

In [4]: df.groupby("A").agg(b=('B', lambda x: 0), c=('B', lambda x: 1))
Out[4]:
   b  c
A
a  0  0

对于熊猫<;0.25

联合国大学(unutbu)目前接受的答案是在pandas版本中实现这一点的好方法<;=0.20。但是,从pandas 0.20开始,使用此方法会引发一个警告,指出在pandas的未来版本中,语法将不可用。

系列:

FutureWarning: using a dict on a Series for aggregation is deprecated and will be removed in a future version

数据帧:

FutureWarning: using a dict with renaming is deprecated and will be removed in a future version

根据pandas 0.20 changelog,建议在聚合时重命名列的方法如下。

# Create a sample data frame
df = pd.DataFrame({'A': [1, 1, 1, 2, 2],
                   'B': range(5),
                   'C': range(5)})

# ==== SINGLE COLUMN (SERIES) ====
# Syntax soon to be deprecated
df.groupby('A').B.agg({'foo': 'count'})
# Recommended replacement syntax
df.groupby('A').B.agg(['count']).rename(columns={'count': 'foo'})

# ==== MULTI COLUMN ====
# Syntax soon to be deprecated
df.groupby('A').agg({'B': {'foo': 'sum'}, 'C': {'bar': 'min'}})
# Recommended replacement syntax
df.groupby('A').agg({'B': 'sum', 'C': 'min'}).rename(columns={'B': 'foo', 'C': 'bar'})
# As the recommended syntax is more verbose, parentheses can
# be used to introduce line breaks and increase readability
(df.groupby('A')
    .agg({'B': 'sum', 'C': 'min'})
    .rename(columns={'B': 'foo', 'C': 'bar'})
)

请参阅0.20 changelog了解更多详细信息。

针对@JunkMechanic的评论更新2017-01-03。

使用旧式字典语法,可以将多个lambda函数传递给.agg,因为这些函数将使用传递字典中的键重命名:

>>> df.groupby('A').agg({'B': {'min': lambda x: x.min(), 'max': lambda x: x.max()}})

    B    
  max min
A        
1   2   0
2   4   3

也可以将多个函数作为列表传递给单个列:

>>> df.groupby('A').agg({'B': [np.min, np.max]})

     B     
  amin amax
A          
1    0    2
2    3    4

但是,这不适用于lambda函数,因为它们是匿名的,并且都返回<lambda>,这会导致名称冲突:

>>> df.groupby('A').agg({'B': [lambda x: x.min(), lambda x: x.max]})
SpecificationError: Function names must be unique, found multiple named <lambda>

为了避免SpecificationError,可以预先定义命名函数,而不是使用lambda。合适的函数名还可以避免随后在数据帧上调用.rename。这些函数可以使用与上面相同的列表语法传递:

>>> def my_min(x):
>>>     return x.min()

>>> def my_max(x):
>>>     return x.max()

>>> df.groupby('A').agg({'B': [my_min, my_max]})

       B       
  my_min my_max
A              
1      0      2
2      3      4

这将从分层列索引中删除最外层:

df = data.groupby(...).agg(...)
df.columns = df.columns.droplevel(0)

如果希望保持最外层,可以在多级列上使用ravel()函数来形成新标签:

df.columns = ["_".join(x) for x in df.columns.ravel()]

例如:

import pandas as pd
import pandas.rpy.common as com
import numpy as np

data = com.load_data('Loblolly')
print(data.head())
#     height  age Seed
# 1     4.51    3  301
# 15   10.89    5  301
# 29   28.72   10  301
# 43   41.74   15  301
# 57   52.70   20  301

df = data.groupby('Seed').agg(
    {'age':['sum'],
     'height':['mean', 'std']})
print(df.head())
#       age     height           
#       sum        std       mean
# Seed                           
# 301    78  22.638417  33.246667
# 303    78  23.499706  34.106667
# 305    78  23.927090  35.115000
# 307    78  22.222266  31.328333
# 309    78  23.132574  33.781667

df.columns = df.columns.droplevel(0)
print(df.head())

收益率

      sum        std       mean
Seed                           
301    78  22.638417  33.246667
303    78  23.499706  34.106667
305    78  23.927090  35.115000
307    78  22.222266  31.328333
309    78  23.132574  33.781667

或者,要保持索引的第一级:

df = data.groupby('Seed').agg(
    {'age':['sum'],
     'height':['mean', 'std']})
df.columns = ["_".join(x) for x in df.columns.ravel()]

收益率

      age_sum   height_std  height_mean
Seed                           
301        78    22.638417    33.246667
303        78    23.499706    34.106667
305        78    23.927090    35.115000
307        78    22.222266    31.328333
309        78    23.132574    33.781667

相关问题 更多 >