Accéder au contenu principal

Customer Lifetime Value

Dans ce tutoriel, apprenez à calculer la Customer Lifetime Value en Python.
· 11 min lire

Explorez l'IA

L’économiste italien Vilfredo Pareto énonce que 80 % des effets proviennent de 20 % des causes : c’est la règle du 80/20, ou principe de Pareto. De la même façon, 80 % du chiffre d’affaires de nombreuses entreprises proviennent de 20 % de leurs clients. Les entreprises doivent donc identifier ces clients clés et entretenir la relation avec eux pour sécuriser des revenus récurrents. Pour bâtir une relation durable, elles peuvent mettre en place des programmes de fidélité comme des remises, offres, coupons, points bonus et cadeaux.

Cibler un nouveau client coûte plus cher que fidéliser un client existant, car vous n’avez pas à consacrer autant de ressources, de temps et d’efforts pour l’acquérir. Il s’agit surtout de conserver la satisfaction des clients actuels. Les analystes mesurent précisément le coût d’acquisition client via la CLTV (Customer Lifetime Value). La CLTV indique le revenu total généré par un client sur l’ensemble de la relation. Elle aide les entreprises à se concentrer sur les clients à fort potentiel, susceptibles de générer davantage de revenus à l’avenir.

Customer Lifetime Value (CLTV)

« La Customer Lifetime Value est une valeur monétaire représentant le revenu ou le profit qu’un client apportera à l’entreprise sur toute la durée de la relation ». La CLTV met en lumière les avantages d’acquérir des clients sur le long terme plutôt que des clients à court terme. La customer lifetime value (CLV) permet de répondre aux questions commerciales essentielles pour toute entreprise :

  • Comment identifier les clients les plus rentables ?
  • Comment proposer la meilleure offre et maximiser la marge ?
  • Comment segmenter les clients rentables ?
  • Quel budget allouer à l’acquisition de clients ?

Calculer la Customer Lifetime Value

Il existe de nombreuses approches pour calculer la CLTV. Chacun peut avoir sa vision. Pour la calculer, il faut des données historiques client, ce qui ne permet pas d’estimer la valeur de nouveaux clients. Pour contourner ce problème, les analystes conçoivent des modèles de machine learning afin de prédire la CLTV des nouveaux clients. Voici quelques approches de calcul de la CLTV :

1) Additionner les profits/recettes par client sur une période donnée. Par exemple, si un client est avec vous depuis 3 ans, vous pouvez sommer tous les profits sur ces 3 ans. Vous pouvez ensuite en calculer la moyenne annuelle, semestrielle ou mensuelle. En revanche, cette méthode ne permet pas de créer un modèle prédictif pour de nouveaux clients.

2) Construire un modèle de régression pour les clients existants. Utilisez les données des six derniers mois comme variables explicatives et le revenu total sur trois ans comme variable cible, puis entraînez un modèle de régression.

3) La CLTV peut aussi être estimée avec les valeurs RFM (Récence, Fréquence, Montant). Pour plus de détails, consultez mon tutoriel.

4) À l’aide de l’équation suivante : CLTV = ((valeur moyenne de commande × fréquence d’achat)/taux d’attrition) × marge bénéficiaire.

      Customer Value = Average Order Value * Purchase Frequency
  • Valeur moyenne de commande (AOV) : c’est le ratio entre le revenu total et le nombre total de commandes. Elle représente le montant moyen dépensé par commande.

                         Average Order Value = Total Revenue / Total Number of Orders
    
  • Fréquence d’achat (PF) : c’est le ratio entre le nombre total de commandes et le nombre total de clients. Elle représente le nombre moyen de commandes par client.

                        Purchase Frequency =  Total Number of Orders / Total Number of Customers
    
  • Taux d’attrition (churn rate) : pourcentage de clients qui n’ont pas repassé commande.

  • Durée de vie client : période pendant laquelle le client passe des commandes de manière continue.

                                  Customer Lifetime=1/Churn Rate
    
  • Taux de réachat (repeat rate) : ratio entre le nombre de clients ayant passé plus d’une commande et le nombre total de clients uniques. Exemple : si vous avez 10 clients sur un mois et que 4 reviennent, le taux de réachat est de 40 %.

                                   Churn Rate= 1-Repeat Rate
    

