I need help on applying my below case statement functions to the same column at once or in parallel? Not sure if I am doing it in the most efficient way, are there alternative ways I can do this?
#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)}
I tried the below
kf['Accrued Calc'] = kf['Accrued Calc'].apply(bbb) & kf['Accrued Calc'].apply(ccc) & kf['Accrued Calc'].apply(ppp)
Not sure if it's a good idea to have all my functions under one large function?
CodePudding user response:
You should have one function to decide which function to call. Apply that function to your dataframe. Depending on your conditions, this function can then call the correct function that will contain the meat of your calculations. Also, in the interest of readability, rename your functions and variables to something that makes sense:
#Accrued Calc for ACT/360
def accrued_act_360(row):
if row['Type'] == 'L' and row['Current Filter'] == 'Current CF':
return 1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (row['Number of days'])/360
elif row['Type'] == 'D':
return -1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (row['Number of days'])/360
else:
return ''
#Accrued Calc for ACT/365
def accrued_act_365(row):
if row['Type'] == 'L' and row['Current Filter'] == 'Current CF':
return 1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (row['Number of days'])/365
elif row['Type'] == 'D':
return -1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (row['Number of days'])/365
else:
return ''
#Accrued Calc for 30/360 Basis
def accrued_30_360(row):
if row['Type'] == 'L' and row['Current Filter'] == 'Current CF':
return 1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (360 *(Settlement.year - row['Start Date YEAR']) 30 * (Settlement.month - row['Start Date MONTH']) Settlement.day - row['Start Date DAYS'])/360
elif row['Type'] == 'D':
return -1 * row['Principal/GrossAmount'] * (row['All in Rate']/100)* (360 *(Settlement.year - row['Start Date YEAR']) 30 * (Settlement.month - row['Start Date MONTH']) Settlement.day - row['Start Date DAYS'])/360
else:
return ''
def accrued_calc(row):
if row["Basis"] == "ACT/360":
return accrued_act_360(row)
elif row["Basis"] == "ACT/365":
return accrued_act_365(row)
elif row["Basis"] == "30/360":
return accrued_30_360(row)
else:
return ""
kf['Accrued Calc'] = kf.apply(accrued_calc, axis = 1)
However: this approach fails to make use of pandas's amazing vectorized processing powers.
You could use boolean indexing to figure out which rows fulfill certain conditions, and only set those rows for the entire dataframe in one shot instead of applying your function row-by-row. This approach will likely be significantly faster than .apply
def accrued_act_360_vec(df):
# Find which rows match your condition
type_l_rows = (df["Basis"] == "ACT/360") & (df["Type"] == "L") & (df["Current Filter"] == "Current CF")
# Set the value for those rows
df.loc[type_l_rows, "Accrued Calc"] = df.loc[type_l_rows, 'Principal/GrossAmount'] * (df.loc[type_l_rows, 'All in Rate']/100)* (df.loc[type_l_rows, 'Number of days'])/360
type_d_rows = (df["Basis"] == "ACT/360") & (df["Type"] == "D")
df.loc[type_d_rows, "Accrued Calc"] = -1 * df.loc[type_d_rows, 'Principal/GrossAmount'] * (df.loc[type_d_rows, 'All in Rate']/100)* (df.loc[type_d_rows, 'Number of days'])/360
# No need to consider the else condition: Those rows never get set.
def accrued_act_365_vec(df):
type_l_rows = (df["Basis"] == "ACT/365") & (df['Type'] == 'L') & (df['Current Filter'] == 'Current CF')
df.loc[type_l_rows, "Accrued Calc"] = 1 * df.loc[type_l_rows, 'Principal/GrossAmount'] * (df.loc[type_l_rows, 'All in Rate']/100)* (df.loc[type_l_rows, 'Number of days'])/365
type_d_rows = (df["Basis"] == "ACT/365") & (df['Type'] == 'D')
df.loc[type_d_rows, "Accrued Calc"] = -1 * df.loc[type_d_rows, 'Principal/GrossAmount'] * (df.loc[type_d_rows, 'All in Rate']/100)* (df.loc[type_d_rows, 'Number of days'])/365
def accrued_30_360_vec(df):
type_l_rows = (df["Basis"] == "30/360") & (df['Type'] == 'L') & (df['Current Filter'] == 'Current CF')
df.loc[type_l_rows, "Accrued Calc"] = 1 * df.loc[type_l_rows, 'Principal/GrossAmount'] * (df.loc[type_l_rows, 'All in Rate']/100)* (360 *(Settlement.year - df.loc[type_l_rows, 'Start Date YEAR']) 30 * (Settlement.month - df.loc[type_l_rows, 'Start Date MONTH']) Settlement.day - df.loc[type_l_rows, 'Start Date DAYS'])/360
type_d_rows = (df["Basis"] == "30/360") & (df['Type'] == 'D')
df.loc[type_d_rows, "Accrued Calc"] = -1 * df.loc[type_d_rows, 'Principal/GrossAmount'] * (df.loc[type_d_rows, 'All in Rate']/100)* (360 *(Settlement.year - df.loc[type_d_rows, 'Start Date YEAR']) 30 * (Settlement.month - df.loc[type_d_rows, 'Start Date MONTH']) Settlement.day - df.loc[type_d_rows, 'Start Date DAYS'])/360
Notice these functions include the condition for df["Basis"] == ...
because they are all standalone functions. To run these, you'd just do:
accrued_act_360_vec(kf)
accrued_act_365_vec(kf)
accrued_30_360_vec(kf)
Please re-check the accuracy of the formulas in my code, I might have accidentally messed them up during copy/paste