Projet: SEGMENTATION DES CLIENTS ET DES COMPTES

Réalisation:Haral Valcourt

Présentation du projet

Ce projet répond à une demande formulée par la Direction du Marketing et des Relations Publiques de la Banque Nationale de Crédit (BNC). Son objectif est de mettre à la disposition de cette Direction une interface permettant la génération des rapports statistiques relatifs à la segmentation de la clientèle en fonction de différents critères ainsi qu’un tableau de bord. L’interface de génération des rapports est connectée directement à l’environnement de production AS400/DB2. Pour ce qui a trait au tableau de bord les données sont périodiquement extraites de l'environnement de production, traitées et modélisées dans une Base de données SQL Server puis visualisées à travers Microsoft Excel.

La demande formulée par la Direction du Marketing

image.png

L'avis de satisfaction exprimé par la Direction du Marketing

image.png

Outils technologiques

Les outils suivants sont utilisés pour l'implémentation du projet:

  • Bases de Données: AS400/DB2 et Microsoft SQL Server
  • les langages : SQL,Visual Basic 6.0, Visual Basic for Applications
  • Outil d'extraction de données: Microsoft Crystal SQL Designer
  • Outil d'analyse et de visualisation: Microsoft Excel,Seaborn et Matplotlib

Jeu de données

Le jeu de données est une extraction des données du système de production AS400/ DB2. L’extraction est effectuée à partir d’une requête SQL à travers l’outil Crystal SQL Designer de Microsoft. La requête est basée sur plusieurs fichiers de la Base de données DB2 puis le résultat est exporté au format Excel.

No description has been provided for this image

Compréhension du jeu de données

  • DMACCT: le numéro du compte du client
  • DMTYP : le type de compte
  • DMBRCH :la Branch d'ouverture du compte
  • CUSEX : le sexe du client
  • CUBDTE: la date de naissance du client
  • DMCBAL: la balance du compte
  • DMSTAT: le statut du compte
  • CUNBR: le numero du client

Les étapes de l'implémentation

Les étapes de l'implémentation sont les suivantes:

  • Importation des librairies
  • Création de la Base de Données
  • Importation des données dans MS SQL Server
  • Connexion à la Base de Données
  • Modélisation des données
  • Exploration des données
  • Connexion de MS Excel avec MS SQL Server à travers Power Query
  • Traitement des données dans MS Excel avec POWER QUERY
  • Analyse et Visualisation des données dans MS Excel avec PivotTable et PivotChart
  • Création du tableau de bord avec MS Excel

Importation des librairies

In [23]:
import pyodbc
import pandas as pd
import pandasql as ps
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
In [39]:
sns.set_context("paper", font_scale=0.9)  
from warnings import filterwarnings
filterwarnings('ignore')

Création de la Base de Données

No description has been provided for this image

Importation des données

No description has been provided for this image

Connexion à la Base de Données

In [27]:
DB = {'servername': 'DESKTOP-RUJ1AK0', 'database': 'BANQUE'}
conn = pyodbc.connect('DRIVER={SQL Server};   SERVER=' + DB['servername'] + ';  DATABASE=' + DB['database']  )
cur= conn.cursor()
print("Connexion établie")
Connexion établie
In [564]:
query = "SELECT TOP 3 * FROM COMPTE;"
df = pd.read_sql(query, conn)
df
Out[564]:
NOCOMPTE TYPE BRANCH SEXE DATENAIS BALANCE STATUT NUMERO
0 4141000226 6 1 M 1954-01-03 0.02 1 1028649
1 1610053064 3 5 M 1954-01-03 0.12 1 5253
2 410044628 3 4 M 1954-01-03 0.13 5 42087

Renommage des colonnes

In [538]:
query="EXEC sp_RENAME 'compte.DMACCT' , 'NOCOMPTE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [540]:
query="EXEC sp_RENAME 'compte.DMTYP' , 'TYPE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [542]:
query="EXEC sp_RENAME 'compte.CUSEX' , 'SEXE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [546]:
query="EXEC sp_RENAME 'compte.CUBDTE' , 'DATENAIS', 'COLUMN'  ";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [548]:
query="EXEC sp_RENAME 'compte.DMCBAL' , 'BALANCE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [550]:
query="EXEC sp_RENAME 'compte.DMSTAT' , 'STATUT', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [552]:
query="EXEC sp_RENAME 'compte.CUNBR' , 'NUMERO', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
In [556]:
query="EXEC sp_RENAME 'compte.DMBRCH' , 'BRANCH', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée

Affichage du nom des colonnes et des types de données

