%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pd.options.mode.chained_assignment = None  # default='warn'

#Lecture
listeVar=['MATRIC','DEPTS','PVS','SEXEQ','AGER','FAMIQ', 
 'RELAT','PCSPQ','QUALS','G03G04S','G25G26S', 
 'G29G30S','G35G36S','G37G38S','G45G46S','G47G48S',
 'IMPNBS','REJETS','OPGNB','MOYRV','TAVEP','ENDET','GAGET',
 'GAGEC','GAGEM','KVUNB','QSMOY','QCRED','DMVTP','BOPPN',
 'FACAN','LGAGT','VIENB','VIEMT','UEMNB','UEMMTS','XLGNB',
 'XLGMT','YLVNB','YLVMT','NBELTS','MTELTS','NBCATS','MTCATS',
 'NBBECS','MTBECS','ZOCNB','NTCAS','NPTAG','SEGV2S','ITAVC',
 'HAVEF','JNBJD1S','JNBJD2S','JNBJD3S','CARVP']
path=""
visaraw = pd.read_table(path+'visa_raw.dat',
                        sep=';',header=None, index_col=0, names=listeVar)

"""
Explanation: <center>
<a href="http://www.insa-toulouse.fr/" ><img src="http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/logo-insa.jpg" style="float:left; max-width: 120px; display: inline" alt="INSA"/></a> 
<a href="http://wikistat.fr/" ><img src="http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/wikistat.jpg" style="float:right; max-width: 250px; display: inline"  alt="Wikistat"/></a>
</center>
Scénarios d'Exploration Statistique
GRC: Segmentation d'une clientèle bancaire en <a href="https://www.python.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Python_logo_and_wordmark.svg/390px-Python_logo_and_wordmark.svg.png" style="max-width: 120px; display: inline" alt="Python"/></a>
Résumé
Ce scénario décrit le traitement classique, la fouille, de données pour la gestion de la relation client (GRC); exploration de données bancaires par des méthodes uni, bi et multidimensionnelles: ACP, AFCM puis segmentation de clientèle par classification non-supervisée k-means, CAH et représentation, interprétation des classes.
Introduction
Objectif
Ce scénatio propose  de décrire un jeu de données bancaires  en utilisant les principales méthodes de statistique exploratoire multidimensionnelle: analyse en composantes principales, analyse des correspondances simple et multiple, classification non supervisée. L'objectif principal, classqiue en marketing, est de produire une segmentation de clientèle, c'est-à-dire une répartition en classes homogènes des clients en fonction de leur comportement bancaire. C'est aussi la mise en oeuvre d'une démarche classique permettant d'affiner sa compréhension des données dans l'idée de construire un score d'appétence pour la carte visa premier. Ce deuxième objectif est intégré à la saison 3 (Apprentissage Statistique). Il s'agit du score d'appétence de la carte Visa Premier mais ce pourrait être un score d'attrition ({\it churn}) d'un opérateur téléphonique ou encore un score de défaillance d'un emprunteur ou de faillite d'une entreprise; les outils de modélisation sont les mêmes et sont très largement utilisés dans tout le secteur tertiaire pour l'aide à la décision.
Une autre version du même scénario  propose d'utiliser le logiciel SAS alors que ce calepin propose une solution en Python utilisant la librairie Scikit-learn.
Présentation des données
Les variables
La liste des variables est issue d'une base de données retraçant l'historique mensuel bancaire et les caractéristiques de tous les clients. Un sondage a été réalisé afin d'alléger les traitements ainsi qu'une première sélection de variables. Les variables contenues dans le fichier initial sont décrites dans le tableau ci-dessous. Elles sont observées sur 1425 clients.
Tableau: Liste des variables et de leur libellé Attention, ils sont finalement écrits en majuscules dans les programmes.
Identifiant | Libellé
           --|--
matric | Matricule (identifiant client)
depts | Département de résidence
pvs | Point de vente
sexeq | Sexe (qualitatif) 
ager | Age en années
famiq | Situation familiale: Fmar Fcel Fdiv Fuli Fsep Fveu
relat | Ancienneté de relation en mois
pcspq | Catégorie socio-professionnelle (code num)
quals | Code "qualité" client évalué par la banque
GxxGxxS | plusieurs variables caractérisant les interdits bancaires
impnbs | Nombre d'impayés en cours
rejets | Montant total des rejets en francs
opgnb | Nombre d'opérations par guichet dans le mois
moyrv | Moyenne des mouvements nets créditeurs des 3 mois en Kf
tavep | Total des avoirs épargne monétaire en francs
endet | Taux d'endettement
gaget | Total des engagements en francs
gagec | Total des engagements court terme en francs
gagem | Total des engagements moyen terme en francs
kvunb | Nombre de comptes à vue
qsmoy | Moyenne des soldes moyens sur 3 mois
qcred | Moyenne des mouvements créditeurs en Kf
dmvtp | Age du dernier mouvement (en jours)\hline
boppn | Nombre d'opérations à M-1
facan | Montant facturé dans l'année en francs
lgagt | Engagement long terme
vienb | Nombre de produits contrats vie
viemt | Montant des produits contrats vie en francs
uemnb | Nombre de produits épargne monétaire
uemmts | Montant des produits d'épargne monétaire en francs
xlgnb | Nombre de produits d'épargne logement
xlgmt | Montant des produits d'épargne logement en francs
ylvnb | Nombre de comptes sur livret
ylvmt | Montant des comptes sur livret en francs
nbelts | Nombre de produits d'épargne long terme
mtelts | Montant des produits d'épargne long terme en francs
nbcats | Nombre de produits épargne à terme
mtcats | Montant des produits épargne à terme
nbbecs | Nombre de produits bons et certificats
mtbecs | Montant des produits bons et certificats en francs
rocnb | Nombre de paiements par carte bancaire à M-1
ntcas | Nombre total de cartes
nptag | Nombre de cartes point argent
segv2s | Segmentation version 2
itavc | Total des avoirs sur tous les comptes
havef | Total des avoirs épargne financière en francs
jnbjd1s | Nombre de jours à débit à M
jnbjd2s | Nombre de jours à débit à M-1
jnbjd3s | Nombre de jours à débit à M-2
carvp | Possession de la carte VISA Premier}
Réponde aux questions en s'aidant des résultats des exécutions
<FONT COLOR="Red">Épisode 1 <i>Data Munging </i></font>
Lecture et prétraitement  des données
Les données sont disponibles dans le répertoire de ce calepin et chargées en même temps.
Même si les données sont déjà extraites par échantillonnage d'une très grande base, elles nécessitent un travail prémiminaire (data munging) pour détecter, corriger les erreurs et incohérences, éliminer des redondances, traiter les données manquantes, transformer certaines variables.  Ce travail préliminaire, souvent long et fastidieux, nécessite d'y consacer beaucoup de temps et de rigueur afin de s'assurer de la qualité finale des résultats. 
Il fait appel à des outils classiques de statistique descriptive. 
Les données sont anonymisées et datent du siècle dernier, elles n'ont plus d'intérêt "commercial". De façon générale, plutôt que de conserver tous les fichiers de données intermédiaires à une étude, ce qui peut nécessiter beaucoup d'espace disque, il est important, voire crucial, d'archiver tous les programmes intermédiaires de saisie, sélection, transformation des données. En effet, en cas de problème ou même simplement d'un mauvais choix méthodologique, il faut pouvoir rapidement repartir d'une étape précédente. 
La production d'un calepin aide à cette mémoire lors de l'analyse préliminaire mais ne constitue pas un code opérationnel.
Lecture des données
End of explanation
"""