Implémentation de la CLTV en Python (avec la formule)

Importer les bibliothèques nécessaires

#import modules
import pandas as pd # for dataframes
import matplotlib.pyplot as plt # for plotting graphs
import seaborn as sns # for plotting graphs
import datetime as dt
import numpy as np

Charger le jeu de données

Commençons par charger le jeu de données Online Retail avec la fonction de lecture CSV de pandas. Vous pouvez télécharger les données ici.

data = pd.read_excel("Online_Retail.xlsx")
data.head()
 InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry
053636585123AWHITE HANGING HEART T-LIGHT HOLDER62010-12-01 08:26:002.5517850.0United Kingdom
153636571053WHITE METAL LANTERN62010-12-01 08:26:003.3917850.0United Kingdom
253636584406BCREAM CUPID HEARTS COAT HANGER82010-12-01 08:26:002.7517850.0United Kingdom
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE62010-12-01 08:26:003.3917850.0United Kingdom
453636584029ERED WOOLLY HOTTIE WHITE HEART.62010-12-01 08:26:003.3917850.0United Kingdom

Supprimer les doublons

Il arrive que le jeu de données soit « bruité ». Vous pouvez avoir des doublons qui faussent l’analyse. En Python, pandas propose la fonction drop_duplicates(), qui supprime les enregistrements répétés.

filtered_data=data[['Country','CustomerID']].drop_duplicates()

Passons aux insights

#Top ten country's customer
filtered_data.Country.value_counts()[:10].plot(kind='bar')
<matplotlib.axes._subplots.AxesSubplot at 0x7fe677a887f0>
bar chart

Dans ce jeu de données, on observe que la majorité des clients viennent du « United Kingdom ». Vous pouvez donc filtrer les clients du Royaume-Uni.

uk_data=data[data.Country=='United Kingdom']
uk_data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 495478 entries, 0 to 541893
Data columns (total 8 columns):
InvoiceNo      495478 non-null object
StockCode      495478 non-null object
Description    494024 non-null object
Quantity       495478 non-null int64
InvoiceDate    495478 non-null datetime64[ns]
UnitPrice      495478 non-null float64
CustomerID     361878 non-null float64
Country        495478 non-null object
dtypes: datetime64[ns](1), float64(2), int64(1), object(4)
memory usage: 34.0+ MB

La fonction describe() de pandas est très pratique pour obtenir des statistiques descriptives. Elle renvoie le nombre d’observations, la moyenne, l’écart type, les valeurs minimale et maximale, ainsi que les quartiles.

uk_data.describe()
 QuantityUnitPriceCustomerID
count495478.000000495478.000000361878.000000
mean8.6054864.53242215547.871368
std227.58875699.3154381594.402590
min-80995.000000-11062.06000012346.000000
25%1.0000001.25000014194.000000
50%3.0000002.10000015514.000000
75%10.0000004.13000016931.000000
max80995.00000038970.00000018287.000000

Ici, on remarque que certains clients ont des quantités négatives, ce qui est impossible. Filtrons donc les lignes avec une quantité strictement positive.

uk_data = uk_data[(uk_data['Quantity']>0)]
uk_data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 486286 entries, 0 to 541893
Data columns (total 8 columns):
InvoiceNo      486286 non-null object
StockCode      486286 non-null object
Description    485694 non-null object
Quantity       486286 non-null int64
InvoiceDate    486286 non-null datetime64[ns]
UnitPrice      486286 non-null float64
CustomerID     354345 non-null float64
Country        486286 non-null object
dtypes: datetime64[ns](1), float64(2), int64(1), object(4)
memory usage: 33.4+ MB

Filtrer les colonnes nécessaires

Ici, nous sélectionnons les colonnes utiles au calcul de la CLTV. Cinq colonnes suffisent : CustomerID, InvoiceDate, InvoiceNo, Quantity et UnitPrice.

  • CustomerID identifie de manière unique chaque client.
  • InvoiceDate permet de calculer le nombre de jours pendant lesquels le client est resté actif.
  • InvoiceNo permet de compter le nombre de transactions (fréquence).
  • Quantity correspond au nombre d’unités achetées par transaction.
  • UnitPrice du produit aide à calculer le montant total dépensé.
