<jupyter_start><jupyter_text><jupyter_code>import numpy as np
import pandas as pd
import joblib
import json
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from yellowbrick.classifier import ROCAUC
from yellowbrick.classifier import ClassificationReport
import seaborn as sns
import matplotlib.pyplot as plt
import sklearn
sklearn.__version__
# Load the Drive helper and mount
from google.colab import drive

# This will prompt for authorization.
drive.mount('/content/drive')
# set working directory
import os
os.chdir("/content/drive/My Drive/Data Scientist/F+ Lead Scoring Model/bitBucket/fuse-fplus-lead-scoring/")
os.getcwd()

ls<jupyter_output>bitbucket-pipelines.yml          NPV_Twintiles.csv
 [0m[01;34mData[0m/                            README.md
 final.csv                       'Refresh NPV (8-10-20).ipynb'
 Fplus_Lead_Scoring               requirements.txt
 Fplus_Lead_Scoring_new           schema.json
 LeadScoringModel_Twintiles.csv   score_collector_phase1.py
 library_binning.py               scoringData.py
 main_leadLevel.py                test_data.json
 model.py                         validation.csv<jupyter_text>Load Data<jupyter_code>fplus_ls_model = joblib.load('Fplus_Lead_Scoring_new')
# fplus_ls_model = model
unitEconomicsData = pd.read_csv('Data/unitEconomicsData.csv')
training = pd.read_csv('Data/Refresh_NPV.csv')<jupyter_output><empty_output><jupyter_text>Library Binning<jupyter_code>import numpy as np
import pandas as pd

def get_co_app_cat(co_app_income):
    
    if pd.isnull(co_app_income):
        return 0
    if float(co_app_income) == 0:
        return 0
    return 1

def get_loan_use_cat(loan_use):
    if pd.isnull(loan_use):
        return 0
    
    loan_use = loan_use.lower().strip()
    if (loan_use in ['major purchase',
                     'other',
                     'Business Expenses',
                     'Medical Expenses',
                     'auto purchase']):
        return 1
    
    return 0

def get_employment_cat(employment_status):
    
    if pd.isnull(employment_status):
        employment_status = ''
    
    employment_status = employment_status.lower().strip()

    if (employment_status in ['self-employed', 'other']):
        return 1
    if (employment_status in ['retired', 'not employed']):
        return 3
    
    return 2

def get_loan_amount_cat(loan_amount):
    
    if pd.isnull(loan_amount):
        return 5
    
    loan_amount = float(loan_amount)
    if (loan_amount < 10000):
        return 1
    if (loan_amount >= 10000) and (loan_amount < 12500):
        return 2
    if (loan_amount >= 12500) and (loan_amount < 20000):
        return 3
    if (loan_amount >= 20000) and (loan_amount < 35000):
        return 4
    if (loan_amount >= 40000) and (loan_amount < 55000):
        return 4
    
    return 5

def get_mkt_chan_cat(utm_source):
    
    if pd.isnull(utm_source):
        return np.exp(5)
    
    utm_source = utm_source.lower().strip()
    if (utm_source in ['google', 'website', 'ck']):
        return np.exp(6)
    if (utm_source in ['ibm']):
        return np.exp(4)
    if (utm_source in ['even', 'nerdwallet', 'Shogun']):
        return np.exp(3)
    if (utm_source in ['credible']):
        return np.exp(2)
    if (utm_source in ['bkr', 'creditkarma']):
        return np.exp(1)
    
    return np.exp(5)

def get_fico(fico):
    
    if pd.isnull(fico):
        fico = 900
    
    fico = int(fico)
    if (fico >= 9000):
        fico = 900
    if fico < 620:
        fico = 900
    
    ficofloor = 1/(np.floor(fico/10)*10)
    ficosig = np.exp(ficofloor)/(1+np.exp(ficofloor))

    return ficosig

def get_lti(lti):
    
    if pd.isnull(lti):
        return 0.36

    lti = np.floor((lti * 100)/5)*5
    
    # lti = float(lti)
    if (lti >= 45):
        return 45
    if (lti <= 10):
        return 5
    
    return np.floor(lti)

def get_bcc0300(bcc0300):
    
    if pd.isnull(bcc0300):
        return 99
    
    bcc0300 = int(bcc0300)
    if (bcc0300 >= 25):
        return 30
    
    return bcc0300

def get_ndi_cat(ndi_cat):
    
    if pd.isnull(ndi_cat):
        return 1
    
    ndi_cat = float(ndi_cat)
    ndi_cat = np.floor((ndi_cat * 100)/5)*5
    
    if (ndi_cat >= 70):
        return 1
    if (ndi_cat >= 50) and (ndi_cat < 70):
        return 2
    if (ndi_cat >= 0) and (ndi_cat < 25):
        return 4
    
    return 3<jupyter_output><empty_output><jupyter_text>Main Lead<jupyter_code>def main_leadlevel(leads, phase=1, provide="scored_lead"):
    
    if phase == 1:
        checked_lead = check_lead_phase1(leads)
        
        if checked_lead["error"]:
            return_value = {
                "fuse.score" : 0,
                "fuse.npv" : 0,
                "fuse.model" : '',
                "fuse.error_flag": True,
                "fuse_error_reason" : "Lead Validation Failed."
            }
            return return_value
        error_msg = checked_lead["warning"]
        
        return_value = score_collector_phase1(checked_lead["return_lead"])
        if len(error_msg.strip()) > 0:
            return_value['fuse.error_reason'] = error_msg + ' ' + return_value['fuse.error_reason']
        
        return return_value

# Check that the lead has all the required fields
# if a value is missing, return warning message
def check_lead_phase1(lead):
    
    # convert all keys to lower case
    raw_lead = {k.lower(): v for k, v in lead.items()}
    
    error = False
    return_lead = {}
    missing_variables = []
    error_msg = ''
    
    required_fields = ["co_app_verifiable_annual_income","loan_use","employment_status",
                       "final_loan_amount","fico","lti","xpn_bcc0300","ndi_ratio","utm_source"]

    try:
        for field in required_fields:
            if (field not in raw_lead):
                raw_lead[field] = np.NaN
        
        for key in raw_lead:
            var = returnNaNifEmptyorNaN(raw_lead[key])
            return_lead[key] = var
            if (pd.isnull(return_lead[key])):
                missing_variables.append(key) 
        
        if (len(missing_variables)>0):
            error_msg = ",".join(missing_variables)
            error_msg = "Imputing values for: " + error_msg
            
    except Exception as e: 
        #print(e)
        error=True
    
    return_value = {
        "return_lead" : return_lead,
        "warning": error_msg,
        "error": error
    }
    
    return return_value

def returnNaNifEmptyorNaN(variable):
    
    if isinstance(variable, int):
        return variable
    if isinstance(variable, float):
        return variable
    # if null or empty
    if pd.isnull(variable) or len(variable)<1:
        return np.NaN
    if variable.isnumeric():
        return variable

    return variable.strip()<jupyter_output><empty_output><jupyter_text>Score Collector<jupyter_code>import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression

#from . import library_binning as lib
#from . import scoringData as sd

def score_collector_phase1(lead, debug = False):
    
    mod_lead = pd.DataFrame()
    bin_vars = {}
    error = False
    error_msg = ''
    prob_prediction = 0
    npv = 0
    MODEL_NAME = 'fplus_ls_202008_v1'
    
    try:
        # create binned/transformed variables
        bin_vars['co_app'] = pd.Series(get_co_app_cat(lead['co_app_verifiable_annual_income']))
        bin_vars['loan_use'] = get_loan_use_cat(lead['loan_use'])
        bin_vars['employment'] = get_employment_cat(lead['employment_status'])
        bin_vars['loan_amount'] = get_loan_amount_cat(lead['final_loan_amount'])
        bin_vars['mkt_chan'] = get_mkt_chan_cat(lead['utm_source'])
        bin_vars['ficox'] = get_fico(lead['fico'])
        bin_vars['lti'] = get_lti(lead['lti'])
        bin_vars['bcc0300'] = get_bcc0300(lead['xpn_bcc0300'])
        bin_vars['ndi'] = get_ndi_cat(lead['ndi_ratio'])
        
        mod_lead = pd.DataFrame(bin_vars)
        
        # create dummies
        cat_vars=['employment','loan_amount', 'ndi']
        for var in cat_vars:
            cat_list = pd.get_dummies(mod_lead[var], prefix=var)
            temp=mod_lead.join(cat_list)
            mod_lead=temp
        data_vars=mod_lead.columns.values.tolist()
        to_keep=[i for i in data_vars if i not in cat_vars]
        mod_lead=mod_lead[to_keep]
        print(mod_lead.columns.values)
        
        # re-index to have same columns as the model
        mod_lead = mod_lead.reindex(columns = ['ficox', 'lti', 'bcc0300', 'co_app',
                                               'loan_use', 'employment_1',
                                               'employment_2', 'employment_3', 'loan_amount_1',
                                               'loan_amount_2', 'loan_amount_3', 'loan_amount_4', 
                                               'loan_amount_5', 'mkt_chan', 'ndi_1', 'ndi_2',
                                               'ndi_3', 'ndi_4',], fill_value=0)
        
        # score
        prob_prediction = fplus_ls_model.predict_proba(mod_lead)[0][1]
        print(prob_prediction)
        
        # calc NPV
        npv = get_npv_calc(lead['final_loan_amount'], prob_prediction, lead['utm_source'])
        
    except Exception as e:
        # print(e)
        error = True
        error_msg = 'Error in Scoring.'
    
    # add an error flag
    if (debug):
        return_scores = {
            'bin_lead': mod_lead,
            'fuse.score':prob_prediction,
            'fuse.npv': npv,
            'fuse.model': MODEL_NAME,
            'fuse.error_flag': error,
            'fuse.error_reason': error_msg
        }
        return return_scores
    
    # return the dictionary
    return_scores = {
        'fuse.score':prob_prediction,
        'fuse.npv': npv,
        'fuse.model': MODEL_NAME,
        'fuse.error_flag': error,
        'fuse.error_reason': error_msg
    }
    return return_scores


def get_npv_calc(loan_amt,prob_prediction,utm_source):
    
    if pd.notnull(utm_source):
        utm_src = utm_source.strip()
        utm_src = utm_src.lower()
    
    npv = 0
    cpa = 0
    
    if pd.notnull(utm_source) and (utm_src in set(unitEconomicsData['utm_source'])):
        cpa = unitEconomicsData.loc[unitEconomicsData['utm_source'] == utm_src, 'CPA'].values[0]
                
    if pd.isnull(loan_amt):
        loan_amt = 0
    else:
        loan_amt = float(loan_amt) 
        
    npv = prob_prediction * ((loan_amt * 0.0681) - (621 + cpa))
    
    return npv<jupyter_output><empty_output><jupyter_text>Scoring Data<jupyter_code>import numpy as np
import pandas as pd
import logging
import os
from sklearn.externals import joblib


dirdata = os.path.join(os.path.dirname(__file__), 'Data')

global initialized
initialized = False

def init():
    
    global fplus_ls_model
    global unitEconomicsData
    
    global initialized
    if (initialized == True):
        return
    
    try:
        #fplus_ls_model = joblib.load('Data/Fplus_Lead_Scoring')
        #unitEconomicsData = pd.read_csv('Data/unitEconomicsData.csv')
        fplus_ls_model = joblib.load(os.path.join(dirdata, 'Fplus_Lead_Scoring'))
        unitEconomicsData = pd.read_csv(os.path.join(dirdata, 'unitEconomicsData.csv'))
        
    except Exception as e:
        #print(e)
        return
    
    initialized = True<jupyter_output><empty_output><jupyter_text>Model<jupyter_code># from . import scoringData as sd
# from . import main_leadLevel as ml
import pandas as pd
import json

# init()

# Assumption : gets dictionary as a input
def run(leads):
    score = main_leadlevel(leads)
    #score is dictionary, score['fuse_score'] is dataframe
    
    #add scores to the lead
    if ('co_app_verifiable_annual_income' in leads):
        leads['co_app_verifiable_annual_income']=str(leads['co_app_verifiable_annual_income'])
    if ('fico' in leads):
        leads['fico']=str(leads['fico'])
    if ('LTI' in leads):
        leads['LTI']=str(leads['LTI'])
    if ('xpn_bcc0300' in leads):
        leads['xpn_bcc0300']=str(leads['xpn_bcc0300'])
    if ('ndi_ratio' in leads):
        leads['ndi_ratio']=str(leads['ndi_ratio'])
    if ('final_loan_amount' in leads):
        leads['final_loan_amount']=str(leads['final_loan_amount'])
    leads.update(score)
    
    return_list = []
    return_list.append(leads)
    return return_list

def format_scores_returned(score):

    # convert everything to a dataframe
    score = pd.DataFrame.from_dict(score,orient='index').transpose() 
    
    # convert back to dictionary in list format
    score = score.to_dict('list')
    
    return score<jupyter_output><empty_output><jupyter_text>Load Data<jupyter_code>training.head()
training.isna().sum()
first_df = training<jupyter_output><empty_output><jupyter_text>Transform Data<jupyter_code># Transform variables
first_df['co_app'] = first_df['first_coapp'].apply(get_co_app_cat)
first_df['loan_use'] = first_df['first_loan_use'].apply(get_loan_use_cat)
first_df['employment'] = first_df['employment_status__c'].apply(get_employment_cat)
first_df['loan_amount'] = first_df['first_amount_of_loan_requested'].apply(get_loan_amount_cat)
first_df['mkt_chan'] = first_df['utm_source__c'].apply(get_mkt_chan_cat)
first_df['ficox'] = first_df['first_FICO'].apply(get_fico)
first_df['lti'] = first_df['First_LTI'].apply(get_lti)
first_df['bcc0300'] = first_df['first_bcc0300__c'].apply(get_bcc0300)
first_df['ndi'] = first_df['first_ndi_ratio__c'].apply(get_ndi_cat)

first_df.head()
first_df.describe()
model1.coef_<jupyter_output><empty_output><jupyter_text>Check inputs<jupyter_code>import seaborn as sns
import matplotlib.pyplot as plt
df1 = first_df
df1.isna().sum()<jupyter_output><empty_output><jupyter_text>Funded<jupyter_code># percent of data that has funded or not
df1['funded_flag'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>Co App<jupyter_code># Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['co_app'], ax=ax_box)
sns.distplot(df1['co_app'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')
# percent of data that has funded or not
df1['co_app'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>Marketing Channel<jupyter_code>np.exp(5)
# Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['mkt_chan'], ax=ax_box)
sns.distplot(df1['mkt_chan'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')
# percent of data that has funded or not
df1['mkt_chan'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>FICO Sig<jupyter_code># Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['ficox'], ax=ax_box)
sns.distplot(df1['ficox'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')
# percent of data that has funded or not
df1['ficox'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>Employment<jupyter_code># percent of data that has funded or not
df1['employment'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>LTIX<jupyter_code># Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['lti'], ax=ax_box)
sns.distplot(df1['lti'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')
# percent of data that has funded or not
df1['lti'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>BCC<jupyter_code># Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['bcc0300'], ax=ax_box)
sns.distplot(df1['bcc0300'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')<jupyter_output><empty_output><jupyter_text>Loan Cat<jupyter_code># Cut the window in 2 parts
f, (ax_hist, ax_box) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.85, .25)})

# Add a graph in each part
sns.boxplot(df1['loan_amount'], ax=ax_box)
sns.distplot(df1['loan_amount'], ax=ax_hist)

# Remove x axis name for the boxplot
ax_box.set(xlabel='')
# percent of data that has funded or not
df1['loan_amount'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>Loan Use<jupyter_code># percent of data that has funded or not
df1['loan_use'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>NDI Cat<jupyter_code># percent of data that has funded or not
df1['ndi'].value_counts()/len(df1)<jupyter_output><empty_output><jupyter_text>TRAIN MODEL  Dummy Var<jupyter_code>training.columns
things = ['funded_flag', 'co_app', 'loan_use', 'mkt_chan', 'ficox', 'employment', 'lti', 'bcc0300', 'loan_amount', 'ndi']
mod_lead = training[things]
mod_lead.head()
# create dummies
cat_vars=['employment','loan_amount', 'ndi']
for var in cat_vars:
    cat_list = pd.get_dummies(mod_lead[var], prefix=var)
    temp=mod_lead.join(cat_list)
    mod_lead=temp
data_vars=mod_lead.columns.values.tolist()
to_keep=[i for i in data_vars if i not in cat_vars]
mod_lead=mod_lead[to_keep]
print(mod_lead.columns.values)

# re-index to have same columns as the model
mod_lead = mod_lead.reindex(columns = ['funded_flag', 'ficox', 'lti', 'bcc0300', 'co_app',
                               'loan_use', 'employment_1',
                               'employment_2', 'employment_3', 'loan_amount_1',
                               'loan_amount_2', 'loan_amount_3', 'loan_amount_4', 
                               'loan_amount_5', 'mkt_chan', 'ndi_1', 'ndi_2',
                               'ndi_3', 'ndi_4',], fill_value=0)
mod_lead.describe()
mod_lead.isna().sum()<jupyter_output><empty_output><jupyter_text>Train and Save Model<jupyter_code># segment out the variable we are predicting from the rest of the data
y = mod_lead['funded_flag']
X = mod_lead.drop(['funded_flag'], axis = 1)
print(X.shape, y.shape)
# Split the data into a train and test dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)<jupyter_output>(82994, 18) (82994,)
(20749, 18) (20749,)<jupyter_text>Scale data?<jupyter_code># Set classes for all plots
classes = ['Not Funded', 'Funded']

classifier = LogisticRegression()

# Instantiate the visualizer with the classification model
visualizer = ROCAUC(classifier, classes=classes)


visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()
# Set classes for all plots
classes = ['Not Funded', 'Funded']

classifier = LogisticRegression()

# Instantiate the visualizer with the classification model
visualizer = ROCAUC(classifier, classes=classes)


visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedKFold
from yellowbrick.classifier import ROCAUC
from yellowbrick.classifier import ClassificationReport
from sklearn.linear_model import LogisticRegression
model1 = LogisticRegression()
model1.fit(X_train, y_train)
model1.score(X_test, y_test)
y_pred = model1.predict_proba(X_test)[:,1]
y_pred<jupyter_output><empty_output><jupyter_text>Prediction<jupyter_code>mod_lead1 = mod_lead
mod_lead1['y_pred_bal'] = model.predict_proba(X)[:,1]
mod_lead1['y_pred'] = model1.predict_proba(X)[:,1]
mod_lead1.head()
# distribution of probabilities that model is outputting
sns.distplot(y_pred)
y_pred = model.predict_proba(X_test)[:,1]
y_pred
# distribution of probabilities that model is outputting
sns.distplot(y_pred)
# breakout predicted probabilities into deciles
twintiles = np.percentile(mod_lead1['y_pred'], np.arange(0,100,5))
twintiles
mod_lead
X['y_pred'] = fplus_ls_model.predict_proba(X)[:,1]
final = X
final['funded_flag'] = y
final.head()
final.to_csv('final.csv', index = False)
# add deciles to the predictions
mod_lead1['twintile_rank']=pd.qcut(mod_lead1['y_pred'], 20, labels=False)
twintiles = mod_lead1.groupby(
    'twintile_rank'
).agg(
    {
        # Get the min, max, and mean of the predictions
		# min and max will help you see the boundaries of each decile
        'y_pred': [min, max, "mean"],
        # Get the mean of the actuals
        'funded_flag': ["mean"],
    }
)
twintiles
# Plot training & validation accuracy values
plt.figure(figsize=(16,8))
plt.plot(twintiles.y_pred['mean'])
plt.plot(twintiles.funded_flag['mean'])
plt.title('Twintile Plot')
plt.ylabel('Probability')
plt.xlabel('Twintile')
plt.legend(['Predicted Probability', 'Actual Probability'], loc='upper left')
plt.show()
model = LogisticRegression(solver='lbfgs', class_weight='balanced', max_iter=1000)
model.fit(X_train, y_train)
model.score(X_test, y_test)
# Set classes for all plots
classes = ['Win', 'Lose']
# Instantiate the visualizer with the classification model
visualizer = ROCAUC(log_model, classes=classes)


visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()   
# wall-clock time at beginning of modeling work
start_time = time.clock()  

classifier = LogisticRegression()
classifier.fit(X_train, y_train)  
# evaluate on the test set for this fold
y_final_test_logit_predict_prob = classifier.predict_proba(X_test)
y_final_test_logit_predict = classifier.predict(X_test)

print('Area under ROC curve:', roc_auc_score(y_test, y_final_test_logit_predict_prob[:,1]))

print('\nLogistic Regression Confusion Matrix',
      '(rows actual, columns predicted)\n')
print_cm(confusion_matrix(y_test.values, 
                 y_final_test_logit_predict),
                 labels = classes)

print('\nLogistic Regression Accuracy: ',                
np.round(accuracy_score(y_test.values, 
               y_final_test_logit_predict), decimals = 3))
          
print()

end_time = time.clock()  # wall-clock time at end of modeling work
runtime = end_time - start_time  # seconds of wall-clock time 
print('\nLogistic Regression classification elapsed time (seconds):', 
      np.round(runtime, decimals = 3))

print('\nRUN COMPLETE')<jupyter_output><empty_output><jupyter_text>Save Model<jupyter_code>from sklearn.externals import joblib

# Save to file in the current working directory
joblib_file = "Fplus_Lead_Scoring"
joblib.dump(model1, joblib_file)

# some time later...
 
# load the model from disk
#loaded_model = pickle.load(open(filename, 'rb'))
#result = loaded_model.score(X_test, Y_test)
#print(result)
fplus_ls_model = joblib.load('Fplus_Lead_Scoring')<jupyter_output><empty_output><jupyter_text>Check API<jupyter_code>test = {"co_app_verifiable_annual_income":68000,"loan_use":'Other', \
        "employment_status":'Retired', "final_loan_amount":25000, "fico":645,\
        "lti":18.23, "xpn_bcc0300":11, "ndi_ratio":0.37523456, "utm_source":''}
check_lead_phase1(test)
run(test)
lead = {"co_app_verifiable_annual_income":342,"loan_use":'Debt Consolidation', \
        "employment_status":'Full-time', "final_loan_amount":25000, "fico":700,\
        "lti":25.8, "xpn_bcc0300":42, "ndi_ratio":40, "utm_source":'Lending Tree'}
check_lead_phase1(lead)
run(lead)<jupyter_output><empty_output><jupyter_text>Validation  Load Data<jupyter_code># Using GBQ shout Out to Hughes
import pandas_gbq
import pydata_google_auth

SCOPES = [
    'https://www.googleapis.com/auth/cloud-platform',
    'https://www.googleapis.com/auth/drive',
]

credentials = pydata_google_auth.get_user_credentials(
    SCOPES,
    auth_local_webserver=False)
sql = """
SELECT
   m.name
  ,CAST(m.funded_flag AS INT64) AS funded_flag
  ,CAST(m.first_coapp AS INT64) AS first_coapp
  ,m.first_loan_use
  ,m.employment_status__c
  ,CAST(m.first_amount_of_loan_requested AS INT64) AS first_amount_of_loan_requested
  ,m.first_FICO
  ,m.First_LTI
  ,CAST(m.first_bcc0300__c AS INT64) AS first_bcc0300__c
  ,m.first_ndi_ratio__c
  ,m.utm_source__c
  ,a.original_npv_phase
  ,a.final_loan_amount
FROM
  `ffn-dw-bigquery-prd.Credit_Views.Check_Sales_NPV_Model_Inputs` m 
LEFT JOIN
  `ffam-data-platform.standardized_data.fplus_application` a on m.name = a.loan_id
WHERE
  createddate BETWEEN '2020-06-01' AND '2020-07-16'
  AND lead_type__c = 'Web'
ORDER BY 1
"""
df = pandas_gbq.read_gbq(sql, project_id='ffn-dw-bigquery-prd', credentials=credentials, dialect='standard')

df.head()
df.info()
df.info()
#int(df['first_FICO'])
# convert column "a" of a DataFrame
df['first_FICO'] = pd.to_numeric(df['first_FICO'])
df.isna().sum()
# percent of data that has funded or not
df1['funded_flag'].value_counts()/len(df1)
# save full data
df1 = df<jupyter_output><empty_output><jupyter_text>Transform Data<jupyter_code># Transform variables
df['co_app'] = df['first_coapp'].apply(get_co_app_cat)
df['loan_use'] = df['first_loan_use'].apply(get_loan_use_cat)
df['employment'] = df['employment_status__c'].apply(get_employment_cat)
df['loan_amount'] = df['first_amount_of_loan_requested'].apply(get_loan_amount_cat)
df['mkt_chan'] = df['utm_source__c'].apply(get_mkt_chan_cat)
df['ficox'] = df['first_FICO'].apply(get_fico)
df['lti'] = df['First_LTI'].apply(get_lti)
df['bcc0300'] = df['first_bcc0300__c'].apply(get_bcc0300)
df['ndi'] = df['first_ndi_ratio__c'].apply(get_ndi_cat)

things = ['funded_flag', 'co_app', 'loan_use', 'mkt_chan', 'ficox', 'employment', 'lti', 'bcc0300', 'loan_amount', 'ndi']
val = df[things]
val.head()
# create dummies
cat_vars=['employment','loan_amount', 'ndi']
for var in cat_vars:
    cat_list = pd.get_dummies(val[var], prefix=var)
    temp=val.join(cat_list)
    val=temp
data_vars=val.columns.values.tolist()
to_keep=[i for i in data_vars if i not in cat_vars]
val=val[to_keep]
print(val.columns.values)

# re-index to have same columns as the model
val = val.reindex(columns = ['funded_flag', 'ficox', 'lti', 'bcc0300', 'co_app',
                               'loan_use', 'employment_1',
                               'employment_2', 'employment_3', 'loan_amount_1',
                               'loan_amount_2', 'loan_amount_3', 'loan_amount_4', 
                               'loan_amount_5', 'mkt_chan', 'ndi_1', 'ndi_2',
                               'ndi_3', 'ndi_4',], fill_value=0)
val.columns
val.isna().sum()
val.describe()<jupyter_output><empty_output><jupyter_text>Predict<jupyter_code>val.drop(columns=['funded_flag'])
preds = fplus_ls_model.predict_proba(val.drop(columns=['funded_flag']))[:,1]
val['pred'] = preds
val['test_fund'] = df['funded_flag']
sum(val['funded_flag'] == df['funded_flag'])
val.info()
df['pred'] = preds
df.head()
df.to_csv("validation.csv")<jupyter_output><empty_output><jupyter_text>Re-Train Model AGAIN!! hopefully last time<jupyter_code># Using GBQ shout Out to Hughes
import pandas_gbq
import pydata_google_auth

SCOPES = [
    'https://www.googleapis.com/auth/cloud-platform',
    'https://www.googleapis.com/auth/drive',
]

credentials = pydata_google_auth.get_user_credentials(
    SCOPES,
    auth_local_webserver=False)
sql = """
SELECT 
 loan_id
, CASE WHEN funded_date IS NOT NULL THEN 1 ELSE 0 END AS funded_flag
, co_app_verifiable_annual_income
, loan_use
, employment_status
, amount_of_loan_requested
, fico
, lti
, bcc0300
, ndi_ratio
, utm_source
, original_npv_phase
, final_loan_amount

FROM `ffam-data-platform.standardized_data.fplus_application` 
WHERE flag_eligible_lead = true
AND latest_prequal_decision <> 'DECLINED'
AND created_datetime BETWEEN '2020-03-01' AND '2020-06-15'
"""
df1 = pandas_gbq.read_gbq(sql, project_id='ffn-dw-bigquery-prd', credentials=credentials, dialect='standard')

df = df1
# Transform variables
df['co_app'] = df['co_app_verifiable_annual_income'].apply(get_co_app_cat)
df['loan_use'] = df['loan_use'].apply(get_loan_use_cat)
df['employment'] = df['employment_status'].apply(get_employment_cat)
df['loan_amount'] = df['amount_of_loan_requested'].apply(get_loan_amount_cat)
df['mkt_chan'] = df['utm_source'].apply(get_mkt_chan_cat)
df['ficox'] = df['fico'].apply(get_fico)
df['lti'] = df['lti'].apply(get_lti)
df['bcc0300'] = df['bcc0300'].apply(get_bcc0300)
df['ndi'] = df['ndi_ratio'].apply(get_ndi_cat)
things = ['co_app', 'loan_use', 'mkt_chan', 'ficox', 'employment', 'lti', 'bcc0300', 'loan_amount', 'ndi']
train = df[things]
train.head()
train.describe()
# create dummies
cat_vars=['employment','loan_amount', 'ndi']
for var in cat_vars:
    cat_list = pd.get_dummies(train[var], prefix=var)
    temp=train.join(cat_list)
    train=temp
data_vars=train.columns.values.tolist()
to_keep=[i for i in data_vars if i not in cat_vars]
train=train[to_keep]
print(train.columns.values)

# re-index to have same columns as the model
train = train.reindex(columns = ['ficox', 'lti', 'bcc0300', 'co_app',
                               'loan_use', 'employment_1',
                               'employment_2', 'employment_3', 'loan_amount_1',
                               'loan_amount_2', 'loan_amount_3', 'loan_amount_4', 
                               'loan_amount_5', 'mkt_chan', 'ndi_1', 'ndi_2',
                               'ndi_3', 'ndi_4',], fill_value=0)
train.head()
all_train = df
all_train.head()
all_train.describe()
# segment out the variable we are predicting from the rest of the data
y = all_train['funded_flag']
X = train
print(X.shape, y.shape)
# Set classes for all plots
classes = ['Not Funded', 'Funded']

classifier = LogisticRegression()

# Instantiate the visualizer with the classification model
visualizer = ROCAUC(classifier, classes=classes)


visualizer.fit(X, y)  # Fit the training data to the visualizer
visualizer.score(val, y_val)  # Evaluate the model on the test data
g = visualizer.poof()
model = LogisticRegression()
model.fit(X, y)
model.score(val, y_val)
from sklearn.externals import joblib

# Save to file in the current working directory
joblib_file = "Fplus_Lead_Scoring_new"
joblib.dump(model, joblib_file)
y_pred = model.predict(X)
y_pred_prob = model.predict_proba(X)
y_pred_prob
y_pred
from sklearn.metrics import classification_report
classes = ['Not Funded', 'Funded']

print(classification_report(y, y_pred, target_names=classes))<jupyter_output>precision    recall  f1-score   support

  Not Funded       0.91      1.00      0.95     80601
      Funded       0.47      0.02      0.03      8078

    accuracy                           0.91     88679
   macro avg       0.69      0.51      0.49     88679
weighted avg       0.87      0.91      0.87     88679<jupyter_text>Validation Round 2<jupyter_code>sql = """
SELECT 
 loan_id
, CASE WHEN funded_date IS NOT NULL THEN 1 ELSE 0 END AS funded_flag
, co_app_verifiable_annual_income
, loan_use
, employment_status
, amount_of_loan_requested
, fico
, lti
, bcc0300
, ndi_ratio
, utm_source
, original_npv_phase
, final_loan_amount

FROM `ffam-data-platform.standardized_data.fplus_application` 
WHERE flag_eligible_lead = true
AND latest_prequal_decision <> 'DECLINED'
AND created_datetime BETWEEN '2020-06-01' AND '2020-07-15'
"""
df1 = pandas_gbq.read_gbq(sql, project_id='ffn-dw-bigquery-prd', credentials=credentials, dialect='standard')

df = df1
# Transform variables
df['co_app'] = df['co_app_verifiable_annual_income'].apply(get_co_app_cat)
df['loan_use'] = df['loan_use'].apply(get_loan_use_cat)
df['employment'] = df['employment_status'].apply(get_employment_cat)
df['loan_amount'] = df['amount_of_loan_requested'].apply(get_loan_amount_cat)
df['mkt_chan'] = df['utm_source'].apply(get_mkt_chan_cat)
df['ficox'] = df['fico'].apply(get_fico)
df['lti'] = df['lti'].apply(get_lti)
df['bcc0300'] = df['bcc0300'].apply(get_bcc0300)
df['ndi'] = df['ndi_ratio'].apply(get_ndi_cat)
things = ['co_app', 'loan_use', 'mkt_chan', 'ficox', 'employment', 'lti', 'bcc0300', 'loan_amount', 'ndi']
val = df[things]
val.head()
# create dummies
cat_vars=['employment','loan_amount', 'ndi']
for var in cat_vars:
    cat_list = pd.get_dummies(val[var], prefix=var)
    temp=val.join(cat_list)
    val=temp
data_vars=val.columns.values.tolist()
to_keep=[i for i in data_vars if i not in cat_vars]
val=val[to_keep]
print(val.columns.values)

# re-index to have same columns as the model
val = val.reindex(columns = ['ficox', 'lti', 'bcc0300', 'co_app',
                             'loan_use', 'employment_1',
                             'employment_2', 'employment_3', 'loan_amount_1',
                             'loan_amount_2', 'loan_amount_3', 'loan_amount_4', 
                             'loan_amount_5', 'mkt_chan', 'ndi_1', 'ndi_2',
                             'ndi_3', 'ndi_4',], fill_value=0)
# preds = model.predict_proba(val)[:,1]
preds = fplus_ls_model.predict_proba(val)[:,1]
df['pred'] = preds
df
y_val = df['funded_flag']<jupyter_output><empty_output><jupyter_text>Twin<jupyter_code># add deciles to the predictions
df['lead_scoring_twentile']=pd.qcut(df['pred'], 20, labels=False)
twintiles = df.groupby(
    'lead_scoring_twentile'
).agg(
    {
        # Get the min, max, and mean of the predictions
		# min and max will help you see the boundaries of each decile
        'pred': [min, max, "count", "mean"],
        # Get the mean of the actuals
        'funded_flag': ["mean"],
    }
)
twintiles
twintiles.to_csv("LeadScoringModel_Twintiles.csv", index=False)
# Plot training & validation accuracy values
plt.figure(figsize=(12,8))
plt.plot(twintiles.pred['mean'])
plt.plot(twintiles.funded_flag['mean'])
plt.title('Twintile Plot')
plt.ylabel('Fund Rate')
plt.xlabel('Twintile')
plt.legend(['Predicted Fund Rate', 'Actual Fund Rate'], loc='upper left')
plt.show()
val
df<jupyter_output><empty_output><jupyter_text>NPV Values<jupyter_code>def npv_calc(x):

    loan_amt = x['amount_of_loan_requested']
    prob_prediction = x['pred']
    utm_source = x['utm_source']
    
    if pd.notnull(utm_source):
        utm_src = utm_source.strip()
        utm_src = utm_src.lower()
    
    npv = 0
    cpa = 0
    
    if pd.notnull(utm_source) and (utm_src in set(unitEconomicsData['utm_source'])):
        cpa = unitEconomicsData.loc[unitEconomicsData['utm_source'] == utm_src, 'CPA'].values[0]
                
    if pd.isnull(loan_amt):
        loan_amt = 0
    else:
        loan_amt = float(loan_amt) 
        
    npv = prob_prediction * ((loan_amt * 0.0681) - (621 + cpa))
    
    return npv


def npv_final_calc(x):

    loan_amt = x['final_loan_amount']
    prob_prediction = x['pred']
    utm_source = x['utm_source']
    
    if pd.notnull(utm_source):
        utm_src = utm_source.strip()
        utm_src = utm_src.lower()
    
    npv = 0
    cpa = 0
    
    if pd.notnull(utm_source) and (utm_src in set(unitEconomicsData['utm_source'])):
        cpa = unitEconomicsData.loc[unitEconomicsData['utm_source'] == utm_src, 'CPA'].values[0]
                
    if pd.isnull(loan_amt):
        loan_amt = 0
    else:
        loan_amt = float(loan_amt) 
        
    npv = prob_prediction * ((loan_amt * 0.0681) - (621 + cpa))
    
    return npv


def npv_actual_calc(x):

    loan_amt = x['final_loan_amount']
    utm_source = x['utm_source']
    fund = x['funded_flag']

    
    if pd.notnull(utm_source):
        utm_src = utm_source.strip()
        utm_src = utm_src.lower()
    
    npv = 0
    cpa = 0
    
    if pd.notnull(utm_source) and (utm_src in set(unitEconomicsData['utm_source'])):
        cpa = unitEconomicsData.loc[unitEconomicsData['utm_source'] == utm_src, 'CPA'].values[0]
                
    if pd.isnull(loan_amt):
        loan_amt = 0
    else:
        loan_amt = float(loan_amt) 
        
    npv = ((loan_amt * 0.0681) - (621 + cpa))

    if fund == 0:
        npv = 0
    
    return npv
df['NPV'] = df.apply(npv_calc, axis=1)
df['NPV_final'] = df.apply(npv_final_calc, axis=1)
df['Actual_NPV'] = df.apply(npv_actual_calc, axis=1)
df['Delta_NPV'] = df['NPV'] - df['original_npv_phase']
df.head()
df.info()
df.to_csv("Updated_NPV_Validation.csv", index=False)


df<jupyter_output><empty_output><jupyter_text>NPV Twin<jupyter_code># add deciles to the predictions
df['npv_twentile']=pd.qcut(df['NPV'], 20, labels=False)
npv_twentile = df.groupby(
    'npv_twentile'
).agg(
    {
        # Get the min, max, and mean of the predictions
		# min and max will help you see the boundaries of each decile
        'NPV': [min, max, "count", "mean"],
        'original_npv_phase': ["mean"],
         # Get the mean of the actuals
        'Actual_NPV': ["mean"],
    }
)
npv_twentile
npv_twentile.to_csv("Updated_NPV_Twintiles.csv", index=False)
# Plot training & validation accuracy values
plt.figure(figsize=(12,8))
plt.plot(npv_twentile.NPV['mean'])
plt.plot(npv_twentile.Actual_NPV['mean'])
plt.plot(npv_twentile.original_npv_phase['mean'])
plt.title('Twentile Plot')
plt.ylabel('NPV')
plt.xlabel('Twentile')
plt.legend(['Predicted NPV', 'Actual NPV', 'Old NPV Score'], loc='upper left')
plt.show()
val
df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12685346561201233, 'fraction_numerical': 0.02096795817133664, 'mean_word_length': 3.7055261165783495, 'pattern_counts': {'":': 27, '<': 146, '<?xml version=': 0, '>': 148, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '34', 'dir': 'jupyter-structured-clean-dedup', 'id': '620441', 'license': 'MIT', 'n_tokens_mistral': 14343, 'n_tokens_neox': 13478, 'n_words': 2656, 'path': 'Refresh_NPV_(8_10_20).ipynb', 'repo_name': 'papagorgio23/Python101', 'size': '37295'}