"""
# What is explainable AI?

Whenever we make any Machine learning or Neural Network Model we only judge a model by the prediction it makes.

But for most of the **non-linear model** we never know how our model has predicted Means we don't know what **features** contributed to our prediction.

And if somehow we can extract those features for our prediction. We can answer very Impotant Question mostly asked in **Interviews**

<font color='orange'>**Can you Explain this model like I am 5 ?**</font>

![](https://i.pinimg.com/originals/55/5c/a3/555ca3f972ccb9faa88683a1e2c316eb.png)


"""
"""
# Why Explainable AI is Important?

## <font  color ='orange'>1. Cross Validation can Fail</font>

Although we can rely on cross validation for testing our  model before putting in production

But the problem with cross validation is  we never know what kind of testing data we’ll get in 
production.

## <font color='orange'> 2. A/B Testing  not the solution For  everyone </font>

Although A/B testing is a  golden standard but the problem is

2.1   Companies will have to expose Not the best quality product to  public testers.

2.2   It can  be expensive as well.



"""
"""
# <font color='blue'> Why I am Stressing Upon It?</font>

![](https://www.kdnuggets.com/images/xai-fig3-accuracy-vs-explainability-600.jpg)
"""
"""
## So for explainability purpose we will use

## <font color='red'> ELI5 ---> Explain me Like i'm 5 😊</font>

For refrence 

1. LIME  =Local Model Agnostic Explainability -----> https://arxiv.org/abs/1602.04938
2. SHAPLEY = Shapley Additive Explainations   ---->https://arxiv.org/abs/1911.11888


### <font color='orange'> If you like my work pls upvote my work</font>
"""
"""
#  LET'S <font color='yellow'>LIME</font>
![](https://miro.medium.com/max/818/1*Wwjnrq1G3e7_BCsN2BD06A.png)

"""
"""
#  Let's Break It?

## What is <font color='red'>LOCAL</font>?

### Why did the model make a certain prediction for an instance?


We will zoom in on a single instance and examine what the model predicts for this input, and explain why. If you look at an individual prediction, the behavior of the otherwise complex model might behave more pleasantly. Locally, the prediction might only depend linearly or monotonically on some features, rather than having a complex dependence on them. For example, the value of a house may depend nonlinearly on its size. But if you are looking at only one particular 100 square meters house, there is a possibility that for that data subset, your model prediction depends linearly on the size. You can find this out by simulating how the predicted price changes when you increase or decrease the size by 10 square meters. Local explanations can therefore be more accurate than global explanations

### What is <font color='red'>Model-Agnostic</font>?

It means any model till date can be applied to LIME and Lime can create local explanations for  them
By treating each model as <font color='orange'>Black box model</font>
should not make any assumptions about model while providing explanations.

### Explanation is just an explanation 😊😊


##  TYPES OF INTERPRETABILITY

There are two main ways to look at a **classification** or a **regression** model:
1. Inspect model parameters and try to figure out how the model works globally.

2. Inspect an individual **prediction of a model** , try to figure out why the model makes the decision it makes.



"""
"""
# What I wanted to Say?
![](https://miro.medium.com/max/1124/1*vE3PUuhG6RRgK1J9oxg0nA.png)

The **black-box model’s** complex decision function f (unknown to LIME) is represented by the blue/pink background, which cannot be approximated well by a linear model. The bold red cross is the instance being explained. LIME samples instances, gets predictions using f, and weighs them by the proximity to the instance being explained (represented here by size). The dashed line is the learned explanation that is locally (but not globally) faithful.
"""
"""
## What Makes <font color='yellow'>LIME</font> excellent ?
LIME use a representation that is understood by the humans irrespective of the actual features used by the model. This is coined as interpretable representation. An interpretable representation would vary with the type of data that we are working with for example :
1. For **text** : It represents presence/absence of words.
2. For **image** : It represents presence/absence of super pixels ( contiguous patch of similar pixels ).
3. For **tabular data** : It is a weighted combination of columns

## LET's Do  SOME PRACTICAL WORK?
"""
# 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

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 read-only "../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))

# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
import warnings
import gc,time
#nlp
import string
import re    #for regex
import nltk
from nltk.corpus import stopwords

import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
color = sns.color_palette()
sns.set_style("dark")
eng_stopwords = set(stopwords.words("english"))
warnings.filterwarnings("ignore")
train=pd.read_csv('/kaggle/input/jigsaw-toxic-comment-classification-challenge/train.csv.zip')
test=pd.read_csv('/kaggle/input/jigsaw-toxic-comment-classification-challenge/test.csv.zip')
submission=pd.read_csv('/kaggle/input/jigsaw-toxic-comment-classification-challenge/sample_submission.csv.zip')
test_labels=pd.read_csv('/kaggle/input/jigsaw-toxic-comment-classification-challenge/test_labels.csv.zip')
train.head()
"""
### Classes are imbalanced
"""

x=train.iloc[:,2:].sum()
x#COLUMN wise sum

fig = px.bar( x=x.index, y=x.values,
             height=400)