In [558]:
query = "select column_name,data_type from INFORMATION_SCHEMA.COLUMNS NomColonnes where TABLE_NAME='COMPTE';" 
df1 = pd.read_sql(query, conn) 
df1
Out[558]:
column_name data_type
0 NOCOMPTE nvarchar
1 TYPE int
2 BRANCH int
3 SEXE nvarchar
4 DATENAIS date
5 BALANCE float
6 STATUT int
7 NUMERO int

Modélisation des données

Ajout d'une colonne "TYPE_COMPTE" pour classifier les comptes

In [577]:
query="ALTER TABLE COMPTE ADD TYPE_COMPTE VARCHAR(25)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour la colonne "TYPE_COMPTE"

In [589]:
query="""
UPDATE COMPTE SET TYPE_COMPTE = 
			   CASE WHEN type=1 THEN 'Compte Epargne'
			        WHEN type=6 THEN 'Compte Courant'
			        WHEN type=5 THEN 'Compte de Prêt'
			        WHEN type=3 THEN 'Dépôt à terme'
			        ELSE 'Autres'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour effectuée')
Mise à jour effectuée
In [593]:
query = " select top 5 nocompte,type,type_compte from compte;" 
df = pd.read_sql(query, conn) 
df
Out[593]:
nocompte type type_compte
0 4141000226 6 Compte Courant
1 1610053064 3 Dépôt à terme
2 410044628 3 Dépôt à terme
3 2110022595 1 Compte Epargne
4 2410015269 1 Compte Epargne

Ajout d'une colonne "SEXE_CLIENT" pour classifier le sexe

In [596]:
query="ALTER TABLE COMPTE ADD SEXE_CLIENT VARCHAR(10)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour la colonne "SEXE_CLIENT"

In [599]:
query="""
UPDATE COMPTE SET SEXE_CLIENT = 
			   CASE WHEN sexe ='M' THEN 'Homme'
			        WHEN sexe ='F' THEN 'Femme'
			        ELSE 'Autres'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [603]:
query = " select top 5 nocompte, sexe ,sexe_client from compte;" 
df1 = pd.read_sql(query, conn) 
df1
Out[603]:
nocompte sexe sexe_client
0 4141000226 M Homme
1 1610053064 M Homme
2 410044628 M Homme
3 2110022595 F Femme
4 2410015269 F Femme

Ajout d'une colonne "STATUT_COMPTE" pour classifier le statut du compte

In [606]:
query="ALTER TABLE COMPTE ADD STATUT_COMPTE VARCHAR(10)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour la colonne STATUT_COMPTE

In [609]:
query="""
UPDATE COMPTE SET STATUT_COMPTE = 
			   CASE WHEN statut =1 THEN 'Ouvert'
			        WHEN statut =3 THEN 'No Débit'
                    WHEN statut =5 THEN 'Dormant'
			        WHEN statut =7 THEN 'Fermé'
			        ELSE 'Autres'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [613]:
query = " select top 5 nocompte, statut ,statut_compte from compte;" 
df1 = pd.read_sql(query, conn) 
df1
Out[613]:
nocompte statut statut_compte
0 4141000226 1 Ouvert
1 1610053064 1 Ouvert
2 410044628 5 Dormant
3 2110022595 1 Ouvert
4 2410015269 5 Dormant

Ajouter un colonne "ANNEE" pour stocker l'année de naissance des clients

In [619]:
query="ALTER TABLE COMPTE ADD ANNEE INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [622]:
query="UPDATE COMPTE SET ANNEE =YEAR(DATENAIS)" 
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [624]:
query = " select top 5 nocompte, statut ,statut_compte,annee from compte;" 
df1 = pd.read_sql(query, conn) 
df1
Out[624]:
nocompte statut statut_compte annee
0 4141000226 1 Ouvert 1954
1 1610053064 1 Ouvert 1954
2 410044628 5 Dormant 1954
3 2110022595 1 Ouvert 1954
4 2410015269 5 Dormant 1954

Ajouter un colonne "MOIS" pour stocker le mois de naissance des clients

In [627]:
query="ALTER TABLE COMPTE ADD MOIS INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [629]:
query="UPDATE COMPTE SET MOIS =MONTH(DATENAIS)" 
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [631]:
query = " select top 5 nocompte, statut ,statut_compte,mois from compte;" 
df1 = pd.read_sql(query, conn) 
df1
Out[631]:
nocompte statut statut_compte mois
0 4141000226 1 Ouvert 1
1 1610053064 1 Ouvert 1
2 410044628 5 Dormant 1
3 2110022595 1 Ouvert 1
4 2410015269 5 Dormant 1

Ajouter un colonne "JOUR" pour stocker le jour de naissance des clients

In [636]:
query="ALTER TABLE COMPTE ADD JOUR INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [638]:
query="UPDATE COMPTE SET JOUR =DAY(DATENAIS)" 
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [640]:
query = " select top 5 nocompte, statut ,statut_compte,jour from compte;" 
df1 = pd.read_sql(query, conn) 
df1
Out[640]:
nocompte statut statut_compte jour
0 4141000226 1 Ouvert 3
1 1610053064 1 Ouvert 3
2 410044628 5 Dormant 3
3 2110022595 1 Ouvert 3
4 2410015269 5 Dormant 3

Ajouter une colonne "NOMMOIS" pour stocker le mois de naissance des clients

In [643]:
query="ALTER TABLE COMPTE ADD NOMMOIS VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [645]:
query="UPDATE COMPTE SET NOMMOIS =DATENAME(mm,DATENAIS)"
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée

Ajouter une colonne "NOMJOUR" pour stocker le jour de naissance des clients

In [648]:
query="ALTER TABLE COMPTE ADD NOMJOUR VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [650]:
query="UPDATE COMPTE SET NOMJOUR =DATENAME(dw,DATENAIS)"
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée

Ajouter une colonne "AGE" pour stocker l’âge des clients

In [653]:
query="ALTER TABLE COMPTE ADD AGE INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour l’âge des clients

In [657]:
query="UPDATE COMPTE SET AGE =YEAR(getdate())-YEAR(DATENAIS) "
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée

Ajouter une colonne "RANG_AGE" pour classifier l’âge des clients

In [660]:
query="ALTER TABLE COMPTE ADD RANG_AGE VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
In [662]:
query="""
UPDATE COMPTE SET RANG_AGE = 
			   CASE WHEN age <30  THEN 'Moins que 30'
			        WHEN age between 30 and 50 THEN 'Entre 30 & 50'
                    WHEN age between 50 and 70 THEN 'Entre 50 & 70'
			        WHEN age >=70 THEN 'Plus que 70'
			        ELSE 'Autres'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée

Ajouter une colonne "SUCC" pour classifier les branches

In [677]:
query="ALTER TABLE COMPTE ADD SUCC VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour la colonne "SUCC"

In [720]:
query="""
UPDATE COMPTE SET SUCC = 
			   CASE WHEN branch =1 THEN 'LGN'
			        WHEN branch =2 THEN 'GNV'
                    WHEN branch =3 THEN 'FTL'
			        WHEN branch =4 THEN 'CAY'
			        ELSE 'FDN'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée

Ajouter une colonne "ZONE" pour la gestion des zônes géographiques

In [684]:
query="ALTER TABLE COMPTE ADD ZONE VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée

Mettre à jour la colonne "ZONE"

In [722]:
query="""
UPDATE COMPTE SET ZONE = 
			   CASE WHEN branch =1 THEN 'OUEST'
			        WHEN branch =2 THEN 'NORD'
                    WHEN branch =3 THEN 'NORD'
			        WHEN branch =4 THEN 'SUD'
			        ELSE 'EST'
			   END
               commit
               """
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
In [726]:
query = " select * from compte;" 
df1 = pd.read_sql(query, conn) 
df1.head(3)
Out[726]:
NOCOMPTE TYPE BRANCH SEXE DATENAIS BALANCE STATUT NUMERO TYPE_COMPTE SEXE_CLIENT STATUT_COMPTE ANNEE MOIS JOUR NOMMOIS NOMJOUR AGE RANG_AGE SUCC ZONE
0 4141000226 6 1 M 1954-01-03 0.02 1 1028649 Compte Courant Homme Ouvert 1954 1 3 January Sunday 71 Plus que 70 LGN OUEST
1 1610053064 3 5 M 1954-01-03 0.12 1 5253 Dépôt à terme Homme Ouvert 1954 1 3 January Sunday 71 Plus que 70 FDN EST
2 410044628 3 4 M 1954-01-03 0.13 5 42087 Dépôt à terme Homme Dormant 1954 1 3 January Sunday 71 Plus que 70 CAY SUD

Exploration des données

Dans cette partie du projet on répondra aux questions suivantes à partir de requête SQL:

  • Répartition des comptes par succursale
  • Répartition des comptes par type
  • Répartition des comptes par Succursale et type
  • Répartition des comptes par zone géographique
  • Répartition des comptes par sexe
  • Répartition des comptes par statut du compte
  • Répartition des comptes par tranche d'âge
  • Répartition la balance totale des comptes par type de compte
  • Répartition la balance totale des comptes par type de compte et succursale
  • Répartition la balance totale des comptes par zône géographique
  • Répartition la balance totale des comptes par sexe et type de compte
  • Répartition la balance totale des comptes par statut et type de compte
  • Répartition la balance totale des comptes par zône et tranche d'âge
  • Répartition la balance totale par zône, succursale et type de compte
  • Répartition des comptes par sexe et année de naissance du client
  • Affichage des 5 plus grands clients par produit
  • Affichage des 5 plus grands clients par Succursale

Répartition des comptes par succursale

In [29]:
query = "SELECT SUCC,count(NOCOMPTE) as QUANTITE from COMPTE group by SUCC"
df = pd.read_sql(query, conn) 
df
Out[29]:
SUCC QUANTITE
0 LGN 11417
1 FDN 7423
2 CAY 3851
3 GNV 4143
4 FTL 10093
In [51]:
sns.set_context("paper", font_scale=0.9)  
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['SUCC'], autopct='%1.1f%%',colors = colors)
plt.title('Répartition des comptes par succursale')

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x=df["SUCC"],y=df["QUANTITE"],data=df,hue=df["SUCC"],palette="Spectral").set_title("Répartition des comptes par succursale");
plt.show()
No description has been provided for this image

Répartition des comptes par type

In [55]:
query = "SELECT TYPE_COMPTE,count(NOCOMPTE) as QUANTITE from COMPTE group by TYPE_COMPTE"
df = pd.read_sql(query, conn) 
df
Out[55]:
TYPE_COMPTE QUANTITE
0 Compte Courant 6299
1 Compte de Prêt 11435
2 Dépôt à terme 4890
3 Compte Epargne 14303
In [59]:
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['TYPE_COMPTE'], autopct='%1.1f%%',colors = colors)
plt.title('Répartition des comptes par Succursale')

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x='TYPE_COMPTE',y='QUANTITE',data=df,hue="TYPE_COMPTE",palette="Spectral").set_title("Répartition des comptes par Succursale");
plt.show()
No description has been provided for this image

Répartition des comptes par Succursale et type

In [214]:
query = """
SELECT SUCC, TYPE_COMPTE, COUNT(NUMERO) QUANTITE
from COMPTE 
group by SUCC,TYPE_COMPTE
ORDER BY SUCC
"""
df = pd.read_sql(query, conn)
df
Out[214]:
SUCC TYPE_COMPTE QUANTITE
0 CAY Compte Epargne 1550
1 CAY Compte de Prêt 990
2 CAY Dépôt à terme 40
3 CAY Compte Courant 1271
4 FDN Compte Epargne 1923
5 FDN Compte de Prêt 2278
6 FDN Compte Courant 669
7 FDN Dépôt à terme 2553
8 FTL Compte de Prêt 2518
9 FTL Dépôt à terme 338
10 FTL Compte Epargne 5945
11 FTL Compte Courant 1292
12 GNV Compte Epargne 1980
13 GNV Dépôt à terme 1055
14 GNV Compte Courant 148
15 GNV Compte de Prêt 960
16 LGN Compte Courant 2919
17 LGN Compte Epargne 2905
18 LGN Compte de Prêt 4689
19 LGN Dépôt à terme 904
In [226]:
plt.figure(figsize = (12,4))
sns.set_style("white")
sns.barplot(x=df.SUCC,y=df.QUANTITE,data=df,hue="TYPE_COMPTE",palette="pastel").set_title("Répartition des comptes par Succursale et type");
plt.xlabel("Succursales")
plt.ylabel("Nombre de compte")
Out[226]:
Text(0, 0.5, 'Nombre de compte')
No description has been provided for this image

Répartition de la balance des comptes par succursale et type

In [231]:
query = """
SELECT SUCC ,TYPE_COMPTE, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION 
from COMPTE 
group by SUCC,TYPE_COMPTE
ORDER BY SUCC
"""
df = pd.read_sql(query, conn)
df
Out[231]:
SUCC TYPE_COMPTE TOTAL_MILLION
0 CAY Compte Epargne 120.87
1 CAY Compte de Prêt 28.48
2 CAY Dépôt à terme 14.81
3 CAY Compte Courant 282.23
4 FDN Compte Epargne 395.05
5 FDN Compte de Prêt 379.09
6 FDN Compte Courant 238.48
7 FDN Dépôt à terme 781.03
8 FTL Compte de Prêt 202.74
9 FTL Dépôt à terme 147.06
10 FTL Compte Epargne 532.21
11 FTL Compte Courant 268.60
12 GNV Compte Epargne 123.18
13 GNV Dépôt à terme 161.50
14 GNV Compte Courant 44.98
15 GNV Compte de Prêt 23.52
16 LGN Compte Courant 992.80
17 LGN Compte Epargne 337.44
18 LGN Compte de Prêt 1448.00
19 LGN Dépôt à terme 501.25
In [245]:
plt.figure(figsize = (12,4))
sns.barplot(x=df.SUCC,y=df.TOTAL_MILLION,data=df,hue="TYPE_COMPTE",palette="Spectral" , estimator=sum).set_title(
    "Répartition de la balance des comptes par Succursale et type de compte");
plt.xlabel("Succursales")
plt.ylabel("Montant en million")
Out[245]:
Text(0, 0.5, 'Montant en million')
No description has been provided for this image

Répartition des comptes par zone géographique

In [61]:
query = "SELECT ZONE,count(NOCOMPTE) as QUANTITE from COMPTE group by ZONE"
df = pd.read_sql(query, conn) 
df
Out[61]:
ZONE QUANTITE
0 SUD 3851
1 NORD 14236
2 OUEST 11417
3 EST 7423
In [63]:
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['ZONE'], autopct='%1.1f%%',colors = colors)
plt.title('Répartition des comptes par zone')

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x='ZONE',y='QUANTITE',data=df,hue="ZONE",palette="Spectral").set_title("Répartition des comptes par zone");
plt.show()
No description has been provided for this image

Répartition des comptes par sexe

In [65]:
query = "SELECT SEXE_CLIENT,count(NOCOMPTE) as QUANTITE from COMPTE group by SEXE_CLIENT"
df = pd.read_sql(query, conn) 
df
Out[65]:
SEXE_CLIENT QUANTITE
0 Homme 16907
1 Femme 20020
In [67]:
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['SEXE_CLIENT'], autopct='%1.1f%%',colors = colors)
plt.title('Répartition des comptes par zone')

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x='SEXE_CLIENT',y='QUANTITE',data=df,hue="SEXE_CLIENT",palette="Spectral").set_title("Répartition des comptes par zone");
plt.show()
No description has been provided for this image

Répartition des comptes par statut du compte

In [69]:
query = "SELECT STATUT_COMPTE,count(NOCOMPTE) as QUANTITE from COMPTE group by STATUT_COMPTE"
df = pd.read_sql(query, conn) 
df
Out[69]:
STATUT_COMPTE QUANTITE
0 Ouvert 27760
1 Dormant 8503
2 No Débit 453
3 Fermé 211
In [71]:
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['STATUT_COMPTE'], autopct='%1.1f%%',colors = colors)
plt.title('Répartition des comptes par statut')

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x='STATUT_COMPTE',y='QUANTITE',data=df,hue="STATUT_COMPTE",palette="Spectral").set_title("Répartition des comptes par statut");
plt.show()
No description has been provided for this image

Répartition des comptes par tranche d'âge

In [73]:
query = "SELECT RANG_AGE ,count(NOCOMPTE) as QUANTITE from COMPTE group by RANG_AGE"
df = pd.read_sql(query, conn) 
df
Out[73]:
RANG_AGE QUANTITE
0 Entre 30 & 50 8756
1 Plus que 70 7233
2 Entre 50 & 70 20938
In [75]:
plt.figure(figsize=(12,4))
colors = sns.color_palette("Spectral")
plt.subplot(1,2,1)
plt.pie(df['QUANTITE'], labels=df['RANG_AGE'], autopct='%1.1f%%',colors = colors)
plt.title("Répartition des comptes par tranche d'âge")

plt.subplot(1,2,2)
sns.set_style("white")
sns.barplot(x='RANG_AGE',y='QUANTITE',data=df,hue="RANG_AGE",palette="Spectral").set_title("Répartition des comptes par tranche d'âge");
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes par zône et succursale

In [298]:
query = """
SELECT ZONE,SUCC, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION ,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by ZONE,SUCC
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[298]:
ZONE SUCC TOTAL_MILLION POURCENTAGE
0 NORD GNV 353.17 5.03
1 SUD CAY 446.39 6.36
2 NORD FTL 1150.62 16.38
3 EST FDN 1793.64 25.54
4 OUEST LGN 3279.48 46.69
In [302]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='SUCC',y='TOTAL_MILLION',data=df,hue="SUCC",palette="Spectral").set_title("Répartition la balance totale des comptes par succursale");
plt.ylabel("Montant en million")
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes par type de compte et succursale

