import pandas as pd
import numpy as np

import seaborn as sns
import matplotlib.pyplot as plt

from imblearn.over_sampling import SMOTE

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, confusion_matrix, recall_score, precision_score

from sklearn.preprocessing import StandardScaler


from collections import Counter

import warnings
warnings.filterwarnings("ignore")


%matplotlib inline
df = pd.read_csv('../input/creditcardfraud/creditcard.csv')
"""
# 1. Data exploration
"""
df.head()
# Checking NaN objects
df.isnull().sum()
"""
As we can see there are no Nan objects
"""
"""
<font size="3.5">Before the data preprocessing let's create some graphs:
* heatmap of correlations between features;
* istribution of classes graph.</font>

"""
# heatmap reflecting correlations between features

corr_matrix = df.corr()

sns.set(rc={'figure.figsize':(40, 40)})
sns.heatmap(data=corr_matrix, annot=True)
# distribution of classes graph
sns.set(rc={'figure.figsize':(10, 10)})
df[['Class']].value_counts().plot(kind='bar').set(xticklabels=[0, 1])
plt.ylabel('Frequency')
plt.xlabel('Class')
plt.title('Distribution of classes')
"""
<font size="3.5">After studing the graphs can make the next inferences:
* 'Time' and 'Amount' have noteble correlation with some other features. We can drop this features;
* on the distribution of classes graph we can see totally class disbalance;
* also we can standardize our data.</font>
"""
"""
# 2. Data preprocessing
"""
# droping 'Time' and 'Amount' from the whole train dataset

data_preproc = df.drop(['Time'], axis=1)
data_preproc = data_preproc.drop(['Amount'], axis=1)
# Let's standardize features except target ("Class")
stand_scl = StandardScaler()
scaled_df = stand_scl.fit_transform(data_preproc.drop(['Class'], axis=1))
# Let's create DataFrame containing standardized features and target
columns_name = list(data_preproc)
columns_name.remove('Class')
scaled_df = pd.DataFrame(scaled_df, columns=columns_name)
scaled_df['Class'] = df[['Class']]
scaled_df.head()
"""
# 3. SMOTE
"""
"""
Let's augment data for the the minority class (Class == 1) by oversampling the dataset using Synthetic Minority Oversampling Technique (SMOTE).
"""
X = scaled_df.drop(['Class'], axis=1)
y = scaled_df.Class.ravel()
# Splitting dataset on train and test samples
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
#using SMOTE algorithm
smote = SMOTE()

# fit X_train and y_train
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)


print('Distribution of classes before SMOTE:', Counter(y_train))
print('Distribution of classes before SMOTE:', Counter(y_train_smote))
"""
# 4. Logistic Regression
"""
"""
To solve the classification problem let's create and fit Logistic Regression Classifier
"""
lr_clf = LogisticRegression()
lr_clf.fit(X_train_smote, y_train_smote)
y_pred = lr_clf.predict(X_test)
print('roc_auc_score:', roc_auc_score(y_test, y_pred))
print('recall_score:', recall_score(y_test, y_pred))
"""
We must maximize the recall score, because we have to detect as many frauds as possible.
Let's try different thresholds of class detecting, and chose the best one.
"""
list_of_thresholds = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

for threshold in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]:    
    

    # Creating and fitting Logistic Regression Classifier on train data
    lr_clf = LogisticRegression()
    lr_clf.fit(X_train_smote, y_train_smote)

    # Making a prediction on test data. Evaluating metrics (roc_auc_score, recall_score, precision_score)
    y_pred_proba = lr_clf.predict_proba(X_test)
    y_pred = np.where(y_pred_proba[:, 1] > threshold, 1, 0)
    r_a_score = roc_auc_score(y_test, y_pred)
    rec_score = recall_score(y_test, y_pred)

    print('threshold:', threshold)
    print()
    print('Primary test sample')
    print('roc_auc_score:', r_a_score)
    print('recall_score:', rec_score)
    print()
    print()
"""
As we can see the best combination of roc_auc_score and recall_score reaches at the value of threshould 0.2.
"""
lr_clf = LogisticRegression()
lr_clf.fit(X_train_smote, y_train_smote)

y_pred_proba = lr_clf.predict_proba(X_test)
y_pred = np.where(y_pred_proba[:, 1] > 0.2, 1, 0)

print('roc_auc_score:', roc_auc_score(y_test, y_pred))
print('recall_score:', recall_score(y_test, y_pred))