fig.show()
"""
## <font color='blue'>Divided train and test set using stratified sampling</font>

### We are working for a Binary Text Classification

We have used 20 percent of Clean and Toxic comments because from above we there is Huge class Imbalance bw clean and 

Toxic comments. So to Handle that Imbalance we will over-sample Toxic comments but due to CPU limitations we have to use

20 percent of data from other classes and then we will oversample Toxic comments class
"""
clean_df=train.loc[(train.toxic==0) &  (train.severe_toxic==0) &(train.obscene==0) &
                   (train.threat==0)  &(train.insult==0) &(train.identity_hate==0)] # clean  comments

toxic_df=train.loc[(train.toxic==1)]# toxic comments

#creating test set
clean_test=clean_df.iloc[:28669]# 20percent of  total clean comments which are  approximately 144000
toxic_test=toxic_df.iloc[:3059]# 20percent of Toxic  comments which are approximately 15000

test_set=clean_test.append(toxic_test,ignore_index=True).sample(frac=1)# appending 2 dataframes and shuffling them
test_set.drop(['id','severe_toxic','obscene','threat','insult','identity_hate'],axis=1,inplace=True)
print(test_set.shape)

#creating train set
clean_train=clean_df.iloc[28669:]
toxic_train=toxic_df.iloc[3059:]
df=clean_train.append(toxic_train,ignore_index=True).sample(frac=1)

# df=clean_df.append(toxic_df,ignore_index=1).sample(frac=1)# appending 2 dataframes and shuffling them
df.drop(['id','severe_toxic','obscene','threat','insult','identity_hate'],axis=1,inplace=True)
df.shape

# Applying a first round of text cleaning techniques

def clean_text(text):
    '''Make text lowercase, remove text in square brackets,remove links,remove punctuation
    and remove words containing numbers.'''
    text = text.lower()
    text = re.sub('\[.*?\]', '', text)
    text = re.sub('https?://\S+|www\.\S+', '', text)
    text = re.sub('<.*?>+', '', text)
    text = re.sub('[%s]' % re.escape(string.punctuation), '', text)
    text = re.sub('\n', '', text)
    text = re.sub('\w*\d\w*', '', text)
    return text
# Applying the cleaning function to both test and training datasets
df['comment_text'] = df['comment_text'].apply(lambda x: clean_text(x))
test_set['comment_text']=test_set['comment_text'].apply(lambda x:clean_text(x))
dictionary_clean={0:'clean',1:'toxic'}
df['target_name']=df['toxic'].map(dictionary_clean)
test_set['target_name']=test_set['toxic'].map(dictionary_clean)
"""
## Logistic regression
"""
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegressionCV
from sklearn.pipeline import make_pipeline
from imblearn.over_sampling import  SMOTE


smt = SMOTE(random_state=777, k_neighbors=1)

vec = TfidfVectorizer(min_df=3,max_features=10000,strip_accents='unicode',
                     analyzer='word',ngram_range=(1,2),token_pattern=r'\w{1,}',use_idf=1,smooth_idf=1,sublinear_tf=1,
                     stop_words='english')

vec_fit=vec.fit_transform(df.comment_text)

clf = LogisticRegressionCV()


# Over Sampling
X_SMOTE, y_SMOTE = smt.fit_sample(vec_fit, df.toxic)

from collections import Counter
#we over sampled it 
print(Counter(y_SMOTE))

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(C=0.1, solver='sag')
scores = cross_val_score(clf, X_SMOTE,y_SMOTE, cv=5,scoring='f1_weighted')
scores
clf.fit(X_SMOTE,y_SMOTE)
from sklearn import metrics

def print_report1(df):
    y_test =  df.toxic
    test_features=vec.transform(df.comment_text)
    y_pred = clf.predict(test_features)
    report = metrics.classification_report(y_test, y_pred,
        target_names=list(df.target_name.unique()))
    print(report)
    print("accuracy: {:0.3f}".format(metrics.accuracy_score(y_test, y_pred)))

print_report1(test_set)
"""
### VERY IMPORTANT
whenever we use  Logistic regressionin  for  2 columns it treats it as Binary problem  hence we  get 1  table

https://stackoverflow.com/questions/51659523/eli5-show-weights-with-two-labels
"""
"""
## Features Using Logistic Regression
"""
import eli5
# import warnings filter
from warnings import simplefilter
# ignore all future warnings
simplefilter(action='ignore', category=FutureWarning)
eli5.show_weights(clf, vec=vec, top=15,
                  target_names=['clean','toxic'])

#  if we got the BIAS term that occurs
#because we are using Linear model for classification and the Intercept added to the equation is termed BIAS here


"""
# Explain me Results?

So above figure tells that green word contributed most to **Toxic** comments and **Red** words  contributed to opposite class that 

is **Clean comments** class
"""
"""
## Testing  time
"""
print(test_set.comment_text[0])
print('\n')
print(test_set.toxic[0])
"""
## and what Eli5 shows
"""
import eli5
eli5.show_prediction(clf, test_set.comment_text[0], vec=vec,
                     target_names=list(df.target_name.unique()),top=15)
# it shows probability of each of  the 2 classes and then shows which features contributed the most and which
# contributed the least in each class
# top argument shows the  top n features that contibuted to the prediction of each class
"""
So THAT was it

## <font color='red'>HOPE you liked my work. Please share and comment below 😄</font>
"""