如何在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
相关产品推荐
相关产品推荐