In [306]:
query = """
SELECT TYPE_COMPTE,SUCC, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by TYPE_COMPTE,SUCC
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[306]:
TYPE_COMPTE SUCC TOTAL_MILLION POURCENTAGE
0 Dépôt à terme CAY 14.81 0.21
1 Compte de Prêt GNV 23.52 0.33
2 Compte de Prêt CAY 28.48 0.41
3 Compte Courant GNV 44.98 0.64
4 Compte Epargne CAY 120.87 1.72
5 Compte Epargne GNV 123.18 1.75
6 Dépôt à terme FTL 147.06 2.09
7 Dépôt à terme GNV 161.50 2.30
8 Compte de Prêt FTL 202.74 2.89
9 Compte Courant FDN 238.48 3.40
10 Compte Courant FTL 268.60 3.82
11 Compte Courant CAY 282.23 4.02
12 Compte Epargne LGN 337.44 4.80
13 Compte de Prêt FDN 379.09 5.40
14 Compte Epargne FDN 395.05 5.62
15 Dépôt à terme LGN 501.25 7.14
16 Compte Epargne FTL 532.21 7.58
17 Dépôt à terme FDN 781.03 11.12
18 Compte Courant LGN 992.80 14.14
19 Compte de Prêt LGN 1448.00 20.62
In [308]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='TYPE_COMPTE',y='TOTAL_MILLION',data=df,hue="SUCC",palette="Spectral").set_title(
    "Répartition la balance totale des comptes par type de compte et succursale");
plt.ylabel("Montant en million")
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes par zône géographique et type de compte

In [310]:
query = """
SELECT ZONE, TYPE_COMPTE,CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by ZONE,TYPE_COMPTE
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[310]:
ZONE TYPE_COMPTE TOTAL_MILLION POURCENTAGE
0 SUD Dépôt à terme 14.81 0.21
1 SUD Compte de Prêt 28.48 0.41
2 SUD Compte Epargne 120.87 1.72
3 NORD Compte de Prêt 226.25 3.22
4 EST Compte Courant 238.48 3.40
5 SUD Compte Courant 282.23 4.02
6 NORD Dépôt à terme 308.56 4.39
7 NORD Compte Courant 313.58 4.46
8 OUEST Compte Epargne 337.44 4.80
9 EST Compte de Prêt 379.09 5.40
10 EST Compte Epargne 395.05 5.62
11 OUEST Dépôt à terme 501.25 7.14
12 NORD Compte Epargne 655.40 9.33
13 EST Dépôt à terme 781.03 11.12
14 OUEST Compte Courant 992.80 14.14
15 OUEST Compte de Prêt 1448.00 20.62
In [312]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='ZONE',y='TOTAL_MILLION',data=df,hue="TYPE_COMPTE",palette="Spectral").set_title(
    "Répartition la balance totale des comptes par zône géographique et type de compte");