def create_categorical_data(df,column_name, cat_name_dic):
    cat_columns = pd.Categorical(df[column_name],ordered=False)
    new_categorie = [cat_name_dic[old_name] for old_name in cat_columns.categories]
    return cat_columns.rename_categories(new_categorie)

#FAMIQ
cat_name_dic = {'C':'Fcel','D':'Fdiv','M':'Fmar','S':'Fsep','U':'Fuli','V':'Fveu','inc':'Finc'}
visaraw["FAMIQ"]=create_categorical_data(visaraw,"FAMIQ", cat_name_dic)
#SEXEQ
cat_name_dic = {'1':'Shom','2':'Sfem','inc':'Sinc'}
visaraw["SEXEQ"]=create_categorical_data(visaraw,"SEXEQ", cat_name_dic)
#CARVP
cat_name_dic = {'non':'Cnon','oui':'Coui'}
visaraw["CARVP"]=create_categorical_data(visaraw,"CARVP", cat_name_dic)
#PCSPQ
visaraw["PCSPQ"] = visaraw["PCSPQ"].str.get(0).replace("0","i")
cat_name_dic = {'1':'Pagr', '2':'Part', '3':'Pcad', '4':'Pint', '5':'Pemp','6':'Pouv',
                '7':'Pret', '8':'Psan', 'i':'Pinc'}
visaraw["PCSPQ"]=create_categorical_data(visaraw,"PCSPQ", cat_name_dic)

"""
Explanation: Une fonction permet de définir le bon type "categorical" des variables qualitatives  en utilisant un dictionnaire des modalités pour le recodage.
End of explanation
"""


visaraw = visaraw[visaraw.NBCATS!= "1"]
visaraw = visaraw[visaraw.NBBECS!= "1"]

