【问题标题】:How do I pass a pandas method as a parameter?如何将 pandas 方法作为参数传递?
【发布时间】:2019-06-12 15:41:10
【问题描述】:

我有一个计算熊猫数据框列模式的函数:

def my_func(df):
    for col in df.columns:
        stat = df[col].mode()
        print(stat)

但我想让它更通用,以便我可以更改我计算的统计数据,例如mean, max,... 我试图将方法 mode() 作为参数传递给我的函数:

def my_func(df, pandas_stat):
    for col in df.columns:
        stat = df[col].pandas_stat()
        print(stat)

已提及:How do I pass a method as a parameter in Python

但这似乎对我不起作用。 用一个简单的例子:

> A
     a    b
0  1.0  2.0
1  2.0  4.0
2  2.0  6.0
3  3.0  NaN
4  NaN  4.0
5  3.0  NaN
6  2.0  6.0
7  4.0  6.0

不识别命令模式:

> my_func(A, mode)
Traceback (most recent call last):

  File "<ipython-input-332-c137de83a530>", line 1, in <module>
    my_func(A, mode)

NameError: name 'mode' is not defined

所以我尝试了 pd.DataFrame.mode:

> my_func(A, pd.DataFrame.mode)
Traceback (most recent call last):

  File "<ipython-input-334-dd913410abd0>", line 1, in <module>
    my_func(A, pd.DataFrame.mode)

  File "<ipython-input-329-8acf337bce92>", line 3, in my_func
    stat = df[col].pandas_stat()

  File "/anaconda3/envs/py36/lib/python3.6/site-packages/pandas/core/generic.py", line 4376, in __getattr__
    return object.__getattribute__(self, name)

AttributeError: 'Series' object has no attribute 'pandas_stat'

有没有办法通过mode函数?

【问题讨论】:

    标签: python pandas parameter-passing


    【解决方案1】:

    您可以使用内置的[getattr][1]__name__ 属性来执行此操作,但我想这会使您的代码有些不清楚。可能存在更好的方法。

    df = pd.DataFrame({'col1': list(range(5)), 'col2': list(range(5, 0, -1))})
    df
    Out:
       col1  col2
    0     0     5
    1     1     4
    2     2     3
    3     3     2
    4     4     1
    

    以这种方式定义my_func并将其应用于df

    def my_func(df, pandas_stat):
        for col in df.columns:
            stat = getattr(df[col], pandas_stat.__name__)()
            print(stat)
    
    my_func(df, pd.DataFrame.mean)
    Out
    2.0
    3.0
    

    解释:pd.DataFrame.mean 具有属性__name__,其值为'mean'。 Getattr 可以从pd.DataFrame 对象中获取此属性,而不是您可以调用它。

    如果需要,您甚至可以传递参数:

    def my_func(df, pandas_stat, *args, **kwargs):
        for col in df.columns:
            stat = getattr(df[col], pandas_stat.__name__)(*args, **kwargs)
            print(stat)
    
    my_func(df, pd.DataFrame.apply, lambda x: x ** 2)
    Out: 
    0     0
    1     1
    2     4
    3     9
    4    16
    Name: col1, dtype: int64
    0    25
    1    16
    2     9
    3     4
    4     1
    Name: col2, dtype: int64
    

    但我再说一遍,我想这种方法有点令人困惑。

    编辑
    关于一个错误:

    > my_func(A, pd.DataFrame.mode)
    Traceback (most recent call last):
    
      File "<ipython-input-334-dd913410abd0>", line 1, in <module>
        my_func(A, pd.DataFrame.mode)
    
      File "<ipython-input-329-8acf337bce92>", line 3, in my_func
        stat = df[col].pandas_stat()
    
      File "/anaconda3/envs/py36/lib/python3.6/site-packages/pandas/core/generic.py", line 4376, in __getattr__
        return object.__getattribute__(self, name)
    
    AttributeError: 'Series' object has no attribute 'pandas_stat'
    

    df[col].pandas_stat() 被执行时,一个点. 操作符会调用一个__getattribute__ 数据框对象的方法。它类似于 getattr,但它会自动将 self 作为第一个参数。
    因此,第二个是方法的“名称”,即代码中的'pandas_stat'。它破坏了执行,因为 pandas 数据框没有具有此类名称的属性。

    如果您向getattr 提供正确的实际方法名称('mean'、'apply' 等),此函数会在列出所有方法的pd.DataFrame.__dict__ 中找到此方法,并将其返回。所以你可以通过(*args, **kwargs)语法调用它。

    【讨论】:

    • 感谢您的解释。在您的方法中使用 pd.DataFrame.mean 和 pandas_stat.__name__ 或使用 pandas_stat 的“均值”有什么好处,如下面@Bubastis 的回答?
    • 取决于你想要什么。可能,更简单的重构,如果你使用一些 IDE 是最明显的优势。当然,您可以只提供一个名称作为参数,或者更早地分配一个方法的名称,例如name = pd.DataFrame.__name__。因此,您可以保留@Bubastis 的方法并轻松重构您的代码。但恐怕,这主要是一个设计问题,我不知道正确答案。我写了我的答案,假设您希望将方法本身作为参数发送;否则你可以使用@Bubastis 的方法,它看起来更简洁,我也使用了类似的模式
    【解决方案2】:

    您可以使用getattr

    def my_func(df, pandas_stat):
        for col in df.columns:
            print(getattr(df[col], pandas_stat)())  # the empty parenthesis
                                                           # are required to call
                                                           # the method
    
    df_max = my_func(df, "max")
    

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 2015-03-10
      • 2015-01-22
      • 1970-01-01
      • 2018-02-05
      • 1970-01-01
      • 2010-11-16
      相关资源
      最近更新 更多