plt.ylabel("Montant en million")
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes par sexe et type de compte

In [316]:
query = """
SELECT SEXE_CLIENT,TYPE_COMPTE, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION ,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by SEXE_CLIENT,TYPE_COMPTE
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[316]:
SEXE_CLIENT TYPE_COMPTE TOTAL_MILLION POURCENTAGE
0 Femme Dépôt à terme 410.76 5.85
1 Femme Compte Courant 539.04 7.68
2 Femme Compte Epargne 544.31 7.75
3 Homme Compte de Prêt 811.30 11.55
4 Homme Compte Epargne 964.44 13.73
5 Homme Dépôt à terme 1194.88 17.01
6 Femme Compte de Prêt 1270.52 18.09
7 Homme Compte Courant 1288.05 18.34
In [318]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='SEXE_CLIENT',y='TOTAL_MILLION',data=df,hue="TYPE_COMPTE",palette="Spectral").set_title(
    "Répartition la balance totale des comptes par sexe et type de compte");
plt.ylabel("Montant en million")
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes par type de compte et statut

In [321]:
query = """
SELECT TYPE_COMPTE, STATUT_COMPTE,CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by TYPE_COMPTE,STATUT_COMPTE
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[321]:
TYPE_COMPTE STATUT_COMPTE TOTAL_MILLION POURCENTAGE
0 Compte Courant Fermé 3.41 0.05
1 Dépôt à terme No Débit 19.34 0.28
2 Compte Courant No Débit 28.27 0.40
3 Compte Epargne No Débit 46.41 0.66
4 Dépôt à terme Dormant 107.28 1.53
5 Compte Courant Dormant 196.93 2.80
6 Compte Epargne Dormant 210.42 3.00
7 Compte Epargne Ouvert 1251.92 17.83
8 Dépôt à terme Ouvert 1479.03 21.06
9 Compte Courant Ouvert 1598.49 22.76
10 Compte de Prêt Ouvert 2081.82 29.64
In [323]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='TYPE_COMPTE',y='TOTAL_MILLION',data=df,hue="STATUT_COMPTE",palette="Spectral").set_title(
    "Répartition la balance totale des comptes par type de compte et statut");
