# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load in 

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the "../input/" directory.
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# Any results you write to the current directory are saved as output.
"""
* **1. Introduction**
* **2. Feature Engineering/Data Preprocessing**
*       2(i). Importing Dataset
*       2(ii). Descriptive Statistics
*       2(iii). Handle Null or Empty Values (Data Cleaning)
*       2(iv). Visualising Descriptive Statistics
*       2(v). HeatMap Visualisation
*       2(vi). Correlation Coefficient Values Each Attribute.
*       2(vii). Label Encoder/One Hot Encoder
*       2(viii). Feature Split
*       2(ix). Feature scale
*       2(x). Resample Module Evaluate Performance
* **3. Modeling**
"""
"""
# **1. Introduction**

we will use various predictive models to see how accurate they are in detecting whether a transaction is a normal payment or a fraud. As described in the dataset.

In this dataset we have imbalanced dataset we have more transaction list of non-fraud and very less number of fraud transaction.

Which is highly imbalanced dataset..With this imabalanced dataset we won't get accuracte predictions now we need to balance both fraud and non-fraud transcation to balanced like 50:50...

Let have a look how i will extract features and convert imbalanced dataset into balanced dataset

We have Non-Fraud (99.83%) of the time, while Fraud transactions occurs (0.17%) in our dataset
"""
"""
# **2. Feature Engineering/Data Preprocessing**

 **2(i). Importing Dataset**
"""
# Importing the dataset
import pandas as pd
dataset = pd.read_csv("../input/creditcardfraud/creditcard.csv")
"""
**2(ii). Descriptive Statistics**
"""
# Displaying the head and tail of the dataset
dataset.head()
dataset.tail()
# Column key for each attributes
dataset.columns
# Displaying the shape and data type for each attribute.

print(dataset.shape)
dataset.dtypes
"""
As per above visuval we have 284807 rows and 31 columns.

All Attribute Having Float and Integer values only we dont have any categorical values.
"""
# Displaying the describe statistics in each column

dataset.describe()
"""
# **2(iii). Handle Null or Empty Values (Data Cleaning)**

Cleaning any null or empty values available in our dataset
"""
# Displaying the only non empty count
dataset.info()
# Displaying the Empty cell and total cell count in each attribute.

dataset.isna().sum()
"""
We dont have any missing values in our dataset. So no need to clean our dataset.

Now we can safely go ahead with other preprocessings.
"""
"""
# Checking Balanced or Imbalanced Dataset
"""
# Checking percentage of each class rows.
non_fraud=round(dataset['Class'].value_counts()[0])/len(dataset)*100.0
fraud=round(dataset['Class'].value_counts()[1])/len(dataset)*100.0

print("Non-Fraud Transaction data percentage %f"%(non_fraud))
print("Fraud Trabsaction data percentage %f"%(fraud))
"""
# It's ImBalance Dataset
As per above class percentage its clear that our dataset is imbalanced dataset.We can seed Non-fraud transaction having 99.8% data and fraud transaction only 0.17%.

By using this imabalance dataset we never get accurate perfromance.

The base for our predictive models and analysis we might get a lot of errors and our algorithms will probably overfit since it will "assume" that most transactions are not fraud. But we don't want our model to assume, we want our model to detect patterns that give signs of fraud!
"""
# Dispalying our class row count in bar plot manner.

colors=['red','blue']
import seaborn as sb
import matplotlib.pyplot as plt
sb.countplot('Class',data=dataset,palette=colors)
plt.title("Class Distribution 0-Not Fraud and 1- Fraud")
"""
# Converting all imbalanced to balanced dataset
"""
"""
we will first scale the columns comprise of Time and Amount . Time and amount should be scaled as the other columns. On the other hand, we need to also create a sub sample of the dataframe in order to have an equal amount of Fraud and Non-Fraud cases.

In this scenario, our subsample will be a dataframe with a 50/50 ratio of fraud and non-fraud transactions. Meaning our sub-sample will have the same amount of fraud and non fraud transactions.

Scaled amount and scaled time are the columns with scaled values.
There are 492 cases of fraud in our dataset so we can randomly get 492 cases of non-fraud to create our new sub dataframe.
We concat the 492 cases of fraud and non fraud, creating a new sub-sample.

"""
# Since our classes are highly skewed we should make them equivalent in order to have a normal distribution of the classes.

# Lets shuffle the data before creating the subsamples

dataset = dataset.sample(frac=1)

# amount of fraud classes 492 rows.
fraud_dataset = dataset.loc[dataset['Class'] == 1]
non_fraud_dataset = dataset.loc[dataset['Class'] == 0][:492]

normal_distributed_dataset = pd.concat([fraud_dataset, non_fraud_dataset])

# Shuffle dataframe rows
new_dataset = normal_distributed_dataset.sample(frac=1, random_state=42)

new_dataset.head()
print('Distribution of the Classes in the subsample dataset')
print(new_dataset['Class'].value_counts()/len(new_dataset))



