You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中对同一列应用多个函数?应计计算优化咨询

问题描述

需要为DataFrame的同一列应用三个对应不同计息基准(ACT/360、ACT/365、30/360)的应计计算函数,但当前依次调用apply会覆盖列值,尝试的&拼接写法不正确,希望了解高效可行的实现方案,同时确认将三个函数合并为一个大函数是否合理。

原实现代码:

#Accrued Calc for ACT/360
def bbb(bb):
    if bb["Basis"] == "ACT/360" and bb['Type'] == 'L' and bb['Current Filter'] == 'Current CF':
        return 1 * bb['Principal/GrossAmount'] * (bb['All in Rate']/100)* (bb['Number of days'])/360
    elif  bb["Basis"] == "ACT/360" and bb['Type'] == 'D':
        return -1 * bb['Principal/GrossAmount'] * (bb['All in Rate']/100)* (bb['Number of days'])/360
    else:
        return ''
kf['Accrued Calc'] = kf.apply(bbb, axis = 1)


#Accrued Calc for ACT/365
def ccc(cc):
    if cc["Basis"] == "ACT/365" and cc['Type'] == 'L' and cc['Current Filter'] == 'Current CF':
        return 1 * cc['Principal/GrossAmount'] * (cc['All in Rate']/100)* (cc['Number of days'])/365
    elif  cc["Basis"] == "ACT/365" and cc['Type'] == 'D':
        return -1 * cc['Principal/GrossAmount'] * (cc['All in Rate']/100)* (cc['Number of days'])/365
    else:
        return ''
kf['Accrued Calc'] = kf.apply(ccc, axis = 1)

#Accrued Calc for 30/360 Basis 
def ppp(ll):
    if ll["Basis"] == "30/360" and ll['Type'] == 'L' and ll['Current Filter'] == 'Current CF':
        return 1 * ll['Principal/GrossAmount'] * (ll['All in Rate']/100)* (360 *(Settlement.year - ll['Start Date YEAR']) + 30 * (Settlement.month - ll['Start Date MONTH']) + Settlement.day - ll['Start Date DAYS'])/360
    elif  ll["Basis"] == "30/360" and ll['Type'] == 'D':
        return -1 * ll['Principal/GrossAmount'] * (ll['All in Rate']/100)* (360 *(Settlement.year - ll['Start Date YEAR']) + 30 * (Settlement.month - ll['Start Date MONTH']) + Settlement.day - ll['Start Date DAYS'])/360
    else:
        return ''
kf['Accrued Calc'] = kf.apply(ppp, axis = 1)

尝试的错误写法:

kf['Accrued Calc'] = kf['Accrued Calc'].apply(bbb) & kf['Accrued Calc'].apply(ccc) & kf['Accrued Calc'].apply(ppp)
可行解决方案

1. 合并为单一函数(合理且直接的方案)

将三个函数的逻辑整合到一个函数中,根据Basis字段分支处理,仅需调用一次apply,既避免覆盖问题,又减少遍历次数,逻辑更集中。

实现代码:

def calculate_accrued(row):
    # 提取通用字段
    basis = row["Basis"]
    amount = row['Principal/GrossAmount']
    rate = row['All in Rate'] / 100
    type_flag = row['Type']
    current_filter = row['Current Filter']
    
    # 确定计算符号
    if type_flag == 'L' and current_filter == 'Current CF':
        sign = 1
    elif type_flag == 'D':
        sign = -1
    else:
        return ''  # 不满足条件返回空
    
    # 根据计息基准计算天数因子
    if basis == "ACT/360":
        day_factor = row['Number of days'] / 360
    elif basis == "ACT/365":
        day_factor = row['Number of days'] / 365
    elif basis == "30/360":
        # 计算30/360基准的计息天数
        days = 360 * (Settlement.year - row['Start Date YEAR']) + \
               30 * (Settlement.month - row['Start Date MONTH']) + \
               Settlement.day - row['Start Date DAYS']
        day_factor = days / 360
    else:
        return ''  # 未知基准返回空
    
    return sign * amount * rate * day_factor

# 应用到目标列
kf['Accrued Calc'] = kf.apply(calculate_accrued, axis=1)

2. 向量化操作(高效性能方案)

apply(axis=1)是逐行遍历,大数据量下效率较低。使用pandas的向量化条件判断(结合np.where或df.loc)可以实现批量计算,性能远优于逐行遍历。

实现代码:

import numpy as np

# 初始化目标列为空字符串
kf['Accrued Calc'] = ''

# 先计算通用符号字段
sign = np.where(
    (kf['Type'] == 'L') & (kf['Current Filter'] == 'Current CF'),
    1,
    np.where(kf['Type'] == 'D', -1, np.nan)
)

# 处理ACT/360基准
act360_mask = (kf['Basis'] == 'ACT/360') & ~sign.isna()
kf.loc[act360_mask, 'Accrued Calc'] = sign[act360_mask] * \
                                      kf.loc[act360_mask, 'Principal/GrossAmount'] * \
                                      (kf.loc[act360_mask, 'All in Rate']/100) * \
                                      (kf.loc[act360_mask, 'Number of days']/360)

# 处理ACT/365基准
act365_mask = (kf['Basis'] == 'ACT/365') & ~sign.isna()
kf.loc[act365_mask, 'Accrued Calc'] = sign[act365_mask] * \
                                      kf.loc[act365_mask, 'Principal/GrossAmount'] * \
                                      (kf.loc[act365_mask, 'All in Rate']/100) * \
                                      (kf.loc[act365_mask, 'Number of days']/365)

# 处理30/360基准
basis30360_mask = (kf['Basis'] == '30/360') & ~sign.isna()
days_30360 = 360 * (Settlement.year - kf.loc[basis30360_mask, 'Start Date YEAR']) + \
             30 * (Settlement.month - kf.loc[basis30360_mask, 'Start Date MONTH']) + \
             Settlement.day - kf.loc[basis30360_mask, 'Start Date DAYS']
kf.loc[basis30360_mask, 'Accrued Calc'] = sign[basis30360_mask] * \
                                          kf.loc[basis30360_mask, 'Principal/GrossAmount'] * \
                                          (kf.loc[basis30360_mask, 'All in Rate']/100) * \
                                          (days_30360 / 360)

# 将NaN转为空字符串(按需保留)
kf['Accrued Calc'] = kf['Accrued Calc'].fillna('')

关于错误写法的说明

你尝试的&拼接写法存在两个核心问题:

  • &是逻辑与操作,会将数值强制转为布尔值,完全不符合应计计算的数值需求;
  • bbb等函数原本设计为接收整行数据,你仅传入Accrued Calc列的值,会导致函数因缺少字段报错。

内容的提问来源于stack exchange,提问作者Raj Das

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:50:42