plt.ylabel("Montant en million")
plt.show()
No description has been provided for this image

Répartition la balance totale des comptes zône et tranche d'âge

In [289]:
query = """
SELECT ZONE,RANG_AGE, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by ZONE, RANG_AGE
ORDER BY TOTAL_MILLION
"""
df = pd.read_sql(query, conn)
df
Out[289]:
ZONE RANG_AGE TOTAL_MILLION POURCENTAGE
0 SUD Plus que 70 6.59 0.09
1 EST Plus que 70 6.67 0.09
2 NORD Plus que 70 15.73 0.22
3 OUEST Plus que 70 22.43 0.32
4 SUD Entre 50 & 70 64.42 0.92
5 EST Entre 50 & 70 94.06 1.34
6 NORD Entre 50 & 70 322.97 4.60
7 OUEST Entre 50 & 70 358.74 5.11
8 SUD Entre 30 & 50 375.38 5.34
9 NORD Entre 30 & 50 1165.09 16.59
10 EST Entre 30 & 50 1692.92 24.10
11 OUEST Entre 30 & 50 2898.31 41.27
In [291]:
plt.figure(figsize=(12,4))
sns.set_style("white")
sns.barplot(x='ZONE',y='TOTAL_MILLION',data=df,hue="RANG_AGE",palette="Spectral").set_title(
    "Répartition la balance totale des comptes par tranche zône et tranche d'âge");
