简体   繁体   中英

How to apply multiple functions to same column in Python?

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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM