#!/usr/bin/env python
# coding: utf-8

# In[1]:


import localhelper,lewishelper
import copy
import pandas as pd
import xgboost


import sys


(X_train,y_train,df,pred,clf)=localhelper.process_adult("randomforest")


df['target']=pred

featlst=list(df.columns)
featlst.remove('target')


# In[2]:


df.iloc[5]


# In[ ]:





# In[3]:


descendant={'Age':['marital','edu','class','occupation','hours'],'sex':['marital','edu','class','occupation','hours'],'country':['marital','edu','class','occupation','hours'],'marital':['edu','class','occupation','hours'],'edu':['class','occupation','hours'],
          'class':[],'occupation':[],
          'hours':['occupation','class']}


# In[4]:


###LOcal explanation to reduce
###LOcal explanations here
def get_scores_decrease(index, df,score_type):

    row=list(df.columns)
    value_map={}
    for feat in row:
        values=list(set(df[feat]))
        value_map[feat]=values

    row.remove('target')
    orig_row=row
    row=copy.deepcopy(orig_row)

    #print(row)
    curr=df.iloc[index]
    
    featnames=copy.deepcopy(row)
    maxscores=[]
    
    for feat in featnames:
        curr_feat=feat
        rowval=[]
        for f in row:
            rowval.append(curr[f])

        ind=row.index(curr_feat)
        prevval=rowval[ind]
        rowval.pop(ind)
        row.pop(ind)

        descendantlst=descendant[feat]
        for f in descendantlst:
            #print(f,row)
            ind=row.index(f)
            #print(ind)
            rowval.pop(ind)
            row.pop(ind)


        values=value_map[feat]
        max_suff=-1
        suff_val=-1
        for val in values:
            #if val<=prevval:
            #    continue
            if feat=='Age'or feat=='sex' or feat=='country':
                suff=lewishelper.get_scores_regression(df,[curr_feat],[prevval],[val],[],[],[],'target')[score_type]
            #elif feat=='marital':
            #    suff=lewishelper.get_scores_regression(df,[curr_feat],[prevval],[val],[],[],[],'target')[score_type]
            else:
                suff=lewishelper.get_scores_regression(df,[curr_feat],[prevval],[val],row,rowval,[],'target')[score_type]
            max_suff=max(max_suff,suff)
            if max_suff==suff:
                suff_val=val
        #print (feat,max_suff,suff_val,prevval)
        maxscores.append(max_suff)
        row.append(feat)
        rowval.append(prevval)
        row=copy.deepcopy(orig_row)
    return (featnames,maxscores)


# In[5]:


###LOcal explanation to reduce
###LOcal explanations here
def get_scores_increase(index, df,score_type):

    row=list(df.columns)
    value_map={}
    for feat in row:
        values=list(set(df[feat]))
        value_map[feat]=values

    row.remove('target')
    orig_row=row
    row=copy.deepcopy(orig_row)

    #print(row)
    curr=df.iloc[index]
    
    featnames=copy.deepcopy(row)
    maxscores=[]
    
    for feat in featnames:
        curr_feat=feat
        rowval=[]
        for f in row:
            rowval.append(curr[f])

        ind=row.index(curr_feat)
        prevval=rowval[ind]
        rowval.pop(ind)
        row.pop(ind)

        descendantlst=descendant[feat]
        for f in descendantlst:
            #print(f,row)
            ind=row.index(f)
            #print(ind)
            rowval.pop(ind)
            row.pop(ind)


        values=value_map[feat]
        max_suff=-1
        suff_val=-1
        for val in values:
            #if val>=prevval:
            #    continue
            #print (row,rowval,val,prevval)
            if feat=='age'or feat=='sex' or feat=='country':
                suff=lewishelper.get_scores_regression(df,[curr_feat],[val],[prevval],[],[],[],'target')[score_type]
            else:
                suff=lewishelper.get_scores_regression(df,[curr_feat],[val],[prevval],row,rowval,[],'target')[score_type]
            #print("suff",suff)
            max_suff=max(max_suff,suff)
            if max_suff==suff:
                suff_val=val

        #print (feat,max_suff,suff_val,prevval,val)
        maxscores.append(max_suff)
        row.append(feat)
        rowval.append(prevval)
        row=copy.deepcopy(orig_row)
    #print (featnames,maxscores)

    return (featnames,maxscores)


# In[6]:


(featname,dec)=get_scores_decrease(5,df,1)


# In[7]:


(featname,inc)=get_scores_increase(5,df,1)


# In[8]:


featname


# In[9]:


inc


# In[10]:


dec


# In[11]:


inc= [ele * -1 for ele in inc]

# select features to show
featlst=['Age', 'sex', 'country', 'marital', 'edu', 'class', 'occupation', 'hours'] 
negvals=["34 yr", "Male", "USA", "Never married", "10th", "Private", "Other service", "30"]
featlabels=['Age', 'Sex', 'Country', 'Marital', 'Education', 'Class', 'Occupation', 'Hours'] 

raven_f=inc
ravendec_f=dec

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pylab as plot

fsize=25
params = {'legend.fontsize': fsize,
          'legend.handlelength': 2}
plot.rcParams.update(params)

font = {'family' : "sans serif", 'size'   : fsize}
matplotlib.rcParams['font.family'] = "sans-serif"
matplotlib.rcParams['hatch.linewidth'] = 0.3
matplotlib.rc('font', **font)

labels=featlabels
barlabels=negvals

x = np.arange(len(labels))  # the label locations
width = 0.25  # the width of the bars

fig, ax = plt.subplots()
rects1 = ax.barh(x - width, raven_f, width, color='khaki', edgecolor='black', hatch="\\\\")
rects2 = ax.barh(x, ravendec_f, width, color='goldenrod', edgecolor='black', hatch="//")

# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_xlabel('Negative output example', fontsize=fsize, labelpad=fsize/2)
ax.set_yticks(x)
ax.set_yticklabels(labels, fontsize=fsize)
ticks =  ax.get_xticks()
ax.set_xticklabels([(abs(round(tick,1))) for tick in ticks], fontsize=fsize)

x_offset = 0
y_offset = 0.4
for i in range(len(labels)):
    val = barlabels[i]
    p = ax.patches[i]
    b = p.get_bbox()
    ax.annotate(val, (b.x1 + x_offset, b.y1 + y_offset), fontsize=fsize/1.1, color='black')
    
import seaborn
seaborn.despine(left=True, right=True)

figure = plt.gcf() # get current figure
figure.set_size_inches(7.5,6)
fig.tight_layout()
plt.savefig('newplots/adult_local_negative_endtoend.pdf')


# In[ ]:





# In[12]:


import numpy as np
import pandas as pd
import sklearn
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.utils import resample
import copy
import random
import xgboost

import shap
import lime

np.random.seed(1)


feature_names=list(df.columns)
feature_names.remove('target')
class_names = np.unique(pred).tolist()
# Lime explanations
limeExplainer = lime.lime_tabular.LimeTabularExplainer(X_train.to_numpy(), feature_names=feature_names,
                                                       class_names=class_names)
predict_fn = lambda x: clf.predict_proba(x).astype(float)

'''
# Shapley scores
shap.initjs()
shapExplainer = shap.TreeExplainer(model)
shap_values = shapExplainer.shap_values(X_train)
'''
limeExp = limeExplainer.explain_instance(df[feature_names].iloc[5], predict_fn, num_features=200)


# In[13]:


feature_names


# In[14]:


#limeExp.show_in_notebook(show_all=False)


# In[15]:


#print (limeExp.local_exp)


# In[16]:


feature_names


# In[17]:


limescores=[0 for u in feature_names]
for (u,v) in limeExp.local_exp[1]:
    limescores[u]=v


# In[18]:


import matplotlib.pyplot as plt
#shap.initjs()
shapExplainer = shap.TreeExplainer(clf)
shap_values = shapExplainer.shap_values(df)