plt.show()
No description has been provided for this image

Répartition la balance totale par zône, succursale et type de compte

In [101]:
query = """
SELECT ZONE,SUCC,TYPE_COMPTE, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION, 
CAST(SUM(BALANCE)*100/(SELECT SUM(BALANCE) FROM COMPTE) AS DECIMAL(10,2))  AS POURCENTAGE
from COMPTE group by ZONE,SUCC,TYPE_COMPTE
ORDER BY ZONE
"""
df = pd.read_sql(query, conn)
df
Out[101]:
ZONE SUCC TYPE_COMPTE TOTAL_MILLION POURCENTAGE
0 EST FDN Compte Epargne 395.05 5.62
1 EST FDN Dépôt à terme 781.03 11.12
2 EST FDN Compte de Prêt 379.09 5.40
3 EST FDN Compte Courant 238.48 3.40
4 NORD GNV Compte Epargne 123.18 1.75
5 NORD FTL Compte Courant 268.60 3.82
6 NORD FTL Compte de Prêt 202.74 2.89
7 NORD GNV Dépôt à terme 161.50 2.30
8 NORD FTL Dépôt à terme 147.06 2.09
9 NORD GNV Compte de Prêt 23.52 0.33
10 NORD FTL Compte Epargne 532.21 7.58
11 NORD GNV Compte Courant 44.98 0.64
12 OUEST LGN Dépôt à terme 501.25 7.14
13 OUEST LGN Compte Epargne 337.44 4.80
14 OUEST LGN Compte Courant 992.80 14.14
15 OUEST LGN Compte de Prêt 1448.00 20.62
16 SUD CAY Compte Epargne 120.87 1.72
17 SUD CAY Compte Courant 282.23 4.02
18 SUD CAY Dépôt à terme 14.81 0.21
19 SUD CAY Compte de Prêt 28.48 0.41

Répartition des comptes par sexe et année de naissance du client

In [103]:
query = "SELECT ANNEE,SEXE_CLIENT, COUNT(NOCOMPTE) QUANTITE from COMPTE group by ANNEE,SEXE_CLIENT ORDER BY ANNEE"
df = pd.read_sql(query, conn)
df
Out[103]:
ANNEE SEXE_CLIENT QUANTITE
0 1942 Femme 28
1 1942 Homme 44
2 1943 Homme 84
3 1943 Femme 51
4 1944 Homme 88
... ... ... ...
83 1983 Homme 432
84 1984 Homme 372
85 1984 Femme 161
86 1985 Homme 293
87 1985 Femme 64

88 rows × 3 columns

In [105]:
plt.figure(figsize=(16,4))
data=df
sns.set_style("white")
sns.barplot(x="ANNEE",y="QUANTITE",data=data,palette="Spectral",hue="SEXE_CLIENT").set_title(
    "Répartition des comptes par sexe et année de naissance du client");
plt.show()
No description has been provided for this image

Afficher les 5 plus grands clients par produit

In [107]:
query = """
	WITH CTE AS
	(
	SELECT TYPE_COMPTE,NUMERO, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
	RANK() OVER( PARTITION BY TYPE_COMPTE ORDER BY CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) DESC) AS RANG from COMPTE 
	GROUP BY TYPE_COMPTE,NUMERO)
	SELECT * FROM CTE WHERE RANG<=5 ORDER BY TYPE_COMPTE
"""

df = pd.read_sql(query, conn)
df
Out[107]:
TYPE_COMPTE NUMERO TOTAL_MILLION RANG
0 Compte Courant 387277 30.01 1
1 Compte Courant 797017 27.45 2
2 Compte Courant 810018 24.76 3
3 Compte Courant 87151 24.08 4
4 Compte Courant 412932 23.01 5
5 Compte de Prêt 89436 25.87 1
6 Compte de Prêt 89434 24.08 2
7 Compte de Prêt 89432 21.35 3
8 Compte de Prêt 89430 20.93 4
9 Compte de Prêt 89425 19.48 5
10 Compte Epargne 543318 14.45 1
11 Compte Epargne 194212 13.08 2
12 Compte Epargne 148969 12.70 3
13 Compte Epargne 928944 11.59 4
14 Compte Epargne 526328 11.32 5
15 Dépôt à terme 92507 21.95 1
16 Dépôt à terme 92617 20.00 2
17 Dépôt à terme 91673 20.00 2
18 Dépôt à terme 16081 18.68 4
19 Dépôt à terme 32159 18.11 5