visaraw= visaraw[np.logical_not(visaraw.G29G30S.isin(['B','X']))] 
visaraw= visaraw[np.logical_not(visaraw.G03G04S.isin(['B','X']))] 
visaraw= visaraw[np.logical_not(visaraw.G45G46S.isin(['A','B','X']))] 
visaraw= visaraw[np.logical_not(visaraw.G37G38S.isin(['A']))] 
visaraw= visaraw[np.logical_not(visaraw.G25G26S.isin(['A','B','X']))] 
visaraw= visaraw[np.logical_not(visaraw.G47G48S.isin(['B']))] 

"""
Explanation: Premiers nettoyages
Suppression d'observations non pertinentes:interdits bancaires et comptes professionnels.
End of explanation
"""


visaraw = visaraw[visaraw.AGER!='.']

"""
Explanation: Suppression d'observations avec données manquantes de la variable AGER
End of explanation
"""


visaraw["AGER"]=visaraw["AGER"].astype(int)
visaraw=visaraw[np.logical_and(visaraw["AGER"]<66,visaraw["AGER"]>17)]

"""
Explanation: Seulement les clients de 18 à 65 ans
End of explanation
"""


visaraw["ZOCNB"]=visaraw["ZOCNB"].replace(".",np.nan)
visaraw["DMVTP"]=visaraw["DMVTP"].replace(".",np.nan)

"""
Explanation: Recodage des données manquantes
End of explanation
"""


listeVarFl=['RELAT','IMPNBS','REJETS','OPGNB','MOYRV',
'TAVEP','ENDET','GAGET','GAGEC','GAGEM','KVUNB','QSMOY','QCRED',
'DMVTP','BOPPN','FACAN','LGAGT','VIENB','VIEMT','UEMNB','UEMMTS','XLGNB',
 'XLGMT','YLVNB','YLVMT','NBELTS','MTELTS','NBCATS','MTCATS',
 'NBBECS','MTBECS','ZOCNB','NTCAS','NPTAG','ITAVC',
 'HAVEF','JNBJD1S','JNBJD2S','JNBJD3S']
visaraw[listeVarFl]=visaraw[listeVarFl].astype(float)

"""
Explanation: Correction des types des variables
End of explanation
"""


visaraw["JNBJD"]=visaraw["JNBJD1S"]+visaraw["JNBJD2S"]+visaraw["JNBJD3S"] 

"""
Explanation: Un seule variable nombre de jours de débit cumulé
End of explanation
"""


listeVarSup=["DEPTS","QUALS","G03G04S","G25G26S","G29G30S","G35G36S",
            "G37G38S","G45G46S","G47G48S","SEGV2S","PVS","JNBJD1S","JNBJD2S","JNBJD3S"]
visaraw.drop(listeVarSup,inplace=True,axis=1)

"""
Explanation: Suppression des variables devenues inutiles
End of explanation
"""


listeVar = [x for x in listeVar if x not in listeVarSup]

"""
Explanation: Mise à jour de la liste des variables
End of explanation
"""


# Moyennes
visaprem=visaraw
visaprem.mean()

"""
Explanation: Desciption univariée et bivariée
End of explanation
"""


visaprem["RELAT"].hist(bins=20)
plt.show()

"""
Explanation: Q Quel problème révèle la distribution ci-dessous de la variable  « ancienneté dans la banque », exprimée en mois?
End of explanation
"""


visaprem["TAVEP"].hist(bins=20)
plt.show()

visaprem["QSMOY"].hist(bins=20)
plt.show()

import scipy.stats as stats
stats.probplot(visaprem["QSMOY"], dist="norm", plot=plt)

"""
Explanation: Q Que dire de la distribution de la variable ci-dessous? Quelle transformaiton proposer?
End of explanation
"""


visaprem["PCSPQ"].value_counts()

visaprem["FAMIQ"].value_counts()

"""
Explanation: Q  Quel problème pose les deux variables ci-dessous? Quelle correction proposer?
End of explanation
"""


visaprem.boxplot('QSMOY','CARVP')
plt.show()

"""
Explanation: Q Quel est le graphe ci-dessous? Les variables vous semblent-elles liées?
End of explanation
"""


from statsmodels.graphics.mosaicplot import mosaic
visaprem["SEXEQ"]=visaprem["SEXEQ"].cat.remove_unused_categories()
table=pd.crosstab(visaprem["SEXEQ"],visaprem["CARVP"])
print(table)
mosaic(table.stack())
plt.show()

"""
Explanation: La moyenne des soldes moyens sur trois mois QSMOY pose un problème mais elle semble peu discriminante, elle est conservée en l'état. Sinon une transformation par la fonction "argument sinus hyperbolique" peut être utilisée avec ce type de distribution mais ce n'est pas indispensable.
Q Que représente le graphique ci-dessous? Interprétation en quelques lignes. Ces variables semblent-elles liées ?
End of explanation
"""


table=pd.crosstab(visaprem["NTCAS"],visaprem["CARVP"])
print(table)

"""
Explanation: Q Quel problème révèle le tableau ci-dessous? Comment le régler?
End of explanation
"""


visaprem.plot('AGER','RELAT',kind='scatter')
plt.show()

"""
Explanation: Q Ce graphique représente la variable « ancienneté dans la banque », exprimée en mois, en fonction de l’âge du client en années. Quelle incohérence montre ce graphique ? Quelles en est la raison?.
End of explanation
"""


table=pd.crosstab(visaprem["NTCAS"],visaprem["ZOCNB"].isnull())
print(table)

#Transformations des variables 
## regroupements de modalités
visatrans=visaprem
FAMIQ_DIC = {"Fmar":'Fcou',"Fuli":'Fcou',"Fdiv":'Fseu','Fveu':'Fseu',
                        "Fsep":'Fseu',"Fcel":'Fseu'}
PCSPQ_DIC = {"Pagr":"Pint",'Part':"Pint","Pret":"Psan","Pinc":"Psan"}
# attention de bien gétrer le type des variables
visatrans["PCSPQ"]=pd.Categorical(visatrans["PCSPQ"].astype(str).replace(PCSPQ_DIC),ordered=False)
visatrans["FAMIQ"]=visatrans["FAMIQ"].astype(str).replace(FAMIQ_DIC)

# complétion de valeurs
visatrans["ZOCNB"].fillna(0, inplace=True)
visatrans["ZOCNB"]
visatrans = visatrans[visatrans.DMVTP.notnull()]
# Correction ancienneté relation
visatrans["RELAT"]= [x-720 if x>600 else x for x in visatrans["RELAT"]]

# log des variables de distribution dissymétrique 
def log1(x):
    return np.log(1+x)
listeVarLog=['OPGNB','MOYRV','TAVEP','ENDET','GAGET','GAGEC',
'GAGEM','QCRED','DMVTP','BOPPN','FACAN','LGAGT',
'VIEMT','XLGMT','YLVMT','ITAVC','HAVEF','JNBJD']
visatrans[listeVarLog]=log1(visatrans[listeVarLog])
visatrans["ZOCNB"]=np.sqrt(visatrans["ZOCNB"])

"""
Explanation: Q Quel problème révèle le tableau ci-dessous? Comment le résoudre?
End of explanation
"""


visatrans2 = visatrans[["SEXEQ","AGER","FAMIQ","RELAT","PCSPQ","OPGNB", "MOYRV","TAVEP", "ENDET", "GAGET","GAGEC", "GAGEM", "KVUNB","QSMOY", "QCRED", "DMVTP","BOPPN", "FACAN", "LGAGT","VIENB", "VIEMT", "UEMNB","XLGNB", "XLGMT", "YLVNB","YLVMT", "ZOCNB", "NPTAG","ITAVC", "HAVEF","JNBJD", "CARVP"]]
visatrans2.head()

"""
Explanation: Vérifier les distributions des variables transformées.
End of explanation
"""


from pandas.tools.plotting import scatter_matrix
scatter_matrix(visatrans[["AGER", "RELAT","QSMOY", "OPGNB", "MOYRV","TAVEP", "ENDET", "GAGET","GAGEC","GAGEM", "QCRED", "DMVTP","BOPPN","FACAN","LGAGT","VIENB","VIEMT","UEMNB","XLGNB","XLGMT","YLVNB","YLVMT","ZOCNB"]], alpha=0.2, figsize=(15, 15), diagonal='kde')
plt.show()

"""
Explanation: Q Comment interpréter le graphe ci-dessous?
End of explanation
"""


from sklearn.decomposition import PCA
from sklearn.preprocessing import scale
# définition de la commande
pca = PCA()
# Sélection des variables quantitatives
dat=visatrans[["AGER","RELAT","KVUNB", "OPGNB", "MOYRV","TAVEP","ENDET","GAGET","GAGEC","GAGEM","QCRED","DMVTP","BOPPN","FACAN","LGAGT","VIEMT","XLGMT","YLVMT","ITAVC","HAVEF","JNBJD","ZOCNB"]]
# réduction
data = pd.DataFrame(scale(dat),columns=dat.columns)
# composantes principales
C = pca.fit(data).transform(data)

"""
Explanation: <FONT COLOR="Red">Épisode 2 ACP</font>
Analyse en composantes principales
Cette phase de l'analyse permet de mieux comprendre la structure de corrélation des variables afin de d'appréhender ce que seront les grandes classes de comportement des clients.
Q L'ACP calculée ci-dessous est-elle réduite ? Pourquoi?
End of explanation
"""


# Eboulis des valeurs propres
plt.figure()
plt.plot(pca.explained_variance_ratio_)
plt.show()

"""
Explanation: Choix de dimension
End of explanation
"""


# Diagrammes boîte des composantes principales
plt.figure()
plt.boxplot(C[:,0:20])
plt.show()

"""
Explanation: Q Que représente le graphe ci-dessous? Quelle information en tirer?
End of explanation
"""


plt.figure(figsize=(10,8))
for i, j, nom in zip(C[:,0], C[:,1], visatrans['CARVP']):
    color = "red" if nom == "Coui" else "blue"
    plt.text(i, j, nom, color=color)
plt.axis((-6,7.5,-5,6))  
plt.show()

"""
Explanation: Représentation des individus
Q Quel est le graphe ci-dessous? Quelle information en retenir?
End of explanation
"""


# coordonnées des variables
coord1=pca.components_[0]*np.sqrt(pca.explained_variance_[0])
coord2=pca.components_[1]*np.sqrt(pca.explained_variance_[1])
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(1, 1, 1)
for i, j, nom in zip(coord1,coord2, data.columns):
    plt.text(i, j, nom)
    plt.arrow(0,0,i,j,color='r')
plt.axis((-1.2,1.2,-1.2,1.2))
# cercle
c=plt.Circle((0,0), radius=1, color='b', fill=False)
ax.add_patch(c)
plt.show()

"""
Explanation: Variables et cercle des corrélations
Q Que représent le graphe ci-dessous? Donner en une ligne une interprétation de l'axe 1 puis de l'axe2.
End of explanation
"""


# Stratégie utilisée pour aider à l'interprétation du plan principal 
# lorsque le nombre de variables est important
from scipy.cluster.hierarchy import dendrogram, linkage
Z = linkage(data.T, 'ward')
plt.figure(figsize=(15, 8))
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Variable')
plt.ylabel('Distance')
dendrogram(Z,leaf_font_size=8.,labels=data.columns)
plt.show()

"""
Explanation: Classification des variables
Q Les classes de variables sont-elles cohérentes avec l'interprétataion des axes?
End of explanation
"""


#Recodage des modalités 
import random
visapremv=visatrans2

visapremv["FAMIQ"].value_counts()

# Recodages aléatoire des Finc
def rep_fami(x):
    if random.random()<0.45:
        x="Fseu"
    else:
        x="Fcou"
    return x
visapremv["FAMIQ"]=[x if x!="Finc" else rep_fami(x) for x in visapremv["FAMIQ"]]

visapremv["FAMIQ"].value_counts()

# attention au type
visapremv["FAMIQ"]=visapremv["FAMIQ"].astype('category')

kvunbq = ["K0" if x in [0,1] else "K1" for x in visapremv["KVUNB"] ]
visapremv["KVUNBQ"]=pd.Categorical(kvunbq,ordered=False)

vienbq = ["V0" if x==0 else "V1" for x in visapremv["VIENB"]]
visapremv["VIENBQ"]=pd.Categorical(vienbq,ordered=False)

uemnbq = ["U0" if x==0 else "U1" if x==1 else "U2" for x in visapremv["UEMNB"] ]
visapremv["UEMNBQ"]=pd.Categorical(uemnbq,ordered=False)

xlgnbq = ["X0" if x==0 else "X1" if x==1 else "X2" for x in visapremv["XLGNB"] ]
visapremv["XLGNBQ"]=pd.Categorical(xlgnbq,ordered=False)

ylvnbq = ["Y0" if x==0 else "Y1" if x==1 else "Y2" for x in visapremv["YLVNB"] ]
visapremv["YLVNBQ"]=pd.Categorical(ylvnbq,ordered=False)

zocnbq = ["Z0" if x ==0 else "Z1" for x in visapremv["ZOCNB"] ]
visapremv["ZOCNBQ"]=pd.Categorical(zocnbq,ordered=False)

nptagq = ["N0" if x ==0 else "N1" for x in visapremv["NPTAG"] ]
visapremv["NPTAGQ"]=pd.Categorical(nptagq,ordered=False)

jnbjdq = ["J0" if x==0 else "J1" for x in visapremv["JNBJD"] ]
visapremv["JNBJDQ"]=pd.Categorical(jnbjdq,ordered=False)

def rec(df,col_name,a,b):
    colq = [b if x>0 else a for x in df[col_name]]
    return colq

visapremv["ENDETQ"]=pd.Categorical(rec(visapremv,"ENDET","E0","E1"),ordered=False)
visapremv["GAGETQ"]=pd.Categorical(rec(visapremv,"GAGET","G0","G1"),ordered=False)
visapremv["FACANQ"]=pd.Categorical(rec(visapremv,"FACAN","F0","F1"),ordered=False)
visapremv["LGAGTQ"]=pd.Categorical(rec(visapremv,"LGAGT","L0","L1"),ordered=False)
visapremv["HAVEFQ"]=pd.Categorical(rec(visapremv,"HAVEF","H0","H1"),ordered=False)

visapremw=visapremv[["AGER","RELAT","QSMOY","OPGNB","MOYRV","TAVEP","DMVTP","BOPPN","ITAVC"]]

visapremw["AGEQ"]=pd.qcut(visapremw.AGER,3,labels=["A0","A1","A2"])
visapremw["RELATQ"]=pd.qcut(visapremw.RELAT,3,labels=["R0","R1","R2"])
visapremw["QSMOYQ"]=pd.qcut(visapremw.QSMOY,3,labels=["Q0","Q1","Q2"])
visapremw["MOYRVQ"]=pd.qcut(visapremw.MOYRV,3,labels=["M0","M1","M2"])
visapremw["TAVEPQ"]=pd.qcut(visapremw.TAVEP,3,labels=["T0","T1","T2"])
visapremw["DMVTPQ"]=pd.qcut(visapremw.DMVTP,3,labels=["D0","D1","D2"])
visapremw["BOPPNQ"]=pd.qcut(visapremw.BOPPN,3,labels=["B0","B1","B2"])
visapremw["ITAVCQ"]=pd.qcut(visapremw.ITAVC,3,labels=["I0","I1","I2"])
visapremw["OPGNBQ"]=pd.qcut(visapremw.OPGNB,2,labels=["O0","O1"])

# suppression des variables devenues inutiles
listeVarSup=["AGER","RELAT","QSMOY","MOYRV","TAVEP","DMVTP","BOPPN","ITAVC","OPGNB"]
visapremw.drop(listeVarSup,inplace=True,axis=1)

fram=[visapremv,visapremw]
visapremvw=pd.concat(fram,1)

visapremvw.head()

"""
Explanation: Pas d'épisode 3 car l'AFD n'est pas adaptée aux données.
<FONT COLOR="Red">Épisode 4 AFCM</font>
Analyse multiple des correspondances
Afin d'intégrer toutes les variables et pas seulement celles quantitatives, un recodage de ces dernières variables, permet de toutes les intégrer dans une analyse multiple des correspondances. 
Remarques
- Le nombre de classes doit être relativement restreint pour limiter les dimensions et faciliter les interprétations, 
- il est préférable de choisir, pour des variables distribuées "normalement", des classes d'effectifs égaux: les bornes sont des quantiles.
- Dans le cas des données bancaires, les variables présentant une distribution très asymétrique se résument souvent en une variable dichotomique: présence ou absence d'un produit financier donné. Dans ce dernier cas, il est inutile de conserver à la fois une variable "nombre" et une variable "montant" du même produit financier.
- Enfin, pour des raisons techniques de lisibilité des graphiques en SAS, les codes des modalités associés à une même variable commencent par la même lettre. Les programmes ci-dessous devraient être adaptés afin d'utiliser cette convention pour améliorer la lisibilité des graphiques.
Q Commenter succinctement chacune des étapes nécessaires à la transformation des variables pour réaliser une analyse multiple des correspondances.
End of explanation
"""


import mca
# variables qualitatives
visapremQ=visapremvw.select_dtypes(include=[pd.Categorical,"object"])
visapremQ.columns

visapremQ["RELATQ"].value_counts()

visapremQ[["FAMIQ","SEXEQ","PCSPQ","AGEQ","RELATQ"]].describe()

# La commande ci-dessous ne marche pas, il faut créer soi même le tableau disjonctif
# mct=mca.MCA(visapremQ, cols=["FAMIQ","SEXEQ","PCSPQ","AGEQ","RELATQ"],benzecri=False)

# Tableau disjonctif complet
D=pd.DataFrame(pd.get_dummies(visapremQ[["FAMIQ","SEXEQ","PCSPQ","AGEQ","RELATQ"]]))

# AFC
mct=mca.MCA(D,benzecri=False)

# Graphique rudimenttaire
col=[1,1,2,2,3,3,3,3,3,4,4,4,4,4,4]
plt.scatter(mct.fs_c()[:, 0],mct.fs_c()[:, 1],c=col)
for i, j, nom in zip(mct.fs_c()[:, 0],mct.fs_c()[:, 1], D.columns):
       plt.text(i, j, nom)
plt.show()

"""
Explanation: Il est classique de rechercher une première AFCM n'utilisant que les variables résumant les caractéristiques sociales (signalétique) des clients en variables principales. afin de détecter d'éventuelles incohérences. Les variables bancaires sont projetées en tant que variables supplémentaires.
End of explanation
"""


# Tableau disjonctif complet
D=pd.DataFrame(pd.get_dummies(visapremQ))
# AFCM de toutes les variables qualitatives
mca_comp=mca.MCA(D,benzecri=False)

fig = plt.figure(1, figsize=(15, 13))
plt.scatter(mca_comp.fs_c()[:, 0],mca_comp.fs_c()[:, 1])
for i, j, nom in zip(mca_comp.fs_c()[:, 0],mca_comp.fs_c()[:, 1], D.columns):
       plt.text(i, j, nom)
plt.show()

"""
Explanation: Q Commenter le graphique ci-dessous. Présente-t-il des incohérences particulières ?
L'objectif de cette exploration est de construire la représentation la plus explicite pour bien appréhender les structures des données. Les fonctions de python sont bien moins élaborées que celles des librairies de R. Il manque dans le graphe ci-dessous une utilisation habile des couleurs pour distinguer les modalités d'une même variable (même première lettre).
Q Remarquant que la plupart des modalités "0" se trouvent à gauche du graphique suivant, quelle interprétation donner du premier axe? 
Rappel: le premier caractère de chaque libellé de modalité identifie la variable.
Exo  améliorer la lisibilité du graphique ci-dessous
Q Identifier quelques variables et modalités caractéristiques et donnez une interprétation du 2ème axe.
Exo: Représenter les plans (1,3) et (2,3). Une interprétation de l'axe 3 est-elle possible?
Q Qu’est-ce qui caractérise principalement les porteurs de la carte visa premier (variable CARVP) ?
End of explanation
"""


fig = plt.figure(1, figsize=(15, 13))
# graphe des individus et des modalités
for i, j, nom in zip(mca_comp.fs_c()[:, 0],-mca_comp.fs_c()[:, 1],D.columns):
    #print(nom,i,j)
    plt.text(i, j, nom,color='g')
plt.scatter(mca_comp.fs_c()[:, 0],-mca_comp.fs_c()[:, 1],marker='1',c='g')
plt.scatter(mca_comp.fs_r()[:, 0],-mca_comp.fs_r()[:, 1],marker='+',c='b')
plt.show()

"""
Explanation: Q Le graphe ci-dessous représente également les clients dans le plan (1,2). L’AFC de quelle matrice a été calculée pour aboutir à ce résultat ?
End of explanation
"""


# Sélection des variables quantitatives
visaprems=visapremvw.select_dtypes(include=["int32","float","int64"])
# Centrage et réduction
visaprems = scale(visaprems)

# Classification d'un grand tableau par k-means puis CAH
## k-means avec 100 classes
from sklearn.cluster import *
T=k_means(visaprems,100)
poids=np.zeros((100,))
for i in T[1]:
    poids[i]=1./np.size(T[1])
np.sum(poids)

## CAH des barycentres des classes
## Calcul de la matrices des distances pondérées
def weightedL2(a,b,wa,wb):
    q = wa*a-wb*b
    return np.sqrt((q*q).sum())
dist=np.zeros((100,100))
for i in range(dist.shape[0]):
    for j in range(dist.shape[1]):
        dist[i,j]=weightedL2(T[0][i],T[0][j],poids[i],poids[j])
from scipy.cluster.hierarchy import *
Q= linkage(dist, 'ward')        
        

## Dendrogramme des barycentres des classes
plt.figure(figsize=(20, 10))
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('sample index')
plt.ylabel('distance')
dendrogram(Q,leaf_font_size=8.)
plt.show()

"""
Explanation: <FONT COLOR="Red">Épisode 5 Classification non supervisée</font>
Segmentation ou clustering des clients
L'objectif principal, lors de cette première étude des données, est de fournir une typologie ou segmentation des clients. C'est-à-dire de définir des classes les plus homogènes au regard des comportements bancaires. Les algorithmes de classification étudiés sont adaptés à des variables {\em quantitatives} ou des matrices de distances. L'intégration d'informations qualitatives peut se faire par un recodage préalable (scoring) à l'aide d'une analyse des correspondances multiples. Ce scénatio se propose donc de comparer deux approches: classification à partir des seules variables quantitatives ou classification à partir des scores issues d'une afcm. D'autres approches sont envisageables sur des variables qualitatives qui nécessitent la définition d'une distance ou dissimilarité entre individus adaptée aux variables qualitatives. Mais, nécessitant la construction de la matrice n x n des distances des individus deux à deux, elles ne sont pas adaptées aux très grands tableaux.
Sur les seules variables quantitatives
A titre d'exemple, voici comment obtenir une typologie à partir des seules variables quantitatives. La stratégie est adaptée à des gros fichiers. 
Q Quel problème peut poser la CAH (classification ascendante hiérérchique)) pour de très gros fichiers?
Q Résumer la stratégie développée ci-dessous pour pouvoir appliquer la CAH à un gros fichier. Quel est l'avantage, que cette stratégie utilise, de la CAH sur les algortihmes par réallocation dynamique de type $k-means$?
End of explanation
"""


plt.figure(figsize=(20, 10))
plt.plot(maxdists(Q)[::-1][0:10])
plt.show()

pd.DataFrame(Z[1],columns=["Classe"])

## k-means avec le nombre choisi de classes 
Z=k_means(visaprems,5)
pca=PCA()
C = pca.fit(visaprems).transform(visaprems)

## représentation des classes dans l'ACP
plt.figure(figsize=(20, 10))
plt.scatter(C[:,0], C[:,1],marker='1',c=Z[1],cmap=plt.cm.Set1)
plt.show()

"""
Explanation: Q Quel est le graphique ci-dessus? Quel est le graphique ci-dessous? Quelle conclusion en tirer?
End of explanation
"""


mca_comp=mca.MCA(D,benzecri=False)

mca_comp.fs_r().shape

"""
Explanation: Clustering sur composantes de l'AFCM
Q Préciser la démarche permettant d'obtenir une typologie des clients décrits par des variables à la fois quantitatives et qualitatives.
End of explanation
"""


# Avec n grand, il faudrait suivre la même stratégie que pour 
# l'acp: k-means puis CAH sur barycentres puis re-k-means. 
# On fait directement la CAH 
# data = (dat - dat.mean()) / dat.std()
ZZ = linkage(mca_comp.fs_r(), 'ward')
plt.figure(figsize=(15, 8))
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('sample index')
plt.ylabel('distance')
dendrogram(ZZ,leaf_font_size=8.)
plt.show()

"""
Explanation: Q Quelles sont les options disponibles de la méthode mise en oeuvre ci-dessous?
End of explanation
"""


plt.figure(figsize=(20, 10))
plt.plot(maxdists(ZZ)[::-1][0:10])
plt.show()

# k-means des composantes de l'AFCM avec 4 classes
KL=k_means(mca_comp.fs_r(),4)
fig = plt.figure(1, figsize=(15, 13))
# Représentation des classes dans les composantes de l'AFCM
for i, j, nom in zip(mca_comp.fs_c()[:, 0],-mca_comp.fs_c()[:, 1],D.columns):
    plt.text(i, j, nom,color='g')
plt.scatter(mca_comp.fs_c()[:, 0],-mca_comp.fs_c()[:, 1],marker='1',c='g')
plt.scatter(mca_comp.fs_r()[:, 0],-mca_comp.fs_r()[:, 1],marker='+',c=KL[1])
plt.show()

# Ajout de la variable Classe dans la table
visapremvw["Klasse"]=KL[1]
visapremvw["Klasse"]=pd.Categorical(visapremvw["Klasse"],ordered=False)
visapremvw["Klasse"]=visapremvw["Klasse"].cat.rename_categories(['KL2','KL1','KL0','KL3'])
visapremvw["Klasse"].value_counts()

"""
Explanation: Q Justifier le choix du nombre de classes.
End of explanation
"""


# AFCM avec la variable Classe
D=pd.get_dummies(visapremvw.select_dtypes(include=[pd.Categorical,"object"]))
mca_class=mca.MCA(D,benzecri=False)
fig = plt.figure(1, figsize=(15, 13))
# Graphe des modalités
for i, j, nom in zip(mca_class.fs_c()[:, 0],-mca_class.fs_c()[:, 1],D.columns):
    if nom=='Klasse_KL0' or nom=='Klasse_KL1' or nom=='Klasse_KL2' or nom=='Klasse_KL3':
        plt.text(i, j, nom,color='r') 
    else:    
        plt.text(i, j, nom,color='g')
plt.scatter(mca_class.fs_c()[:, 0],-mca_class.fs_c()[:, 1],marker='1',c='g')
plt.show()

"""
Explanation: Q Les classes obtenues sont représentées dans une AFCM comme les modalités KL0, KL1, KL2, KL3 d’une variable qualitative. A partir du graphe ci-dessous, résumer quelques caractéristiques des classes de client kL1, KL2, KL3.
Exo Représenter le plan (1,3). Interprétation de KL0.
End of explanation
"""


