命名Pandas聚合函数中的返回列?[duplicate]

xdyibdwo  于 2022-12-02  发布在  其他
关注(0)|答案(6)|浏览(141)

此问题在此处已有答案

Multiple aggregations of the same column using pandas GroupBy.agg()(4个答案)
三年前就关门了。
我在使用Pandas的groupby功能时遇到了问题。我读过the documentation,但我看不出如何将聚合函数应用于多个列 * 和 * 为这些列提供了自定义名称。
这非常接近,但是返回的数据结构具有嵌套的列标题:

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

(ie.我想取column2的mean和std,但将这些列返回为“mean”和“std”)
我错过了什么?

kdfy810k

kdfy810k1#

对于Pandas〉= 0.25

命名返回的聚合列的功能是reintroduced in the master branch,针对panda 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

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

对于Pandas〈0.25

unutbu目前接受的答案描述了在〈= 0.20的panda版本中执行此操作的很好的方法。但是,从panda 0.20开始,使用此方法会引发一个警告,表明该语法在panda的未来版本中将不可用。
系列:
未来警告:不赞成在Series上使用dict进行聚合,在将来的版本中将删除此功能
数据框:
未来警告:不赞成使用带有重命名的dict,在将来的版本中将删除它
根据Pandas0.20的修改日志,在聚合时重命名列的推荐方法如下。

# 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变更记录以取得其他详细信息。

更新2017 - 01 - 03以回应@JunkMechanic的评论。

使用旧式字典语法,可以将多个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。合适的函数名称还可以避免以后在 Dataframe 上调用.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
368yc8dk

368yc8dk2#

This will drop the outermost level from the hierarchical column index:

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

If you'd like to keep the outermost level, you can use the ravel() function on the multi-level column to form new labels:

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

update: in newer pandas instead of .ravel() use .tolist() or .to_numpy()use df.columns = ["_".join(x) for x in df.columns.tolist()]

For example:

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())

yields

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

Alternatively, to keep the first level of the index:

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

yields

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
kr98yfug

kr98yfug3#

我同意OP的观点,在同一个地方命名和定义输出列似乎更自然、更一致(例如,使用tidyverse's summarize in R时),但目前panda中的一个解决方案是在聚合之前 * 通过assign * 创建具有所需名称的新列:

data.assign(
    f=data['column1'],
    mean=data['column2'],
    std=data['column2']
).groupby('Country').agg(dict(f=sum, mean=np.mean, std=np.std)).reset_index()

(使用reset_index会将'Country''f''mean''std'全部转换为具有单独整数索引的常规列。)

ryoqjall

ryoqjall4#

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

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

它将更改您的 Dataframe :

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
mm5n2pyu

mm5n2pyu5#

@Joel Ostblom的灵感
对于那些已经有一个仅用于聚合的可用字典的人,可以使用/修改以下代码用于较新版本的聚合,分离聚合和重命名部分。如果有多个项,请注意嵌套字典。

def agg_translate_agg_rename(input_agg_dict):
    agg_dict = {}
    rename_dict = {}
    for k, v in input_agg_dict.items():
        if len(v) == 1:
            agg_dict[k] = list(v.values())[0]
            rename_dict[k] = list(v.keys())[0]
        else:
            updated_index = 1
            for nested_dict_k, nested_dict_v in v.items():
                modified_key = k + "_" + str(updated_index)
                agg_dict[modified_key] = nested_dict_v
                rename_dict[modified_key] = nested_dict_k
                updated_index += 1
    return agg_dict, rename_dict

one_dict = {"column1": {"foo": 'sum'}, "column2": {"mean": 'mean', "std": 'std'}}
agg, rename = agg_translator_aa(one_dict)

我们得到

agg = {'column1': 'sum', 'column2_1': 'mean', 'column2_2': 'std'}
rename = {'column1': 'foo', 'column2_1': 'mean', 'column2_2': 'std'}

如果有更聪明的方法,请告诉我。谢谢。

vktxenjb

vktxenjb6#

比如这种 Dataframe ,列名有两层:

shop_id  item_id   date_block_num item_cnt_day       
                                  target              
0   0       30          1            31

我们可以使用以下代码:
df.columns = [col[0] if col[-1]=='' else col[-1] for col in df.columns.values]
结果是:

shop_id  item_id   date_block_num target              
0   0       30          1            31

相关问题