uk_data=uk_data[['CustomerID','InvoiceDate','InvoiceNo','Quantity','UnitPrice']]
#Calulate total purchase
uk_data['TotalPurchase'] = uk_data['Quantity'] * uk_data['UnitPrice']

Nous allons effectuer les opérations suivantes :

  • Calculer le nombre de jours entre la date actuelle et la dernière date d’achat de chaque client.
  • Calculer le nombre de commandes par client.
  • Calculer la somme des montants dépensés par client.
uk_data_group=uk_data.groupby('CustomerID').agg({'InvoiceDate': lambda date: (date.max() - date.min()).days,
                                        'InvoiceNo': lambda num: len(num),
                                        'Quantity': lambda quant: quant.sum(),
                                        'TotalPurchase': lambda price: price.sum()})
uk_data_group.head()
 InvoiceDateInvoiceNoQuantityTotalPurchase
CustomerID    
12346.0017421577183.60
12747.036610312754196.01
12748.037245962574833719.73
12749.020919914714090.88
12820.032359722942.34

Renommer les colonnes

# Change the name of columns
uk_data_group.columns=['num_days','num_transactions','num_units','spent_money']
uk_data_group.head()
 num_daysnum_transactionsnum_unitsspent_money
CustomerID    
12346.0017421577183.60
12747.036610312754196.01
12748.037245962574833719.73
12749.020919914714090.88
12820.032359722942.34

Calculer la CLTV avec la formule suivante :

 CLTV = ((Average Order Value x Purchase Frequency)/Churn Rate) x Profit margin.

 Customer Value = Average Order Value * Purchase Frequency

1. Calculer la valeur moyenne de commande

# Average Order Value
uk_data_group['avg_order_value']=uk_data_group['spent_money']/uk_data_group['num_transactions']
uk_data_group.head()
 num_daysnum_transactionsnum_unitsspent_moneyavg_order_value
CustomerID     
12346.0017421577183.6077183.600000
12747.036610312754196.0140.737961
12748.037245962574833719.737.336756
12749.020919914714090.8820.557186
12820.032359722942.3415.971864

2. Calculer la fréquence d’achat

purchase_frequency=sum(uk_data_group['num_transactions'])/uk_data_group.shape[0]

3. Calculer le taux de réachat et le taux d’attrition

# Repeat Rate
repeat_rate=uk_data_group[uk_data_group.num_transactions > 1].shape[0]/uk_data_group.shape[0]
#Churn Rate
churn_rate=1-repeat_rate
purchase_frequency,repeat_rate,churn_rate
(90.37107880642694, 0.9818923743942872, 0.018107625605712774)

4. Calculer la marge bénéficiaire

La marge est le ratio de rentabilité le plus courant. Elle indique la part du chiffre d’affaires conservée en gain. Supposons ici une marge d’environ 5 % sur les ventes.

# Profit Margin
uk_data_group['profit_margin']=uk_data_group['spent_money']*0.05
uk_data_group.head()
 num_daysnum_transactionsnum_unitsspent_moneyavg_order_valueprofit_margin
CustomerID      
12346.0017421577183.6077183.6000003859.1800
12747.036610312754196.0140.737961209.8005
12748.037245962574833719.737.3367561685.9865
12749.020919914714090.8820.557186204.5440
12820.032359722942.3415.97186447.1170

5. Calculer la Customer Lifetime Value

# Customer Value
uk_data_group['CLV']=(uk_data_group['avg_order_value']*purchase_frequency)/churn_rate
#Customer Lifetime Value
uk_data_group['cust_lifetime_value']=uk_data_group['CLV']*uk_data_group['profit_margin']
uk_data_group.head()
 num_daysnum_transactionsnum_unitsspent_moneyavg_order_valueprofit_marginCLVcust_lifetime_value