#shap.force_plot(shapExplainer.expected_value[1], shap_values[1][5], X_test.iloc[5],show=True,matplotlib=True)#.savefig('german_shap.pdf')


# In[19]:


shap.force_plot(shapExplainer.expected_value[1], shap_values[1][5], df.iloc[5],show=True,matplotlib=True)#.savefig('german_shap.pdf')


# In[20]:


shapval=shap_values[0][5]
shapname=feature_names


# In[21]:


feature_names


# In[ ]:





# In[ ]:





# In[22]:


# our = [max(raven[i], ravendec[i]) for i in range(len(raven))]
#raven = [ele * -1 for ele in inc]
shapval = [ele * -1 for ele in shapval]
ravenmax = max(max([abs(ele) for ele in inc]), max([abs(ele) for ele in dec]))

# raven is ordered 
lime_ordered=[]
limenamevals=[]
limevals=[]
for i in range(len(feature_names)):
    limevals.append(limescores[i])
    lime_ordered.append((limescores[i], feature_names[i]))
            
shap_ordered=[]
shapvals=[]
for i in range(len(feature_names)):
    for j in range(len(shapname)):
        if feature_names[i] in shapname[j]:
            shap_ordered.append((shapval[j], feature_names[i]))
            shapvals.append(shapval[j])
            


# In[23]:


shap_ordered


# In[ ]:





# In[24]:


normalized_shapley=[]
normalized_lime=[]
normalized_raven=[]
normalized_ravendec=[]
for i in range(len(feature_names)):
    #print (i,feature_names[i],shapvals)
    normalized_shapley.append(shapvals[i]*1.0/max([abs(ele) for ele in shapval]))
    normalized_lime.append(limevals[i]*1.0/max([abs(ele) for ele in limevals]))
    normalized_raven.append(inc[i]*1.0/ravenmax)
    normalized_ravendec.append(dec[i]*1.0/ravenmax)
    i+=1
import scipy.stats as ss
shapley_rank=ss.rankdata([abs(ele) for ele in normalized_shapley], method='min')
lime_rank=ss.rankdata([abs(ele) for ele in normalized_lime], method='min')
raven_rank=ss.rankdata([abs(ele) for ele in normalized_raven], method='min')
ravendec_rank=ss.rankdata([abs(ele) for ele in normalized_ravendec], method='min')


# In[25]:


# select features to show
featlst=['Age', 'sex', 'country', 'marital', 'edu', 'class', 'occupation', 'hours']
feats=['age=34 yr', 'sex=Male', 'country=USA', 'marital=Never', 'edu=10th', 'class=Private', 'occup=Other', 'hours=30']

# featlst = ravenname
# feats = featlst

shaprank_f=[]
limerank_f=[]
ravenrank_f=[]
ravendecrank_f=[]

raven_f=[]
ravendec_f=[]
lime_f=[]
shapley_f=[]

for feat in featlst:
    idx = feature_names.index(feat)
    shapley_f.append(normalized_shapley[idx])
    lime_f.append(normalized_lime[idx])
    raven_f.append(normalized_raven[idx])
    ravendec_f.append(normalized_ravendec[idx])
    shaprank_f.append(shapley_rank[idx])
    limerank_f.append(lime_rank[idx])
    ravenrank_f.append(raven_rank[idx])
    ravendecrank_f.append(ravendec_rank[idx])


# In[26]:


import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pylab as plot

fsize=20
params = {'legend.fontsize': fsize,
          'legend.handlelength': 2,
         'axes.labelsize': fsize,
         'axes.titlesize':fsize,
         'xtick.labelsize':fsize}
plot.rcParams.update(params)
font = {'family' : "sans serif", 'size'   : fsize}
matplotlib.rc('font', **font)
matplotlib.rcParams['hatch.linewidth'] = 0.3

labels=feats
# labels=limenames
x = np.arange(len(labels))  # the label locations
width = 0.25/1.3  # the width of the bars
plt.figure(figsize=(6, 10)) # in inches!

