【问题标题】:How to apply multiple functions to a pandas dataframe without multiple loops?如何在没有多个循环的情况下将多个函数应用于熊猫数据框?
【发布时间】:2016-01-07 15:44:30
【问题描述】:

我将 pandas 用于 ETL 过程。我查询数据库,将结果放入数据框中;数据框非常大(1M 行 * 50 列)。数据框主要由字符串和日期组成。

我使用 pandas 的apply() 函数来进行所有的转换。问题是我的转换在字符串上包含多个分支。

df['merged_contract_status'] = df.apply(lib.merged_contract_status, axis=1) 
df['renewed'] = df.apply(lib.contract_renewed, axis=1)
df['renewal_dt'] = df.apply(lib.contract_renewed_date, axis=1)
....

我有一堆这样的转变。 我调用的函数:

def merged_contract_status(row):
    if row['tbm_contract_status'] is not np.nan:
        mergedContractStatus = row['tbm_contract_status']
    else:
        mergedContractStatus = row['ccn_status']

    return mergedContractStatus

def contract_renewed(row):
    ccn_activation_dt = row['ccn_activation_dt']
    ccn_status = row['ccn_status']
    f_init_val_dt = row['f_init_val_dt']
    f_nat_exp_dt = row['f_nat_exp_dt']
    spr_spo_code = row['spr_spo_code']  
    csp_status_sep_1 = row['csp_status_sep_1']
    csp_begin_dt_sep_1 = row['csp_begin_dt_sep_1']
    ctt_type_1 = row['ctt_type_1']  
    csp_status_sep_2 = row['csp_status_sep_2']
    csp_begin_dt_sep_2 = row['csp_begin_dt_sep_2']
    ctt_type_2 = row['ctt_type_2']  
    csp_status_sep_3 = row['csp_status_sep_3']
    csp_begin_dt_sep_3 = row['csp_begin_dt_sep_3']
    ctt_type_3 = row['ctt_type_3']
    csp_begin_dt_sep_father = row['csp_begin_dt_sep_father']
    csp_end_dt_sep_father = row['csp_end_dt_sep_father']
    todayDate = datetime.datetime.today()       

    if spr_spo_code == 'PCC':       
        if ctt_type_1 == 'NORMAL' and ccn_activation_dt is not None and csp_begin_dt_sep_1 is not None and csp_begin_dt_sep_1>(ccn_activation_dt+timedelta(365)):
            return 'Y'
        elif ctt_type_2 == 'NORMAL' and ccn_activation_dt is not None and csp_begin_dt_sep_2 is not None and csp_begin_dt_sep_2>(ccn_activation_dt+timedelta(365)):
            return 'Y'
        elif ctt_type_3== 'NORMAL' and ccn_activation_dt is not None and csp_begin_dt_sep_3 is not None and csp_begin_dt_sep_3>(ccn_activation_dt+timedelta(365)):
            return 'Y'
        else:
            return 'N'
    else:
        if (f_init_val_dt is None and f_nat_exp_dt is None and 
            ccn_activation_dt is not None and 
            ccn_activation_dt < (todayDate- timedelta(365)) and 
            (csp_begin_dt_sep_father <= todayDate and csp_begin_dt_sep_father >= todayDate and ccn_status=='ACTIVATED')):
            return 'Y'
        elif f_init_val_dt is not None and f_nat_exp_dt is not None and f_init_val_dt <= todayDate and f_nat_exp_dt >= todayDate and ccn_status=='ACTIVATED' and ccn_activation_dt is not None and ccn_activation_dt < (todayDate- timedelta(365)):
            return 'Y'
        else:
            return 'N'

每次我在我的 df 上调用 apply 时,pandas 都会遍历整个 df,大约需要 10 分钟。我觉得那 10 分钟没问题;我知道我无法提高性能。 但是有没有办法避免多重循环?熊猫可以只循环一次并完成我想要的所有转换吗?

编辑:很难给你数据,因为数据框很大,而且它是用 sql 查询构建的。 我想要的帮助是一种只在数据帧中循环一次的方法,我不想改进每个函数(对于那些在字符串上分支是不可能的)

谢谢

【问题讨论】:

  • 如果你展示你的函数在做什么、一些示例数据、重现你的df和所需的df的代码会有所帮助
  • 也许 .groupby().agg() 方法会有所帮助?例如:stackoverflow.com/questions/22128218/…

标签: python performance pandas apply


【解决方案1】:

Python 和 Pandas 一次只能做一件事。你的函数做了很多事情,你可以将它们一起构建成一个函数。但这实际上不是你的问题。

使用axis=1 应用函数非常繁重,因为您正在迭代整个数据帧。

您正在使用 pandas,但您没有使用 pandas。

你应该重写你应用到向量化操作中的函数。

看来.loc method 可以帮到你很多

根据您在 if 语句中使用的任何内容为您的数据框编制索引

df.set_index(['spr_spo_code', 'ctt_type_1', 'ccn_activation_dt'], inplace=True)

等等。

然后你可以使用.loc,但首先你应该在你想要结果的地方创建一个列。

df['Contract_renewed'] = 'N'
df.loc['PCC', 'NORMAL', None ..., 'Contract_renewed'] = 'Y'

而且这会比你目前的操作方式快得多。

小例子

>>> df = pd.DataFrame({'foo':[1,2,3], 'bar':['baz','boo','bee'], 'baz':['N']*3})
>>> df.set_index(['bar', 'foo'], inplace=True)
>>> df.loc[('baz', 1), 'baz'] = 'Y'
>>> df
        baz
bar foo    
baz 1     Y
boo 2     N
bee 3     N

【讨论】:

  • 是的,我同意这一点,我知道这一点。但是你可以猜到,因为我处理的是字符串,所以不可能将我的函数重写为矢量化操作。
  • 这不是不可能的。 Pandas 也为字符串提供了许多不错的向量化操作。 pandas.pydata.org/pandas-docs/version/0.15.0/…
猜你喜欢
  • 2018-12-11
  • 1970-01-01
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 2014-03-31
  • 1970-01-01
  • 2014-07-04
相关资源
最近更新 更多