sb.countplot('Class', data=new_dataset, palette=colors)
plt.title('Equally Distributed Classes')
plt.show()
"""
# 2(viii). Feature Split
"""
y=new_dataset['Class']
x=new_dataset.drop(['Class'],axis=1)
x=x.values
y=y.values
x[:1,:]
"""
# 2(x). Resample Module Evaluate Performance
"""
# Splitting the dataset into training and test set
train_size=0.80
test_size=0.20
seed=5
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,train_size=train_size,
                                               test_size=test_size,random_state=seed)
"""
# 3. Modeling

# Classification.
"""
# Spotcheck and compare algorithms with out applying feature scale.......

n_neighbors=5
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB

# keeping all models in one list
models=[]
models.append(('LogisticRegression',LogisticRegression()))
models.append(('knn',KNeighborsClassifier(n_neighbors=n_neighbors)))
models.append(('SVC',SVC()))
models.append(("decision_tree",DecisionTreeClassifier()))
models.append(('Naive Bayes',GaussianNB()))

# Evaluating Each model
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
names=[]
predictions=[]
error='accuracy'
for name,model in models:
    fold=KFold(n_splits=10,random_state=0)
    result=cross_val_score(model,x_train,y_train,cv=fold,scoring=error)
    predictions.append(result)
    names.append(name)
    msg="%s : %f (%f)"%(name,result.mean(),result.std())
    print(msg)
    

# Visualizing the Model accuracy
fig=plt.figure()
fig.suptitle("Comparing Algorithms")
plt.boxplot(predictions)
plt.show()
"""
Classification Algorithm accuracy without feature scale.

1. LogisticRegression : 0.921243 (0.021070)
2. knn : 0.664589 (0.038532)
3. SVC : 0.575576 (0.048506)
4. decision_tree : 0.923856 (0.032898)
5. Naive Bayes : 0.871633 (0.025133)
"""
# Spot Checking and Comparing Algorithms With StandardScaler Scaler
from sklearn.pipeline import Pipeline
from sklearn. preprocessing import StandardScaler
pipelines=[]
pipelines.append(('scaled Logisitic Regression',Pipeline([('scaler',StandardScaler()),('LogisticRegression',LogisticRegression())])))
pipelines.append(('scaled KNN',Pipeline([('scaler',StandardScaler()),('KNN',KNeighborsClassifier(n_neighbors=n_neighbors))])))
pipelines.append(('scaled SVC',Pipeline([('scaler',StandardScaler()),('SVC',SVC())])))
pipelines.append(('scaled DecisionTree',Pipeline([('scaler',StandardScaler()),('decision',DecisionTreeClassifier())])))
pipelines.append(('scaled naive bayes',Pipeline([('scaler',StandardScaler()),('scaled Naive Bayes',GaussianNB())])))

# Evaluating Each model
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
names=[]
predictions=[]
for name,model in models:
    fold=KFold(n_splits=10,random_state=0)
    result=cross_val_score(model,x_train,y_train,cv=fold,scoring=error)
    predictions.append(result)
    names.append(name)
    msg="%s : %f (%f)"%(name,result.mean(),result.std())
    print(msg)
    