CustomerID        
12346.0017421577183.6077183.6000003859.18003.852060e+081.486579e+12
12747.036610312754196.0140.737961209.80052.033140e+054.265538e+07
12748.037245962574833719.737.3367561685.98653.661610e+046.173424e+07
12749.020919914714090.8820.557186204.54401.025963e+052.098545e+07
12820.032359722942.3415.97186447.11707.971198e+043.755789e+06

Modèle de prédiction de la CLTV

Construisons un modèle de prédiction de la CLTV.

Ici, nous allons prédire la CLTV avec une régression linéaire.

Repartons des données chargées et filtrées ci-dessus.

uk_data.head()
 CustomerIDInvoiceDateInvoiceNoQuantityUnitPriceTotalPurchasemonth_yr
017850.02010-12-01 08:26:0053636562.5515.30Dec-2010
117850.02010-12-01 08:26:0053636563.3920.34Dec-2010
217850.02010-12-01 08:26:0053636582.7522.00Dec-2010
317850.02010-12-01 08:26:0053636563.3920.34Dec-2010
417850.02010-12-01 08:26:0053636563.3920.34Dec-2010

Extraire le mois et l’année depuis InvoiceDate.

uk_data['month_yr'] = uk_data['InvoiceDate'].apply(lambda x: x.strftime('%b-%Y'))
uk_data.head()
 CustomerIDInvoiceDateInvoiceNoQuantityUnitPriceTotalPurchasemonth_yr
017850.02010-12-01 08:26:0053636562.5515.30Dec-2010
117850.02010-12-01 08:26:0053636563.3920.34Dec-2010
217850.02010-12-01 08:26:0053636582.7522.00Dec-2010
317850.02010-12-01 08:26:0053636563.3920.34Dec-2010
417850.02010-12-01 08:26:0053636563.3920.34Dec-2010

Le tableau croisé dynamique agrège des colonnes en une table bidimensionnelle offrant une synthèse multidimensionnelle des données.

sale=uk_data.pivot_table(index=['CustomerID'],columns=['month_yr'],values='TotalPurchase',aggfunc='sum',fill_value=0).reset_index()
sale.head()
month_yrCustomerIDApr-2011Aug-2011Dec-2010Dec-2011Feb-2011Jan-2011Jul-2011Jun-2011Mar-2011May-2011Nov-2011Oct-2011Sep-2011
012346.00.000.000.000.000.0077183.600.000.000.000.000.000.000.00
112747.00.00301.70706.27438.500.00303.040.00376.30310.78771.31312.73675.380.00
212748.01100.37898.244228.131070.27389.64418.771113.272006.261179.372234.5010639.232292.846148.84
312749.00.001896.130.00763.060.000.000.000.000.00859.10572.590.000.00
412820.00.000.000.00210.350.00170.460.000.000.000.000.00343.76217.77

Faisons la somme des ventes sur l’ensemble des mois.

sale['CLV']=sale.iloc[:,2:].sum(axis=1)
sale.head()
month_yrCustomerIDApr-2011Aug-2011Dec-2010Dec-2011Feb-2011Jan-2011Jul-2011Jun-2011Mar-2011May-2011Nov-2011Oct-2011Sep-2011CLV
012346.00.000.000.000.000.0077183.600.000.000.000.000.000.000.0077183.60
112747.00.00301.70706.27438.500.00303.040.00376.30310.78771.31312.73675.380.004196.01
212748.01100.37898.244228.131070.27389.64418.771113.272006.261179.372234.5010639.232292.846148.8432619.36
312749.00.001896.130.00763.060.000.000.000.000.00859.10572.590.000.004090.88
412820.00.000.000.00210.350.00170.460.000.000.000.000.00343.76217.77942.34

Sélection des variables

Divisez les colonnes en deux types : variable cible (dépendante) et variables explicatives (features). Sélectionnez les 6 derniers mois comme variables explicatives.

X=sale[['Dec-2011','Nov-2011', 'Oct-2011','Sep-2011','Aug-2011','Jul-2011']]
y=sale[['CLV']]

Découper les données

Pour évaluer les performances du modèle, il est recommandé de diviser le jeu de données en ensemble d’entraînement et de test.