fig, ax = plt.subplots()
rects1 = ax.barh(x - 2 * width, raven_f, width, label='Lewis:-ve', color='khaki', edgecolor='black', hatch="\\")
rects2 = ax.barh(x - width, ravendec_f, width, label='Lewis:+ve', color='goldenrod', edgecolor='black', hatch="\\")
# rects2 = ax.barh(x, ravendec, width, label='Our-Down',color='royalblue', edgecolor='black')
# rects3 = ax.barh(x + width, lime_0, width, label='Lime: O=0',color='lightcoral', edgecolor='black', hatch="/")
# rects3 = ax.barh(x + 2*width, lime_1, width, label='Lime: O=1',color='y', edgecolor='black', hatch="-")
rects3 = ax.barh(x, lime_f, width, label='LIME',color='snow', edgecolor='black', hatch="/")
rects4 = ax.barh(x + width, shapley_f, width, label='SHAP',color='lightcoral', edgecolor='black', hatch="|")

# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_xlabel('Normalized score', fontsize=fsize, labelpad=10)
ax.set_yticks(x)
ax.set_yticklabels(labels, fontsize=fsize*1.1)

ax.set_xticks(range(-1, 2, 1))
ax.set_xticklabels([abs(y) for y in range(-1, 2, 1)])
ax.xaxis.set_ticks_position('bottom')
ax.xaxis.set_label_position('bottom')
# ax.legend(loc=0)
ax.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
       ncol=2, mode="expand", borderaxespad=0.)
# ax.invert_yaxis()
plt.xticks(np.arange(-1, 1.2, 1))
matplotlib.pyplot.hlines(labels,-1,1, color='gainsboro', zorder=0, linestyles='dashed')

