<repo_name>nnsriram/Credit_Risk_Modelling<file_sep>/train.py
##########################################################
# The train.py file is used for training credit risk model
##########################################################

import pandas as pd
import numpy as np
from sklearn.externals import joblib
from sklearn.metrics import roc_auc_score
import pickle
from models import classifier_select
from preprocess import preprocess_split_train
np.random.seed(42)
import os


# train_data describes the path of the input file in the form of .csv
train_data = r'C:\Users\<NAME>\Downloads\ML_Artivatic_dataset\train_indessa.csv'
# path variable describes the folder to save the trained model
model_save_path = r'F:\models'

# preprocess the input data - the details of preprocessing are available in preprocess.py
# - input arguements : train_data variable
# - output           : the entries in the .csv file are preprocessed and split into train and validation split
X_train, X_test, y_train, y_test = preprocess_split_train(train_data)

# Choice of the prediction algorithm: the choice variable could set from one of the options below
# Set 'Log_Reg' for Logistic Regression
# Set 'ADB_LR' for Boosted model with base model as Logistic Regression
# Set 'DT' for Decision Tree
# Set 'RF' for Random forest
# Set 'KNN' for K-Nearest Neighbours
# Set 'Ensemble' for ensemble of 3 networks: Log_reg, RF, KNN
choice = 'Log_Reg'

# classifier select function configures the model and returns it
# input arguements : choice of the algorithm
# output           : returns the configured classifier
classifier = classifier_select(choice)
classifier.fit(X_train,y_train)
Y_pred = classifier.predict(X_test)

# Metrics - Accuracy and AUC-ROC score
print(choice)
accuracy = round(classifier.score(X_test, y_test) * 100, 2)
print("Accuracy = ", accuracy)
print("ROC = ", roc_auc_score(y_test, Y_pred))

# Save the model
filename = os.path.join(model_save_path, choice + '.sav')
joblib.dump(classifier, open(filename, 'wb'))
<file_sep>/preprocess.py
##########################################################
# The preprocess.py file is used for preprocessing the data which includes
# - cleaning the data
# - data transformations and scaling
##########################################################


import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
import os

# preprocess_split_train: includes basic preprocessing operations on the training
# data and generates train and validation splits
# - input arguements : data_path - path to the train_data.csv file
# - output           : returns train and validation splits
def preprocess_split_train(data_path):
    if os.path.exists(data_path):
        loan_df = pd.read_csv(data_path)

        loan_df1 = pd.DataFrame.copy(loan_df)

        # the features chosen below are qualitatively examined and inferred that they are not of significant importance
        # for training
        loan_df1.drop(["member_id", 'funded_amnt_inv', 'grade', 'emp_title', 'desc', 'title'], axis=1, inplace=True)

        # features which contain more than 80% of null values are dropped
        loan_df1.dropna(thresh=loan_df1.shape[0] * 0.2, how='all', axis=1, inplace=True)

        # the features described below are inferred to categorical variables
        colname1 = ['term', 'sub_grade', 'pymnt_plan', 'purpose', 'zip_code',
                    'delinq_2yrs', 'inq_last_6mths', 'mths_since_last_delinq', 'open_acc', 'pub_rec',
                    'total_acc', 'initial_list_status', 'collections_12_mths_ex_med', 'mths_since_last_major_derog',
                    'application_type', 'addr_state', 'last_week_pay', 'acc_now_delinq', 'batch_enrolled', 'emp_length',
                    'home_ownership', 'verification_status']

        for k in loan_df1.keys():
            if k in colname1:
                # Categorical features which contain null values are replaced with most frequent entries
                # in the respective columns
                loan_df1[k].fillna(loan_df1[k].mode()[0], inplace=True)
            else:
                # Continuous features which contain null values are replaced with mean of the respective columns
                loan_df1[k].fillna(loan_df1[k].mean(), inplace=True)

        # X is the feature set and y is the label information
        X = loan_df1.drop('loan_status', axis=1)
        y = loan_df1['loan_status']

        # the overall data is split into train and validation splits
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
                                                            random_state=42, stratify=y)

        le = {}
        for x in colname1:
            le[x] = LabelEncoder()
        # Categorical variables are one-hot encoded
        for x in colname1:
            X_test[x] = le[x].fit_transform(X_test.__getattr__(x))

        for x in colname1:
            X_train[x] = le[x].fit_transform(X_train.__getattr__(x))

        # All the features are scaled for uniform variance
        scaler = StandardScaler()
        scaler.fit_transform(X_train, y_train)
        scaler.fit_transform(X_test, y_test)

    else :
        raise Exception('Data path does not exist')

    return X_train, X_test, y_train, y_test