Afficher les 2 plus grands clients par Succursale

In [109]:
query = """
	WITH CTE AS
	(
	SELECT SUCC,NUMERO, CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) TOTAL_MILLION,
	RANK() OVER( PARTITION BY SUCC ORDER BY CAST(SUM(BALANCE)/1000000 AS DECIMAL(10,2)) DESC) AS RANG from COMPTE 
	GROUP BY SUCC,NUMERO)
	SELECT * FROM CTE WHERE RANG<=2 ORDER BY SUCC
"""

df = pd.read_sql(query, conn)
df
Out[109]:
SUCC NUMERO TOTAL_MILLION RANG
0 CAY 84115 15.71 1
1 CAY 85865 11.18 2
2 FDN 797017 27.45 1
3 FDN 92507 21.95 2
4 FTL 810018 24.76 1
5 FTL 92617 20.00 2
6 GNV 50346 19.42 1
7 GNV 66215 13.93 2
8 LGN 387277 30.01 1
9 LGN 89436 25.87 2

Visualisation des données avec MS Excel

Connexion de MS Excel avec MS SQL Server à traver Power Query

No description has been provided for this image

Importation des données de MS SQL Server

image.png

Nettoyage des données

  • Conversion des données recuperées en table de données
  • Determiniation du type de données approprié pour chaque colonne
  • Verification de l'absence de doublon
  • verification de l'absence de valeur manquante

Modelisation des données

Ajout d'une colonne "MOIS_ABREG"

  • MOIS_ABREG=TEXT([@DATENAIS],"mmm")

Ajout d'une colonne "JOUR_ABREG"

  • JOUR_ABREG=TEXT([@DATENAIS],"ddd")

image.png

Analyse et Visualisation des données

Définition des indicateurs de performance

Les KPIs requis sont les suivants:

  • Total Comptes
  • Total comptes courants
  • Total comptes epargnes
  • total comptes de prêt
  • Total clients
  • Total Succursales
No description has been provided for this image

Définition des graphiques exigés

Les graphiques requis sont les suivants:

  • Répartition des comptes par produit
  • Répartition des comptes par groupe d’âge
  • Répartition des comptes par Succursale
  • Répartition de la balance par Succursale
  • Répartition des comptes par produit et genre
  • Répartition des comptes par produit et statut
  • Répartition des comptes par produit et zône
  • Répartition des comptes par sexe
  • Répartition des comptes par année
  • Répartition des comptes par région
  • Top cinq grands clients

Répartition des comptes par produit

image.png

Répartition des comptes par groupe d’âge

image.png

Répartition des comptes par Succursale

image.png

Répartition de la balance par Succursale

image.png

Répartition des comptes par produit et genre

image.png

Répartition des comptes par produit et statut

image.png

Répartition des comptes par produit et zône

image.png

Top cinq grands clients

image.png

Création du tableau de bord avec MS Excel

image.png

Interface de Segmentation des Clients

image.png

Fonctionnalités

  • Générer des rapports de segmentation de la clientèle selon les critères suivants
    • la nature des comptes
    • la catégorie des comptes
    • la tranche de balance des comptes
    • la Succursale des comptes
    • le statut des comptes
    • la tranche d’âge des clients
    • le sexe du client
    • le statut matrimonial des clients
    • le département d'habitation des clients
    • Le secteur d'activité des clients
    • La profession des clients
  • Générer des rapports ciblés en fonction de différents critères variables
    • La monnaie des comptes
    • La nature des comptes
    • La Succursale des comptes
    • La tranche de balance des comptes
    • La tranche d’âge des clients
  • Générer les rapports du portefeuille pour tous les types de comptes
  • Générer le rapport des grands clients pour une Succursale désignée
  • Générer le rapport de tous les grands clients de dépôt
  • Générer le rapport de tous les grands clients de placement
  • Générer le rapport des grands clients de prêt

Jeu de données

Il est important de souligner que les statistiques présentées dans cette présentation n’ont rien à voir avec la réalité. Les requêtes sont en effet paramétrées.

Rapports de segmentation selon la nature des comptes générés automatiquement

image.png

image.png

image.png

Rapports de segmentation selon la catégorie des comptes générés automatiquement

image.png

image.png

image.png