Scindons le jeu de données avec la fonction train_test_split(). Vous devez passer 3 paramètres : les features, la cible et la taille du test set. Vous pouvez aussi utiliser random_state comme graine pour la reproductibilité : chaque découpage donnera les mêmes résultats. Si random_state est None, le générateur aléatoire utilise np.random pour sélectionner les enregistrements, et le découpage variera à chaque exécution si vous ne fixez pas de graine.

#split training set and test set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,random_state=0)

Développement du modèle

Importez d’abord le module de régression linéaire et créez un objet Linear Regression. Ajustez ensuite le modèle sur le jeu d’entraînement avec fit(), puis réalisez des prédictions sur le jeu de test avec predict().

# import model
from sklearn.linear_model import LinearRegression

# instantiate
linreg = LinearRegression()

# fit the model to the training data (learn the coefficients)
linreg.fit(X_train, y_train)

# make predictions on the testing set
y_pred = linreg.predict(X_test)
# print the intercept and coefficients
print(linreg.intercept_)
print(linreg.coef_)
[208.50969617]
[[0.99880551 0.80381254 1.60226829 1.67433228 1.52860813 2.87959449]]

Qualité d’ajustement du modèle

Pour évaluer l’ajustement global du modèle linéaire, on utilise le R². Le R² est la proportion de la variance expliquée par le modèle. Sa valeur est comprise entre 0 et 1. Plus le R² est élevé, mieux c’est, car le modèle explique une plus grande part de la variance.

from sklearn import metrics

# compute the R Square for model
print("R-Square:",metrics.r2_score(y_test, y_pred))
R-Square: 0.9666074402817512

Ce modèle affiche un R² élevé (0,96) et s’ajuste donc bien aux données.

Évaluation du modèle

Pour les problèmes de régression, on utilise généralement les métriques suivantes (Ritchie Ng) :

  • Erreur absolue moyenne (MAE) : moyenne des valeurs absolues des erreurs.
  • Erreur quadratique moyenne (MSE) : moyenne des carrés des erreurs.
  • Racine de l’erreur quadratique moyenne (RMSE) : racine carrée du MSE.
# calculate MAE using scikit-learn
print("MAE:",metrics.mean_absolute_error(y_test,y_pred))

#calculate mean squared error
print("MSE",metrics.mean_squared_error(y_test, y_pred))
# compute the RMSE of our predictions
print("RMSE:",np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
MAE: 595.0282284701234
MSE 2114139.8898678957
RMSE: 1454.0082151995896

La RMSE est souvent préférée au MSE et au MAE car elle s’exprime dans les mêmes unités que la variable cible y, ce qui la rend plus interprétable.

Avantages et limites de la CLTV

La CLTV vous aide à concevoir un plan d’affaires efficace et ouvre des perspectives de montée en échelle. Elle permet de dégager des segments clients pertinents, utiles pour identifier les besoins propres à chaque segment.

La Customer Lifetime Value est un outil, pas une stratégie. La CLTV aide à repérer les clients les plus rentables, mais la manière d’en tirer profit relève de votre stratégie. Les modèles de CLTV sont parfois mal compris ou mal utilisés. Une obsession pour la CLTV peut créer des œillères : l’entreprise se focalise sur un segment « premium » et cherche à répéter les ventes, alors qu’il est aussi important d’adresser les autres clients.

Conclusion

Félicitations, vous êtes arrivé au bout de ce tutoriel !

Vous avez passé en revue de nombreux aspects de la Customer Lifetime Value : définition, méthodes de calcul, implémentation from scratch en Python, modèle de prédiction, ainsi que ses avantages et ses limites. Vous avez également revu des notions de base de pandas comme groupby et les tableaux croisés pour synthétiser des colonnes et lignes de données.

Nous espérons que vous pourrez désormais mobiliser la CLTV pour analyser vos propres jeux de données. Merci de votre lecture !

Pour aller plus loin sur l’analyse client en Python, suivez le cours Customer Analytics & A/B Testing in Python de DataCamp.

Sujets

Contenus associés

Tutoriel

Cache Python : Deux méthodes simples