# preprocess_split_test: includes basic preprocessing operations required for the test data
# - input arguements : data_path - path to the train_data.csv file
# - output           : returns preprocessed test data
def preprocess_test(data_path):
    if os.path.exists(data_path):
        loan_df = pd.read_csv(data_path)

        loan_df1 = pd.DataFrame.copy(loan_df)

        loan_df1.drop(["member_id", 'funded_amnt_inv', 'grade', 'emp_title', 'desc', 'title'], axis=1, inplace=True)

        loan_df1.dropna(thresh=loan_df1.shape[0] * 0.2, how='all', axis=1, inplace=True)

        colname1 = ['term', 'sub_grade', 'pymnt_plan', 'purpose', 'zip_code',
                    'delinq_2yrs', 'inq_last_6mths', 'mths_since_last_delinq', 'open_acc', 'pub_rec',
                    'total_acc', 'initial_list_status', 'collections_12_mths_ex_med', 'mths_since_last_major_derog',
                    'application_type', 'addr_state', 'last_week_pay', 'acc_now_delinq', 'batch_enrolled', 'emp_length',
                    'home_ownership',
                    'verification_status']

        for k in loan_df1.keys():
            if k in colname1:
                loan_df1[k].fillna(loan_df1[k].mode()[0], inplace=True)
            else:
                loan_df1[k].fillna(loan_df1[k].mean(), inplace=True)

        X_test = loan_df1
        le = {}  # create blank dictionary
        for x in colname1:
            le[x] = LabelEncoder()

        for x in colname1:
            X_test[x] = le[x].fit_transform(X_test.__getattr__(x))

        scaler = StandardScaler()
        scaler.fit_transform(X_test)

    else:
        raise Exception('Data path does not exist')

    return X_test<file_sep>/README.md
# Credit Risk Modelling

This project describes the experimentation conducted with data collected over years for deciding whether a potential customer would default from paying back the load. The work describes appraoches based on machine learning for predicting the status of a loan. Different machine learning approaches are used in this study and AUC-ROC is considered as the metric of evaluation. 

The approaches used for experimentation and metrics:

| Algorithm | AUC-ROC |
| :---: | :---: |
| Logistic Regression(LR) | 50.56 |
| Boosted Logistic Regression | 59.61 |
| Decision Tree | 73.45 |
| Random Forest(RF)| 73.45 |
| K-Nearest Neighbors(KNN) | 61.85 |
| Ensemble (LR,RF,KNN) | 62.7 |

To run the code clone the project

1. train.py is used for training - path to training data is required
2. test.py is used for inference - path to test data and trained model file required

Trained models for the above experiments are available at:
https://drive.google.com/file/d/1HLquUEZ0iQDWMneXlTP5gZ54MSmFhxX9/view?usp=sharing <file_sep>/models.py
##########################################################
# The models.py file is used for configuring a classifier
# based on the user's choice
##########################################################

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression


# classifier_select: configures a classifier based on the choice
# - input arguements : choice of the classifier network
# - output           : returns the configured classifier
def classifier_select(choice):
    if choice == 'Log_Reg':
        classifier = LogisticRegression()
    elif choice == 'ADB_LR':
        classifier = AdaBoostClassifier(base_estimator=LogisticRegression())
    elif choice == 'DT':
        classifier = DecisionTreeClassifier()
    elif choice == 'RF':
        classifier = RandomForestClassifier(501)
    elif choice == 'KNN':
        classifier = KNeighborsClassifier(n_neighbors=10)
    elif choice == 'Ensemble':
        estimators = []
        model1 = LogisticRegression()
        estimators.append(('log', model1))
        model2 = RandomForestClassifier(501)
        estimators.append(('rf', model2))
        model3 = KNeighborsClassifier(n_neighbors=10)
        estimators.append(('KNN', model3))
        classifier = VotingClassifier(estimators)
    else :
        raise Exception('Invalid Classifier, please select a valid option from the list')
    return classifier