Python - Pandas系列 - 最强pandas.DataFrame.agg解释

官方网址:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.aggregate.html

目的

该篇文章主要线路为探索agg的基本用法,以及对应有哪些适用场景,最后做一个简单探索源代码层。

1、介绍agg的参数及使用demo

2、GroupBy的agg用法案例

3、通过查看底层推演agg的路线原理

1、介绍agg的参数及使用demo

aggaggregate的别名

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的别名,因为一开始底层代码就有这条赋值语句。

image.png

2、agg其实就是调用apply函数,也就是apply函数能用的它也能用

image.png
  • 做个测试看看,返回的结果是一样的。

  •   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模块的,再找不到就报错。

你可能感兴趣的:(Python - Pandas系列 - 最强pandas.DataFrame.agg解释)