官方网址:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.aggregate.html
目的
该篇文章主要线路为探索agg的基本用法,以及对应有哪些适用场景,最后做一个简单探索源代码层。
1、介绍agg的参数及使用demo
2、GroupBy的agg用法案例
3、通过查看底层推演agg的路线原理
1、介绍agg的参数及使用demo
agg
是aggregate
的别名
DataFrame.aggregate
(func=None, axis=0, args,kwargs)
参数名 | 解释 | 传参格式 | 例如 |
---|---|---|---|
func | 用于汇总数据的功能。如果是函数,则必须在传递DataFrame或传递给DataFrame.apply时起作用。 | 函数,str,列表或字典 | [np.sum, 'mean'] |
axis | 如果为0或'index':将函数应用于每一列。如果为1或“列”:将函数应用于每一行。 | {0或'index',1或'columns'},默认0 | 1 |
它会return的数据类型一般为:标量(值)、Series、DataFrame三种。
对应可以使用
标量:使用单个函数调用Series.agg
Series:使用单个函数调用DataFrame.agg
DaFrame:使用多个函数调用DataFrame.agg
返回例子
标量
s_df = pd.Series([1,2,3])
print(s_df)
print(s_df.agg(sum))
---------return----------
0 1
1 2
2 3
dtype: int64
6
Seires
df = pd.DataFrame([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[np.nan, np.nan, np.nan]],
columns=['A', 'B', 'C'])
print(df)
-----return------
A B C
0 1.0 2.0 3.0
1 4.0 5.0 6.0
2 7.0 8.0 9.0
3 NaN NaN NaN
print(df.agg(sum))
----return------
A 12.0
B 15.0
C 18.0
dtype: float64
DataFrame
# 在行上汇总这些功能
print(df.agg(['sum', 'min'])
----return----
A B C
sum 12.0 15.0 18.0
min 1.0 2.0 3.0
# 每列不同的聚合
print(df.agg({'A' : ['sum', 'min'], 'B' : ['min', 'max']}))
----return----
A B
sum 12.0 NaN
min 1.0 2.0
max NaN 8.0
# 在列上聚合不同的函数,然后重命名结果DataFrame的索引
print(df.agg(x=('A', max), y=('B', 'min'), z=('C', np.mean)))
----return----
A B C
x 7.0 NaN NaN
y NaN 2.0 NaN
z NaN NaN 6.0
2、GroupBy的agg用法案例
数据构造
import pandas as pd
df = pd.DataFrame({'Country':['China','China', 'India', 'India', 'America', 'Japan', 'China', 'India'],
'Income':[10000, 10000, 5000, 5002, 40000, 50000, 8000, 5000],
'Age':[5000, 4321, 1234, 4010, 250, 250, 4500, 4321]})
----return----
Age Country Income
0 5000 China 10000
1 4321 China 10000
2 1234 India 5000
3 4010 India 5002
4 250 America 40000
5 250 Japan 50000
6 4500 China 8000
7 4321 India 5000
接下来会按照城市分组,用print()方法给认知groupby的分组逻辑
df.groupby(['Country']).apply(lambda x: print(x,type(x)))
----print----
Country Income Age
4 America 40000 250
Country Income Age
0 China 10000 5000
1 China 10000 4321
6 China 8000 4500
Country Income Age
2 India 5000 1234
3 India 5002 4010
7 India 5000 4321
Country Income Age
5 Japan 50000 250
这儿其实就很清晰了,分组里面的结果就是一个个分组后的DataFrame
。所以针对Groupby后agg的用法,就是DataFrame.agg的用法,不用额外说什么,照样是 列表、字典 形式传入。
列表传参
df_agg = df.groupby('Country').agg(['min', 'mean', 'max'])
print(df_agg)
----print----
Income Age
min mean max min mean max
Country
America 40000 40000.000000 40000 250 250.000000 250
China 8000 9333.333333 10000 4321 4607.000000 5000
India 5000 5000.666667 5002 1234 3188.333333 4321
Japan 50000 50000.000000 50000 250 250.000000 250
字典传参
print(df.groupby('Country').agg({'Age':['min', 'mean', 'max'], 'Income':['min', 'max']}))
---print---
Age Income
min mean max min max
Country
America 250 250.000000 250 40000 40000
China 4321 4607.000000 5000 8000 10000
India 1234 3188.333333 4321 5000 5002
Japan 250 250.000000 250 50000 50000
==总结:==首先了解agg
能传什么形式的func,再清晰groupby
的形式,就知道groupy+agg
结合起来的用法。
3、通过查看底层推演agg的路线原理
为什么要查看这个底层呢?主要是对传func时候,遇到的这几种传参产生好奇,想要知道为什么能这样子传,追根朔源。
这几种传参指的是:
df = pd.DataFrame([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[np.nan, np.nan, np.nan]],
columns=['A', 'B', 'C'])
print(df.agg([sum, 'sum', np.sum]))
------print-----
A B C
sum 12.0 15.0 18.0
sum 12.0 15.0 18.0
sum 12.0 15.0 18.0
sum
、"sum"
、np.sum
的作用效果一样,它们的表达形式不同。
开始查阅底层代码
1、agg = aggregate
, agg是aggregate的别名,因为一开始底层代码就有这条赋值语句。
2、agg其实就是调用apply函数,也就是apply函数能用的它也能用
做个测试看看,返回的结果是一样的。
print(df.apply([sum, 'sum', np.sum])) ----return---- A B C sum 12.0 15.0 18.0 sum 12.0 15.0 18.0 sum 12.0 15.0 18.0
3、所以sum、‘sum’、np.sum 重点是 func 传参解析的作用,而不是函数本身作用。
找一下有关func的注释
func : function
Function to apply to each column or row.
# 解释 函数能用于行或列而已
If you are just applying a NumPy reduction function this will
achieve much better performance.
# 这儿就说如果用numpy的函数,能有更好表现,可以说明np.sum 与 sum 是调用不同模块的函数
找了半天,虽然猜测是 ‘sum’转为sum使用了,但是仍没找到,所以尝试一下这样子。
4、_try_aggregate_string_function
找到转化的原因!
print(df.apply([sum, 'sum', np.sum,'np.sum']))
----error----
...
File "D:\r\Anaconda3\lib\site-packages\pandas\core\series.py", line 3688, in aggregate
result, how = self._aggregate(func, *args, **kwargs)
File "D:\r\Anaconda3\lib\site-packages\pandas\core\base.py", line 477, in _aggregate
return self._aggregate_multiple_funcs(arg, _axis=_axis), None
File "D:\r\Anaconda3\lib\site-packages\pandas\core\base.py", line 507, in _aggregate_multiple_funcs
new_res = colg.aggregate(a)
File "D:\r\Anaconda3\lib\site-packages\pandas\core\series.py", line 3688, in aggregate
result, how = self._aggregate(func, *args, **kwargs)
File "D:\r\Anaconda3\lib\site-packages\pandas\core\base.py", line 311, in _aggregate
return self._try_aggregate_string_function(arg, *args, **kwargs), None
File "D:\r\Anaconda3\lib\site-packages\pandas\core\base.py", line 282, in _try_aggregate_string_function
f"'{arg}' is not a valid function for '{type(self).__name__}' object"
AttributeError: 'np.sum' is not a valid function for 'Series' object
重点看_try_aggregate_string_function
的报错。
该函数如下
def _try_aggregate_string_function(self, arg: str, *args, **kwargs):
"""
if arg is a string, then try to operate on it:
- try to find a function (or attribute) on ourselves
- try to find a numpy function
- raise
"""
assert isinstance(arg, str)
f = getattr(self, arg, None) # 再这里转化的
if f is not None:
if callable(f):
return f(*args, **kwargs)
# people may try to aggregate on a non-callable attribute
# but don't let them think they can pass args to it
assert len(args) == 0
assert len([kwarg for kwarg in kwargs if kwarg not in ["axis"]]) == 0
return f
f = getattr(np, arg, None)
if f is not None:
if hasattr(self, "__array__"):
# in particular exclude Window
return f(self, *args, **kwargs)
raise AttributeError(
f"'{arg}' is not a valid function for '{type(self).__name__}' object"
)
转化的函数是这个f = getattr(np, arg, None)
,它能找到对应是否有函数,注释也有说,如果arg是string格式,会去寻找它本身是否有这个函数,找不到再去寻找numpy模块的,再找不到就报错。