def autolabel(rects,rank, col):
    """Attach a text label above each bar in *rects*, displaying its height."""
    i=0
    for rect in rects:
        height = rect.get_width()
        offset = 0.07
        if height < 0:
            offset = offset * -1
        val=len(shapley_rank)-int(rank[i])+1
        ax.annotate('{}'.format(val),
                    xy=(height + offset, rect.get_y() + abs(0.08 * offset)),
                    xytext=(0, -5),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom', fontsize=fsize/1.2, color=col)
        i+=1


autolabel(rects1,ravenrank_f, 'black')
autolabel(rects2,ravendecrank_f, 'black')
autolabel(rects3,limerank_f, 'black')
autolabel(rects4,shaprank_f, 'black')

# handles, labels = ax.get_legend_handles_labels()
# ax.legend(handles[::-1], labels[::-1])
# plt.show()
figure = plt.gcf() # get current figure
figure.set_size_inches(8,12)
fig.tight_layout()
plt.savefig('newplots/adult_local_negative_related.pdf')


# In[ ]:





# In[27]:


(featname,inc)=get_scores_increase(7,df,0)


# In[28]:


(featname,dec)=get_scores_decrease(7,df,0)


# In[29]:


inc


# In[30]:


dec


# In[31]:


featname


# In[32]:


inc= [ele * -1 for ele in inc]


# select features to show
featlst=['Age', 'sex', 'country', 'marital', 'edu', 'class', 'occupation', 'hours']
vals=["63 yr", "Male", "USA", "Married-civ-spouse", "HS-grad", "Self-emp-not-inc", "Prof-specialty", "32"]
# featlst = ravenname

raven_f=inc
ravendec_f=dec
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pylab as plot

fsize=25
params = {'legend.fontsize': fsize,
          'legend.handlelength': 2}
plot.rcParams.update(params)

font = {'family' : "sans serif", 'size'   : fsize}
matplotlib.rcParams['font.family'] = "sans-serif"
matplotlib.rcParams['hatch.linewidth'] = 0.3
matplotlib.rc('font', **font)

labels=featlabels
barlabels=vals

x = np.arange(len(labels))  # the label locations
width = 0.25  # the width of the bars

fig, ax = plt.subplots()
rects1 = ax.barh(x - width, raven_f, width, color='lightsteelblue', edgecolor='black', hatch="\\\\")
rects2 = ax.barh(x, ravendec_f, width, color='cornflowerblue', edgecolor='black', hatch="//")

# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_yticks([])

ax.set_xlabel('Positive output example', fontsize=fsize, labelpad=fsize/2)
ticks =  ax.get_xticks()
ax.set_xticklabels([(abs(tick)) for tick in ticks], fontsize=fsize)
ax.xaxis.set_ticks_position('bottom')

from matplotlib.ticker import FormatStrFormatter
ax.xaxis.set_major_formatter(FormatStrFormatter('%.1f'))

x_offset = 0
y_offset = 0.4
for i in range(len(labels)):
    val = barlabels[i]
    p = ax.patches[i]
    b = p.get_bbox()
    ax.annotate(val, (b.x0 + x_offset, b.y1 + y_offset), fontsize=fsize/1.1, color='black')
    
import seaborn
seaborn.despine(left=True, right=True)

figure = plt.gcf() # get current figure
figure.set_size_inches(5,6)
fig.tight_layout()
plt.savefig('newplots/adult_local_positive_endtoend.pdf')


# In[33]:


df.iloc[7]


# In[34]:


limeExp = limeExplainer.explain_instance(df[feature_names].iloc[7], predict_fn, num_features=200)


# In[35]:


limescores=[0 for u in feature_names]
for (u,v) in limeExp.local_exp[1]:
    limescores[u]=v


# In[36]:


limescores


# In[37]:


import matplotlib.pyplot as plt
#shap.initjs()
shapExplainer = shap.TreeExplainer(clf)
shap_values = shapExplainer.shap_values(df,check_additivity=False)

shap.force_plot(shapExplainer.expected_value[1], shap_values[1][7], df.iloc[7],show=True,matplotlib=True)#.savefig('german_shap.pdf')
shapval=shap_values[0][7]
shapname=feature_names


# In[38]:


# our = [max(raven[i], ravendec[i]) for i in range(len(raven))]
#raven = [ele * -1 for ele in inc]
shapval = [ele * -1 for ele in shapval]
ravenmax = max(max([abs(ele) for ele in inc]), max([abs(ele) for ele in dec]))

# raven is ordered 
lime_ordered=[]
limenamevals=[]
limevals=[]
for i in range(len(feature_names)):
    limevals.append(limescores[i])
    lime_ordered.append((limescores[i], feature_names[i]))
            
shap_ordered=[]
shapvals=[]
for i in range(len(feature_names)):
    for j in range(len(shapname)):
        if feature_names[i] in shapname[j]:
            shap_ordered.append((shapval[j], feature_names[i]))
            shapvals.append(shapval[j])
            


# In[39]:


normalized_shapley=[]
normalized_lime=[]
normalized_raven=[]
normalized_ravendec=[]
for i in range(len(feature_names)):
    #print (i,feature_names[i],shapvals)
    normalized_shapley.append(shapvals[i]*1.0/max([abs(ele) for ele in shapval]))
    normalized_lime.append(limevals[i]*1.0/max([abs(ele) for ele in limevals]))
    normalized_raven.append(inc[i]*1.0/ravenmax)
    normalized_ravendec.append(dec[i]*1.0/ravenmax)
    i+=1
import scipy.stats as ss
shapley_rank=ss.rankdata([abs(ele) for ele in normalized_shapley], method='min')
lime_rank=ss.rankdata([abs(ele) for ele in normalized_lime], method='min')
raven_rank=ss.rankdata([abs(ele) for ele in normalized_raven], method='min')
ravendec_rank=ss.rankdata([abs(ele) for ele in normalized_ravendec], method='min')


# In[40]:


# select features to show
featlst=['Age', 'sex', 'country', 'marital', 'edu', 'class', 'occupation', 'hours']
feats=['age=63 yr', 'sex=Male', 'country=USA', 'marital=Married-civ', 'edu=Prof-school', 'class=Self-emp-not', 'occup=Prof-spec', 'hours=32']

# featlst = ravenname
# feats = featlst

shaprank_f=[]
limerank_f=[]
ravenrank_f=[]
ravendecrank_f=[]

raven_f=[]
ravendec_f=[]
lime_f=[]
shapley_f=[]

for feat in featlst:
    idx = feature_names.index(feat)
    shapley_f.append(normalized_shapley[idx])
    lime_f.append(normalized_lime[idx])
    raven_f.append(normalized_raven[idx])
    ravendec_f.append(normalized_ravendec[idx])
    shaprank_f.append(shapley_rank[idx])
    limerank_f.append(lime_rank[idx])
    ravenrank_f.append(raven_rank[idx])
    ravendecrank_f.append(ravendec_rank[idx])


# In[41]:


import matplotlib
import matplotlib.pyplot as plt
import numpy as np

import pylab as plot
fsize=20
params = {'legend.fontsize': fsize/1.1,
          'legend.handlelength': 2,
         'axes.labelsize': fsize,
         'axes.titlesize':fsize,
         'xtick.labelsize':fsize}
plot.rcParams.update(params)
font = {'family' : "sans serif", 'size'   : fsize}
matplotlib.rc('font', **font)
matplotlib.rcParams['hatch.linewidth'] = 0.3

labels=feats
# labels=limenames
x = np.arange(len(labels))  # the label locations
width = 0.25/1.2  # the width of the bars
plt.figure(figsize=(6, 10)) # in inches!

fig, ax = plt.subplots()
rects1 = ax.barh(x - 2 * width, raven_f, width, label='Lewis:-ve', color='lightsteelblue', edgecolor='black', hatch="\\")
rects2 = ax.barh(x - width, ravendec_f, width, label='Lewis:+ve', color='cornflowerblue', edgecolor='black', hatch="\\")
# rects2 = ax.barh(x, ravendec, width, label='Our-Down',color='royalblue', edgecolor='black')
# rects3 = ax.barh(x + width, lime_0, width, label='Lime: O=0',color='lightcoral', edgecolor='black', hatch="/")
# rects3 = ax.barh(x + 2*width, lime_1, width, label='Lime: O=1',color='y', edgecolor='black', hatch="-")
rects3 = ax.barh(x, lime_f, width, label='LIME',color='snow', edgecolor='black', hatch="/")
rects4 = ax.barh(x + width, shapley_f, width, label='SHAP',color='lightcoral', edgecolor='black', hatch="|")

# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_xlabel('Normalized score', fontsize=fsize, labelpad=10)
ax.set_yticks(x)
ax.set_yticklabels(labels, fontsize=fsize)

ax.set_xticks(range(-1, 2, 1))
ax.set_xticklabels([abs(y) for y in range(-1, 2, 1)])
ax.xaxis.set_ticks_position('bottom')
ax.xaxis.set_label_position('bottom')
# ax.legend(loc=0)
ax.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
       ncol=2, mode="expand", borderaxespad=0.)
# ax.invert_yaxis()
plt.xticks(np.arange(-1, 1.2, 1))
matplotlib.pyplot.hlines(labels,-1,1, color='gainsboro', zorder=0, linestyles='dashed')

def autolabel(rects,rank, col):
    """Attach a text label above each bar in *rects*, displaying its height."""
    i=0
    for rect in rects:
        height = rect.get_width()
        offset = 0.07
        if height < 0:
            offset = offset * -1
        val=len(shapley_rank)-int(rank[i])+1
        ax.annotate('{}'.format(val),
                    xy=(height + offset, rect.get_y()),
                    xytext=(0, -5),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom', fontsize=fsize/1.3, color=col)
        i+=1


autolabel(rects1,ravenrank_f, 'black')
autolabel(rects2,ravendecrank_f, 'black')
autolabel(rects3,limerank_f, 'black')
autolabel(rects4,shaprank_f, 'black')

# handles, labels = ax.get_legend_handles_labels()
# ax.legend(handles[::-1], labels[::-1])

# plt.show()
figure = plt.gcf() # get current figure
figure.set_size_inches(8,12)
fig.tight_layout()
plt.savefig('newplots/adult_local_positive_related.pdf')


# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:




