78_Pandasagg()和aggregate()的用法
通过使用pandas.DataFrame和Series的agg()或aggregate()方法,可以对行或列同时应用多个操作进行聚合。agg()是aggregate()的别名,二者用法相同。
pandas.DataFrame.agg — pandas 2.1.3 文档
pandas.Series.agg — pandas 2.1.3 文档
目录
- agg()和aggregate()是相同的
- agg()的基本用法
- 对于pandas.DataFrame
- 对于pandas.Series
- agg()的第一个参数可以指定的操作(函数或方法)
- 函数或方法名的字符串
- 可调用对象
- 指定函数或方法的参数
- 对不支持的数据类型dtype的处理
如果希望一次性获取各列的主要统计量(如平均值、标准差等),可以使用describe()方法,比通过agg()指定列表更简单。
相关文章:59_Pandas中使用describe获取每列的汇总统计信息(平均值、标准差等)
本文代码示例中使用的pandas和NumPy版本如下。需要注意的是,不同版本可能存在差异。
import pandas as pd
import numpy as np
print(pd.__version__)
# 2.1.2
print(np.__version__)
# 1.26.1
agg()和aggregate()是相同的
如开头所述,agg()是aggregate()的别名,二者效果相同。
print(pd.DataFrame.agg is pd.DataFrame.aggregate)
# True
print(pd.Series.agg is pd.Series.aggregate)
# True
agg()的基本用法
对于pandas.DataFrame
以下是一个DataFrame示例:
df = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df)
# A B
# 0 0 3
# 1 1 4
# 2 2 5
在agg()的第一个参数中,可以指定要应用的函数或方法的名称(字符串)、可调用对象或其列表。以下示例使用字符串,详细说明见后文。
当指定列表时,返回DataFrame;当单独指定字符串或可调用对象时,返回Series。即使元素数量为1,只要是列表,返回的也是DataFrame。
print(df.agg(['sum', 'mean', 'min', 'max']))
# A B
# sum 3.0 12.0
# mean 1.0 4.0
# min 0.0 3.0
# max 2.0 5.0
print(type(df.agg(['sum', 'mean', 'min', 'max'])))
# <class 'pandas.core.frame.DataFrame'>
print(df.agg(['sum']))
# A B
# sum 3 12
print(type(df.agg(['sum'])))
# <class 'pandas.core.frame.DataFrame'>
print(df.agg('sum'))
# A 3
# B 12
# dtype: int64
print(type(df.agg('sum')))
# <class 'pandas.core.series.Series'>
通过指定一个以列名为键(key),操作为值(value)的字典,可以对不同列应用不同的操作。
print(df.agg({'A': ['sum', 'min', 'max'], 'B': ['mean', 'min', 'max']}))
# A B
# sum 3.0 NaN
# min 0.0 3.0
# max 2.0 5.0
# mean NaN 4.0
如果操作不是列表而是单独指定,则返回Series。如果任一列指定了列表,则返回DataFrame。
print(df.agg({'A': 'sum', 'B': 'mean'}))
# A 3.0
# B 4.0
# dtype: float64
print(df.agg({'A': ['sum'], 'B': 'mean'}))
# A B
# sum 3.0 NaN
# mean NaN 4.0
print(df.agg({'A': ['min', 'max'], 'B': 'mean'}))
# A B
# min 0.0 NaN
# max 2.0 NaN
# mean NaN 4.0
默认情况下,agg()按列操作。如果将参数axis设置为1或’columns’,则按行操作。
print(df.agg(['sum', 'mean', 'min', 'max'], axis=1))
# sum mean min max
# 0 3.0 1.5 0.0 3.0
# 1 5.0 2.5 1.0 4.0
# 2 7.0 3.5 2.0 5.0
对于pandas.Series
以下是一个Series示例:
s = pd.Series([0, 1, 2])
print(s)
# 0 0
# 1 1
# 2 2
# dtype: int64
当agg()的第一个参数为列表时,返回Series;当单独指定时,返回标量值。即使元素数量为1,只要是列表,返回的也是Series。
print(s.agg(['sum', 'mean', 'min', 'max']))
# sum 3.0
# mean 1.0
# min 0.0
# max 2.0
# dtype: float64
print(type(s.agg(['sum', 'mean', 'min', 'max'])))
# <class 'pandas.core.series.Series'>
print(s.agg(['sum']))
# sum 3
# dtype: int64
print(type(s.agg(['sum'])))
# <class 'pandas.core.series.Series'>
print(s.agg('sum'))
# 3
print(type(s.agg('sum')))
# <class 'numpy.int64'>
如果通过字典指定,键(key)将作为结果的标签名,而值(value)为要执行的操作。
print(s.agg({'Total': 'sum', 'Average': 'mean', 'Min': 'min', 'Max': 'max'}))
# Total 3.0
# Average 1.0
# Min 0.0
# Max 2.0
# dtype: float64
字典的值(value)不能指定为列表。
# print(s.agg({'NewLabel_1': ['sum', 'max'], 'NewLabel_2': ['mean', 'min']}))
# SpecificationError: nested renamer is not supported
agg()的第一个参数可以指定的操作(函数或方法)
函数或方法名的字符串
agg()的第一个参数中指定的字符串会通过_apply_str()
函数进行检查。此前,这一函数名为_try_aggregate_string_function()
。
def _apply_str(self, obj, func: str, *args, **kwargs):
"""
...
如果 arg
是字符串,则尝试对其进行操作:
- 尝试在
obj
上找到一个函数(或属性) - 尝试找到一个
numpy
函数 - 抛出错误
obj
(此处为 Series
或 DataFrame
)的与方法、属性以及 NumPy
函数名称一致的字符串是有效的。
例如,'count'
是 Series
和 DataFrame
的方法,但在 NumPy
中不存在;而 'amax'
是 NumPy
的函数,但在 Series
和 DataFrame
中不存在。两者均可通过字符串指定。
pandas.Series.count
— pandas 2.1.3 文档
numpy.amax
— NumPy v1.26 手册
df = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df)
# A B
# 0 0 3
# 1 1 4
# 2 2 5
print(df.agg(['count', 'amax']))
# A B
# count 3 3
# amax 2 5
print(df['A'].count())
# 3
# print(np.count(df['A']))
# AttributeError: module 'numpy' has no attribute 'count'
print(np.amax(df['A']))
# 2
# print(df['A'].amax())
# AttributeError: 'Series' object has no attribute 'amax'
与上述规则不匹配的字符串将导致错误。
# print(df.agg(['xxx']))
# AttributeError: 'xxx' is not a valid function for 'Series' object
# print(df.agg('xxx'))
# AttributeError: 'xxx' is not a valid function for 'DataFrame' object
从上述错误信息可以看出,当以列表形式指定时,将使用 Series
的方法;当以单独字符串形式指定时,将使用 DataFrame
的方法或属性。
此外,从 _apply_str()
的源代码可以看出,NumPy
函数在 obj
拥有 __array__
属性时才有效。
DataFrame
和 Series
拥有 __array__
属性,但 groupby()
、resample()
和 rolling()
等返回的对象不具备此属性。
print(hasattr(pd.DataFrame, '__array__'))
# True
print(hasattr(pd.core.groupby.GroupBy, '__array__'))
# False
因此,对于 groupby()
、resample()
、rolling()
等返回的对象的 agg()
方法,NumPy
函数名称的字符串是无效的,但可以通过调用对象(如 np.xxx
)的形式指定。
需要注意的是,这是 pandas 2.1.2
的行为,版本不同可能会有差异。
可调用对象
agg()
的第一个参数可以指定可调用对象,例如通过 def
定义的函数或匿名函数(lambda 表达式)。
df = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df)
# A B
# 0 0 3
# 1 1 4
# 2 2 5
def my_func(x):
return x.min() + x.max()
print(df.agg([my_func, lambda x: x.min() - x.max()]))
# A B
# my_func 2 8
# <lambda> -2 -2
为函数或方法指定参数
通过 agg()
指定的关键字参数将传递给应用的函数或方法。
df = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df)
# A B
# 0 0 3
# 1 1 4
# 2 2 5
print(df.agg('std'))
# A 1.0
# B 1.0
# dtype: float64
print(df.agg('std', ddof=0))
# A 0.816497
# B 0.816497
# dtype: float64
print(df.agg(['std'], ddof=0))
# A B
# std 0.816497 0.816497
当指定多个函数或方法时,所有关键字参数都会传递给它们。如果某个函数无法接受参数,则会引发错误。
# print(df.agg(['max', 'std'], ddof=0))
# TypeError: max() got an unexpected keyword argument 'ddof'
如果需要为每个函数分别指定参数,可以使用 lambda 表达式。
print(df.agg(['max', lambda x: x.std(ddof=0)]))
# A B
# max 2.000000 5.000000
# <lambda> 0.816497 0.816497
处理不支持的数据类型 (dtype
)
以下示例以包含字符串列的 DataFrame
为例:
df_str = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5], 'C': ['X', 'Y', 'Z']})
print(df_str)
# A B C
# 0 0 3 X
# 1 1 4 Y
# 2 2 5 Z
例如,从包含字符串的 Series
上调用 mean()
会引发错误,因此通过 agg()
指定时也会出错。
# df_str['C'].mean()
# TypeError: Could not convert XYZ to numeric
# print(df_str.agg(['mean']))
# TypeError: Could not convert string 'XYZ' to numeric
需要注意的是,这是 pandas 2.1.2
的行为。在 pandas 1.0.4
中不会引发错误,而是返回 NaN
。
DataFrame
的 mean()
实现了 numeric_only
参数,但 Series
的 mean()
未实现该参数。因此,当以列表形式指定(按 Series
处理)时,numeric_only
无法使用。
pandas.DataFrame.mean
— pandas 2.1.3 文档
print(df_str.mean(numeric_only=True))
# A 1.0
# B 4.0
# dtype: float64
print(df_str.agg('mean', numeric_only=True))
# A 1.0
# B 4.0
# dtype: float64
# df_str['C'].mean(numeric_only=True)
# TypeError: Series.mean does not allow numeric_only=True with non-numeric dtypes.
# print(df_str.agg(['mean'], numeric_only=True))
# TypeError: Series.mean does not allow numeric_only=True with non-numeric dtypes.
如果只希望针对数值列,可以在调用 agg()
前使用 select_dtypes()
。
print(df_str.select_dtypes(include='number').agg(['sum', 'mean']))
# A B
# sum 3.0 12.0
# mean 1.0 4.0