# Visualizing the Model accuracy
fig=plt.figure()
fig.suptitle("Comparing Algorithms")
plt.boxplot(predictions)
plt.show()
"""
We got an accuracy likes..

1. LogisticRegression : 0.927459 (0.028305)
2. knn : 0.637861 (0.054821)
3. SVC : 0.515807 (0.060123)
4. decision_tree : 0.908439 (0.031689)
5. Naive Bayes : 0.880542 (0.028052)
"""
"""
Now we are going to apply tuning to Logistic Regression and Decision Tree...
"""
# tuning to Logistic Regression
import numpy as np
from sklearn.model_selection import GridSearchCV
scaler=StandardScaler().fit(x_train)
rescaledx=scaler.transform(x_train)
c=[0.01,0.1,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
param_grid=dict(C=c)
model=LogisticRegression()
fold=KFold(n_splits=10,random_state=5)
grid=GridSearchCV(estimator=model,param_grid=param_grid,scoring=error,cv=fold)
grid_result=grid.fit(rescaledx,y_train)

print("Best: %f using %s "%(grid_result.best_score_,grid_result.best_params_))
# tuning to Decision Tree Classification Algorithm
import numpy as np
from sklearn.model_selection import GridSearchCV
scaler=StandardScaler().fit(x_train)
rescaledx=scaler.transform(x_train)
param_grid=dict()
model=DecisionTreeClassifier()
fold=KFold(n_splits=10,random_state=5)
grid=GridSearchCV(estimator=model,param_grid=param_grid,scoring=error,cv=fold)
grid_result=grid.fit(rescaledx,y_train)

print("Best: %f using %s "%(grid_result.best_score_,grid_result.best_params_))
"""
After Applying tuning to those top 2 algorithms we got accuray and with best hyper parameter and its values.

1. Logistic Regression 0.943995 using {'C': 0.9} 
2. Decision Tree Classifier Best: 0.905972 using {} 
"""
# Ensemble and Boosting algorithm to improve performance

#Ensemble
# Boosting methods
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
# Bagging methods
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
ensembles=[]
ensembles.append(('scaledAB',Pipeline([('scale',StandardScaler()),('AB',AdaBoostClassifier())])))
ensembles.append(('scaledGBC',Pipeline([('scale',StandardScaler()),('GBc',GradientBoostingClassifier())])))
ensembles.append(('scaledRFC',Pipeline([('scale',StandardScaler()),('rf',RandomForestClassifier(n_estimators=10))])))
ensembles.append(('scaledETC',Pipeline([('scale',StandardScaler()),('ETC',ExtraTreesClassifier(n_estimators=10))])))

# Evaluate each Ensemble Techinique
results=[]
names=[]
for name,model in ensembles:
    fold=KFold(n_splits=10,random_state=5)
    result=cross_val_score(model,x_train,y_train,cv=fold,scoring=error)
    results.append(result)
    names.append(name)
    msg="%s : %f (%f)"%(name,result.mean(),result.std())
    print(msg)
    
# Visualizing the compared Ensemble Algorithms
fig=plt.figure()
fig.suptitle('Ensemble Compared Algorithms')
plt.boxplot(results)
plt.show()
"""
We got good accuracy for this ensemble models.

1. Ada Boost Classifier Algorithm 0.931289 (0.028229)
2. GradientBoosting Classifier Algorithm 0.949059 (0.032391)
3. Random Forest Classifier Algorithm 0.938916 (0.035196)
4. Extra Tree Classifier Algorithm 0.932554 (0.037078)

Now we are going to tuning the Random Forest and Gradient Boosting CLassification algorithms.....
"""
"""
Now we are going to apply tuning Random Forest and Gradient Boosting classification algorithms.
"""
# Random forest Classifier Tuning
import numpy as np
from sklearn.model_selection import GridSearchCV
scaler=StandardScaler().fit(x_train)
rescaledx=scaler.transform(x_train)
n_estimators=[10,20,30,40,50,100,150,200]
param_grid=dict(n_estimators=n_estimators)
model=RandomForestClassifier()
fold=KFold(n_splits=10,random_state=5)
grid=GridSearchCV(estimator=model,param_grid=param_grid,scoring=error,cv=fold)
grid_result=grid.fit(rescaledx,y_train)

print("Best: %f using %s "%(grid_result.best_score_,grid_result.best_params_))
# Gradient Boosting Classifier Tuning
import numpy as np
from sklearn.model_selection import GridSearchCV
scaler=StandardScaler().fit(x_train)
rescaledx=scaler.transform(x_train)
learning_rate=[0.01,0.05,0.1,0.2,0.3,0.4]
n_estimators=[10,20,30,40,50,100,150,200]
param_grid=dict(n_estimators=n_estimators,learning_rate=learning_rate)
model=GradientBoostingClassifier()
fold=KFold(n_splits=10,random_state=5)
grid=GridSearchCV(estimator=model,param_grid=param_grid,scoring=error,cv=fold)
grid_result=grid.fit(rescaledx,y_train)

print("Best: %f using %s "%(grid_result.best_score_,grid_result.best_params_))
"""
After Applying tuning to classification algorithm and ensemble algorithm we got top 4 accuracy algorithm

1. Random Forest classification algorithm 0.942746 using {'n_estimators': 30} 
2. Gradient Boosting Classification algorithm 0.950357 using {'learning_rate': 0.2, 'n_estimators': 50} 
3. Logistic Regression 0.943995 using {'C': 0.9} 
4. Decision Tree Classifier Best: 0.905972 using {} 
"""
"""
As per above algorithm Ada Boosting Algorithm Giving the best Accuracy So now we are going to use Ada boost algorithm to fit and predict our model.
"""
# Finalize Model
# we finalized the Gradient Boosting Algorithm and evaluate the model for Hotel Booking Demand Dataset

from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
scaler=StandardScaler().fit(x_train)
scaler_x=scaler.transform(x_train)
model=GradientBoostingClassifier(learning_rate=0.2,n_estimators=50)
model.fit(scaler_x,y_train)

#Transform the validation test set data
scaledx_test=scaler.transform(x_test)
y_pred=model.predict(scaledx_test)
y_trainpred=model.predict(scaler_x)
accuracy_mean=accuracy_score(y_train,y_trainpred)
accuracy_matric=confusion_matrix(y_train,y_trainpred)
print("train set %f"%accuracy_mean)
print("train set ",accuracy_matric)



accuracy_mean=accuracy_score(y_test,y_pred)
accuracy_matric=confusion_matrix(y_test,y_pred)
print("test set %f"%accuracy_mean)
print("test set ",accuracy_matric)
"""
Well Done we got accuracy for training set is 100% and 92.89% for test set...
"""