# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## Read Data

import pandas as pd

# there file was downloaded from https://www.kaggle.com/wendykan/lending-club-loan-data 

kaggle_data = pd.read_csv("C:/Users/jange/OneDrive/Dokumente/ML_Pipeline_Loan/loan.csv", low_memory = False)

# ## Preliminary Transformations (don't need to be run in prediction)

# Filter Loans (don't use current loans)

kagge_data = kaggle_data[~kaggle_data.loan_status.isin(["Current", "Does not meet the credit policy. Status:Charged Off",
                                                       "Does not meet the credit policy. Status:Fully Paid", "Issued"])]

# Create target variable

kaggle_data = kagge_data.assign(good_loan = pd.Series(kagge_data.loan_status == "Fully Paid"))

# ## Split Data into Training und Validation Set

from sklearn.model_selection import train_test_split

train_data, valid_data = train_test_split(kaggle_data,
                                           test_size = 0.25,
                                           random_state = 111)

# ## Define Target and Features 

target = "good_loan"
cat_features = ['home_ownership', 'purpose', 'addr_state']
num_features = ['loan_amnt', 'installment', 'annual_inc', 'int_rate', 'emp_length']
features = cat_features + num_features

positive_class = True

# Data Types

kaggle_data[features].dtypes

# ## Define Preprocessing

import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer

# **Create Derived Features**

import re


# +
def emp_length_num(string):
        if string == '< 1 year':
            emp_length = 0
        else:
            emp_length = find_number(string)
        return emp_length

    
    
def find_number(string):
        if type(string) is float:
            first_number = float('NaN')
        else:
            first_number = int(re.findall(pattern = '(\d+)', string = string)[0])
        return first_number
    
class CreateDerivedFeatures(TransformerMixin, BaseEstimator):
    def __init__(self):
        self

    def fit(self, X, *_):
        return self
        
    def transform(self, X, *_):
        X_transformed = X.assign(loan_income_ratio = pd.Series(X.loan_amnt / X.annual_inc),
                                 interest_income_ratio = pd.Series((X.loan_amnt * 0.01 * X.int_rate)/ X.annual_inc),
                                 emp_length = pd.Series(X.emp_length.apply(emp_length_num)))
       
        return X_transformed



# -

derive_step =('derive', CreateDerivedFeatures())
derive_features = Pipeline([derive_step])

# **Categorical Features**

# +
si_step_cat = ('si_cat', SimpleImputer(strategy = 'constant',
                                   fill_value= 'missing_value'))
ohe_step_cat = ('ohe_cat', OneHotEncoder(handle_unknown='ignore',
                                     sparse = False))

pipe_cat = Pipeline([si_step_cat, ohe_step_cat])
# -

# **Numerical Features**

si_step_num = ('si_num', SimpleImputer(strategy='constant',
                                       fill_value = -999))
pipe_num = Pipeline([si_step_num])

# **Preprocessing**

from sklearn.compose import ColumnTransformer

preprocessor = ColumnTransformer(
    transformers = [
        ('cat', pipe_cat, cat_features),
        ('num', pipe_num, num_features)
    ])

# ## Define Classification Model

from sklearn.ensemble import RandomForestClassifier as rf

classifier = rf(n_estimators = 20, max_depth = 20)

# ## Combine Preprocessing and Classification into Pipeline

preprocessor_classifier = Pipeline([
    ('derive_features', derive_features),
    ('preprocessor', preprocessor),
    ('classifier', classifier)
])

# ## Training Modell

fitted_model = preprocessor_classifier.fit(X = train_data[features], y = train_data[target])

# ## Predictions Modell

train_scores = fitted_model.predict_proba(X = train_data)
train_predictions = fitted_model.predict(X = train_data)
valid_scores = fitted_model.predict_proba(X = valid_data)
valid_predictions = fitted_model.predict(X = valid_data)

# ## Evaluation Modell

# **Classifier with Parameters**

classifier

index_positive = np.min(np.where(classifier.classes_ == positive_class))

# **Feature Importance**

# Here I would like to see the names of the features

top_n_features = 10

# +
importances = fitted_model.named_steps['classifier'].feature_importances_
indices = np.argsort(importances)[::-1]

# Print the feature ranking
print("Feature ranking:")

for f in range(0,top_n_features):
    print("%d. feature %d (%f)" % (f + 1, indices[f], importances[indices[f]]))
# -

import matplotlib.pyplot as plt

plt.figure()
plt.bar(range(0,top_n_features), importances[indices][0:top_n_features],
       color="r", align="center")
plt.xticks(range(0,top_n_features), indices)
plt.xlim([-1, top_n_features])
plt.show()

# **Classification Report**

from sklearn.metrics import classification_report

# Training Set

print(classification_report(y_true= train_data[target],
                      y_pred = train_predictions))

# Validation Set

print(classification_report(y_true= valid_data[target],
                      y_pred = valid_predictions))

# **Confusion Matrix**

from sklearn.metrics import confusion_matrix

confusion_matrix(y_true = valid_data[target],
                 y_pred = valid_predictions)

# **ROC**

from sklearn.metrics import roc_auc_score, roc_curve

roc_auc_score(y_true= valid_data[target],
              y_score = valid_scores[:,index_positive])

fpr, tpr, thresholds = roc_curve(y_true= valid_data[target], y_score=valid_scores[:,index_positive])

plt.plot(fpr, tpr, 'ro')

# **Example Predictions**

valid_data_predictions = valid_data.assign(scores = pd.Series(valid_scores[:,index_positive]).values)

high_predictions = valid_data_predictions[valid_data_predictions.scores > 0.98]

high_predictions.head(20)

low_predictions = valid_data_predictions[valid_data_predictions.scores < 0.3]

low_predictions.head(20)

StarcoderdataJupyterScriptsDedupFiltered