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
L'avis de satisfaction exprimé par la Direction du Marketing
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.

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
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
sns.set_context("paper", font_scale=0.9)
from warnings import filterwarnings
filterwarnings('ignore')
Création de la Base de Données

Importation des données

Connexion à la Base de Données
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
query = "SELECT TOP 3 * FROM COMPTE;"
df = pd.read_sql(query, conn)
df
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
query="EXEC sp_RENAME 'compte.DMACCT' , 'NOCOMPTE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.DMTYP' , 'TYPE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.CUSEX' , 'SEXE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.CUBDTE' , 'DATENAIS', 'COLUMN' ";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.DMCBAL' , 'BALANCE', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.DMSTAT' , 'STATUT', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
query="EXEC sp_RENAME 'compte.CUNBR' , 'NUMERO', 'COLUMN'";
cur.execute(query)
print('Modification éffectuée')
Modification éffectuée
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
query = "select column_name,data_type from INFORMATION_SCHEMA.COLUMNS NomColonnes where TABLE_NAME='COMPTE';"
df1 = pd.read_sql(query, conn)
df1
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
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"
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
query = " select top 5 nocompte,type,type_compte from compte;"
df = pd.read_sql(query, conn)
df
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
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"
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
query = " select top 5 nocompte, sexe ,sexe_client from compte;"
df1 = pd.read_sql(query, conn)
df1
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
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
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
query = " select top 5 nocompte, statut ,statut_compte from compte;"
df1 = pd.read_sql(query, conn)
df1
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
query="ALTER TABLE COMPTE ADD ANNEE INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
query="UPDATE COMPTE SET ANNEE =YEAR(DATENAIS)"
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
query = " select top 5 nocompte, statut ,statut_compte,annee from compte;"
df1 = pd.read_sql(query, conn)
df1
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
query="ALTER TABLE COMPTE ADD MOIS INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
query="UPDATE COMPTE SET MOIS =MONTH(DATENAIS)"
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
query = " select top 5 nocompte, statut ,statut_compte,mois from compte;"
df1 = pd.read_sql(query, conn)
df1
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
query="ALTER TABLE COMPTE ADD JOUR INT";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
query="UPDATE COMPTE SET JOUR =DAY(DATENAIS)"
cur.execute(query)
print('Mise à jour éffectuée')
Mise à jour éffectuée
query = " select top 5 nocompte, statut ,statut_compte,jour from compte;"
df1 = pd.read_sql(query, conn)
df1
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
query="ALTER TABLE COMPTE ADD NOMMOIS VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
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
query="ALTER TABLE COMPTE ADD NOMJOUR VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
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
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
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
query="ALTER TABLE COMPTE ADD RANG_AGE VARCHAR(15)";
cur.execute(query)
print('Nouvelle colonne ajoutée')
Nouvelle colonne ajoutée
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
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"
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
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"
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
query = " select * from compte;"
df1 = pd.read_sql(query, conn)
df1.head(3)
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
query = "SELECT SUCC,count(NOCOMPTE) as QUANTITE from COMPTE group by SUCC"
df = pd.read_sql(query, conn)
df
SUCC | QUANTITE | |
---|---|---|
0 | LGN | 11417 |
1 | FDN | 7423 |
2 | CAY | 3851 |
3 | GNV | 4143 |
4 | FTL | 10093 |
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()
Répartition des comptes par type
query = "SELECT TYPE_COMPTE,count(NOCOMPTE) as QUANTITE from COMPTE group by TYPE_COMPTE"
df = pd.read_sql(query, conn)
df
TYPE_COMPTE | QUANTITE | |
---|---|---|
0 | Compte Courant | 6299 |
1 | Compte de Prêt | 11435 |
2 | Dépôt à terme | 4890 |
3 | Compte Epargne | 14303 |
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()
Répartition des comptes par Succursale et type
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
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 |
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")
Text(0, 0.5, 'Nombre de compte')
Répartition de la balance des comptes par succursale et type
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
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 |
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")
Text(0, 0.5, 'Montant en million')
Répartition des comptes par zone géographique
query = "SELECT ZONE,count(NOCOMPTE) as QUANTITE from COMPTE group by ZONE"
df = pd.read_sql(query, conn)
df
ZONE | QUANTITE | |
---|---|---|
0 | SUD | 3851 |
1 | NORD | 14236 |
2 | OUEST | 11417 |
3 | EST | 7423 |
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()
Répartition des comptes par sexe
query = "SELECT SEXE_CLIENT,count(NOCOMPTE) as QUANTITE from COMPTE group by SEXE_CLIENT"
df = pd.read_sql(query, conn)
df
SEXE_CLIENT | QUANTITE | |
---|---|---|
0 | Homme | 16907 |
1 | Femme | 20020 |
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()
Répartition des comptes par statut du compte
query = "SELECT STATUT_COMPTE,count(NOCOMPTE) as QUANTITE from COMPTE group by STATUT_COMPTE"
df = pd.read_sql(query, conn)
df
STATUT_COMPTE | QUANTITE | |
---|---|---|
0 | Ouvert | 27760 |
1 | Dormant | 8503 |
2 | No Débit | 453 |
3 | Fermé | 211 |
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()
Répartition des comptes par tranche d'âge
query = "SELECT RANG_AGE ,count(NOCOMPTE) as QUANTITE from COMPTE group by RANG_AGE"
df = pd.read_sql(query, conn)
df
RANG_AGE | QUANTITE | |
---|---|---|
0 | Entre 30 & 50 | 8756 |
1 | Plus que 70 | 7233 |
2 | Entre 50 & 70 | 20938 |
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()
Répartition la balance totale des comptes par zône et succursale
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
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 |
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()
Répartition la balance totale des comptes par type de compte et succursale
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
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 |
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()
Répartition la balance totale des comptes par zône géographique et type de compte
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
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 |
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()
Répartition la balance totale des comptes par sexe et type de compte
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
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 |
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()
Répartition la balance totale des comptes par type de compte et statut
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
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 |
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()
Répartition la balance totale des comptes zône et tranche d'âge
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
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 |
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()
Répartition la balance totale par zône, succursale et type de compte
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
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
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
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
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()
Afficher les 5 plus grands clients par produit
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
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
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
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
Importation des données de MS SQL Server
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")
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
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
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
Top cinq grands clients
Création du tableau de bord avec MS Excel
Interface de Segmentation des Clients
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.