在python/pandas中跨多个列应用类似的函数

在python/pandas中跨多个列应用类似的函数,python,function,for-loop,pandas,Python,Function,For Loop,Pandas,问题:考虑到下面的数据框架,我正在尝试编写代码,将函数应用于三个不同的列,而不必编写三个单独的函数调用 数据的代码: import pandas as pd data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'], 'days': [365, 365, 213, 318, 71], 'spend_30day': [22, 241.5, 0, 27321.05, 345], 'spend_90day': [22,

问题:考虑到下面的数据框架,我正在尝试编写代码,将函数应用于三个不同的列,而不必编写三个单独的函数调用

数据的代码:

import pandas as pd
data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'],
    'days': [365, 365, 213, 318, 71],
    'spend_30day': [22, 241.5, 0, 27321.05, 345],
    'spend_90day': [22, 451.55, 64.32, 27321.05, 566.54],
    'spend_365day': [854.56, 451.55, 211.65, 27321.05, 566.54]}

df = pd.DataFrame(data)
cols = df.columns.tolist()
cols = ['name', 'days', 'spend_30day', 'spend_90day', 'spend_365day']
df = df[cols]
df
下面的功能将基本上按年计算支出;如果某人在“天”列中的天数少于(比如)365天,则以下函数将告诉我如果他们有365天,他们的花费是多少:

def annualize_spend_365(row):
    if row['days']/(float(365)) < 1:
        return (row['spend_365day']/(row['days']/float(365)))
    else:
        return row['spend_365day']
这正是我希望它的一个专栏。但是,我不想为三个不同的支出列30、90、365中的每一个都重写这个。我希望能够编写代码,在一个过程中将此函数推广并应用于多个列

我以为我可以创建列及其各自的日期列表,使用zip函数,并将函数嵌套在for循环中,但我下面的尝试最终失败了:

spend_cols = [df.spend_30day, df.spend_90day, df.spend_365day]
days_list = [30, 90, 365]

for col, day in zip(spend_cols, days_list):
    def annualize_spend(row):
        if (row.days/(float(day)) < 1:
            return (row.col)/((row.days)/float(day))
        else:
            return row.col
    col = df.apply(annualize_spend, axis = 1)

我不知道为什么循环方法会失败。不管怎样,我希望能得到关于如何在熊猫中推广函数应用的指导。提前谢谢

看看您的两个函数定义:

def annualize_spend_365(row):
    if row['days']/(float(365)) < 1:
        return (row['spend_365day']/(row['days']/float(365)))
    else:
        return row['spend_365day']
在你的循环之前。另一方面,在语法df.days中,字段名实际上是days,但在df.col中,字段名不是字符串col,而是字符串col的值。因此,在后一种情况下,您可能还需要使用row[col]。不管怎么说,我不确定在col上的循环中将col作为输出变量有多明智

我不熟悉pandas.DataFrame.apply,但可能使用单个函数定义,它将天数和感兴趣的字段作为输入变量:

def annualize_spend(col,day,row):
    if (row['days']/(float(day)) < 1:
        return (row[col])/((row['days'])/float(day))
    else:
        return row[col]

spend_cols = ['spend_30day', 'spend_90day', 'spend_365day']
days_list = [30, 90, 365]

for col, day in zip(spend_cols, days_list):
    col = df.apply(lambda row,col=col,day=day: annualize_spend(col,day,row), axis = 1)

lambda将确保当函数被应用时,只有一个输入参数是悬空的。

像一个符咒一样工作。我认为我的问题是概念性的,所以感谢你提出了一个更加连贯的计划。如果您有时间,可以解释lambda函数行中的参数,col=col,day=day吗?@milton确定:lambda只能使用显式传递给它的变量,因此您可以将col和day传递给它。用这种方式命名lambda的参数是一件懒惰的事情,也许这会更清楚:lambda var1,var2=col,var3=day:annualize_spendvar2,var3,var1。因此,可以为lambda的最后两个参数设置默认值,从而有效地将其呈现为apply的单个输入函数。由于这些只是默认值,lambda也可以在2或3输入语法中工作,但apply只使用一个变量,因此它最多只能有1个非默认参数。哇,非常感谢您的解释。还有一个更普遍的问题:为什么要将lambda传递给apply函数而不仅仅是函数本身?这就是为什么df.applylambda row,col=col,day=day:annualize\u spendcol,day,row,而不仅仅是df.applylambda nularize\u spend?当已创建lambda功能时,利用lambda功能可获得什么效率/价值?我已经看到这种方法用于更简单的函数,并且很好奇为什么在函数已经创建时调用lambda是必要的。再次感谢,非常有帮助@如果您不使用lambda来尝试它:您应该会得到一个错误,即您的函数需要3个参数,并且只指定了1个参数,那么您的函数应该如何知道col和day是什么?函数定义中的名称是非常任意的,我使用lambda行col=col,day=day:…,这就是一个例子,因此函数定义中变量的名称对程序员没有任何帮助,它只对程序员有帮助。这仅仅是因为apply需要一个输入函数,然后应用到变量上。好吧,我想我明白了:使用多参数lambda是你绕过apply的单参数约束的方法。当需要使用apply或map或applymap应用任何多参数函数时,可以推广这种方法。也就是说,首先显式创建多参数函数。然后将该函数中的每个参数指定为lambda中的变量。最后,通过调用函数和每个参数来完成lambda。再次感谢!
def annualize_spend_365(row):
    if row['days']/(float(365)) < 1:
        return (row['spend_365day']/(row['days']/float(365)))
    else:
        return row['spend_365day']
#col in [df.spend_30day, df.spend_90day, df.spend_365day]
def annualize_spend(row):
    if (row.days/(float(day)) < 1:
        return (row.col)/((row.days)/float(day))
    else:
        return row.col
spend_cols = ['spend_30day', 'spend_90day', 'spend_365day']
def annualize_spend(col,day,row):
    if (row['days']/(float(day)) < 1:
        return (row[col])/((row['days'])/float(day))
    else:
        return row[col]

spend_cols = ['spend_30day', 'spend_90day', 'spend_365day']
days_list = [30, 90, 365]

for col, day in zip(spend_cols, days_list):
    col = df.apply(lambda row,col=col,day=day: annualize_spend(col,day,row), axis = 1)