
Des transactions aux tendances : prédisez quand un client est sur le point d’arrêter d’acheter
comment les mathématiques peuvent résoudre tant de problèmes dans le monde réel. Quand j’étais à l’école primaire, je ne voyais certainement pas les choses de cette façon. D’ailleurs, je n’ai jamais détesté les mathématiques, et je n’ai pas non plus eu de difficulté à apprendre la plupart des concepts de base.
Cependant, j’avoue que pour la plupart des cours au-delà de l’arithmétique classique, je pensais généralement : « Je n’utiliserai jamais ça pour quoi que ce soit dans ma vie ».
Mais c’était d’autres moments. Il n’y avait pas d’Internet, pas de science des données et les ordinateurs existaient à peine. Mais le temps passe. La vie arrive, et nous verrons le jour où nous résoudrons d’importants problèmes commerciaux avec bon vieux math!
Dans cet article, nous utiliserons la fameuse régression linéaire pour un problème différent : prédire le taux de désabonnement des clients.
Régression linéaire vs désabonnement
Le désabonnement des clients se produit rarement du jour au lendemain. Dans de nombreux cas, les clients réduiront progressivement leur fréquence d’achat avant de s’arrêter complètement. Certains appellent cela un roulement silencieux [1].
La prévision du taux de désabonnement peut être effectuée avec les modèles de désabonnement traditionnels, qui (1) nécessitent des données de désabonnement étiquetées ; (2) sont parfois complexes à expliquer ; (3) détecter le désabonnement après qu’il s’est déjà produit.
En revanche, ce projet montre une solution différente, répondant à une question plus simple :
Est-ce que ce client
ralentir les courses ?
On répond à cette question avec la logique suivante.
Nous utilisons les tendances d’achat mensuelles et la régression linéaire pour mesurer la dynamique des clients au fil du temps. Si le client continue d’augmenter ses dépenses, le montant total augmentera avec le temps, entraînant une tendance à la hausse (ou une pente positive dans une régression linéaire, si vous préférez). L’inverse est également vrai. Des montants de transactions inférieurs entraîneront une tendance à la baisse.
Décomposons la logique en petites étapes et comprenons ce que nous ferons avec les données :
- Regrouper les transactions clients par mois
- Créer un index de temps continu (par exemple 1, 2, 3…n)
- Remplissez les mois manquants avec zéro achat
- Ajuster une droite de régression linéaire
- Utilisez la pente (convertie en degrés) pour quantifier le comportement d’achat
- Évaluation : Une pente négative indique un engagement en baisse. Une pente positive indique un engagement croissant.
Eh bien, passons ensuite à la mise en œuvre.
Code
La première chose consiste à importer certains modules dans une session Python.
# Imports
import scipy.stats as stats
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
Ensuite, nous générerons des données qui simuleront certaines transactions clients. Vous pouvez consulter le code complet dans ceci Dépôt GitHub. L’ensemble de données généré apporte les colonnes customer_id, transaction_dateet total_amtet ressemblera à la photo suivante.

Nous allons maintenant créer une nouvelle colonne qui extrait le mois de la date, afin qu’il nous soit plus facile de regrouper les données ultérieurement.
# Create new column month
df['mth'] = df['transaction_date'].dt.month
# Group customers by month
df_group = (
df
.groupby(['mth','customer_id'])
['total_amt']
.sum()
.reset_index()
)
Voici le résultat.

Si l’on vérifie rapidement s’il y a des clients qui n’ont pas effectué de transaction chaque mois, on trouvera quelques cas.
Cela nous amène au point suivant. Nous devons nous assurer que si le client n’effectue pas au moins un achat par mois, nous devons alors ajouter ce mois avec une dépense de 0 $.
Créons une fonction capable de faire cela et calculons également la pente de la tendance d’achat du client.
Cette fonction semble énorme, mais nous la reviendrons en petits morceaux. Faisons ça.
- Filtrer les données d’un client donné à l’aide de Pandas
query()méthode. - Créez un groupe rapide et vérifiez si le client effectue au moins un achat par mois.
- Sinon, nous ajouterons le mois manquant avec une dépense de 0$. J’ai implémenté cela en fusionnant une trame de données temporaire avec les 12 mois et 0 $ avec les données d’origine. Après la fusion des mois, les périodes manquantes seront des lignes avec
NaNpour la colonne de données d’origine, qui peut être remplie avec 0 $. - Ensuite, nous normalisons les axes. N’oubliez pas que l’axe X est un indice de 1 à 12, mais que l’axe Y est le montant des dépenses, en milliers de dollars. Ainsi, pour éviter toute distorsion dans notre pente, nous normalisons le tout à la même échelle, entre 0 et 1. Pour cela, nous utilisons la fonction personnalisée
min_max_standardize. - Ensuite, nous pouvons tracer la régression à l’aide d’une autre fonction personnalisée.
- Ensuite nous calculerons la pente, qui est le premier résultat renvoyé par la fonction
scipy.linregress(). - Enfin, pour calculer l’angle de la pente en degrés, on fera appel aux mathématiques pures, en utilisant la notion d’arc tangent pour calculer l’angle entre l’axe X et la droite de pente de régression linéaire. En Python, utilisez simplement les fonctions
np.arctan()etnp.degrees()de numpy.

# Standardize the data
def min_max_standardize(vals):
return (vals - np.min(vals)) / (np.max(vals) - np.min(vals))
#------------
# Quick Function to plot the regression
def plot_regression(x,y, cust):
plt.scatter(x,y, color = 'gray')
plt.plot(x,
stats.linregress(x,y).slope*np.array(x) + stats.linregress(x,y).intercept,
color = 'red',
linestyle='--')
plt.suptitle("Slope of the Linear Regression [Expenses x Time]")
plt.title(f"Customer {cust} | Slope: {np.degrees(np.arctan(stats.linregress(x,y).slope)):.0f} degrees. Positive = Buying more | Negative = Buying less", size=9, color='gray')
plt.show()
#-----
def get_trend_degrees(customer, plot=False):
# Filter the data
one_customer = df.query('customer_id == @customer')
one_customer = one_customer.groupby('mth').total_amt.sum().reset_index().rename(columns={'mth':'period_idx'})
# Check if all months are in the data
cnt = one_customer.groupby('period_idx').period_idx.nunique().sum()
# If not, add 0 to the months without transactions
if cnt < 12:
# Create a DataFrame with all 12 months
all_months = pd.DataFrame({'period_idx': range(1, 13), 'total_amt': 0})
# Merge with the existing one_customer data.
# Use 'right' merge to keep all 12 months from 'all_months' and fill missing total_amt.
one_customer = pd.merge(all_months, one_customer, on='period_idx', how='left', suffixes=('_all', ''))
# Combine the total_amt columns, preferring the actual data over the 0 from all_months
one_customer['total_amt'] = one_customer['total_amt'].fillna(one_customer['total_amt_all'])
# Drop the temporary _all column if it exists
one_customer = one_customer.drop(columns=['total_amt_all'])
# Sort by period_idx to ensure correct order
one_customer = one_customer.sort_values(by='period_idx').reset_index(drop=True)
# Min Max Standardization
X = min_max_standardize(one_customer['period_idx'])
y = min_max_standardize(one_customer['total_amt'])
# Plot
if plot:
plot_regression(X,y, customer)
# Calculate slope
slope = stats.linregress(X,y)[0]
# Calculate angle degrees
angle = np.arctan(slope)
angle = np.degrees(angle)
return angle
Super. Il est temps de tester cette fonction. Prenons deux clients :
- C_014.
- Il s’agit d’un client à tendance haussière qui achète davantage au fil du temps.
# Example of strong customer
get_trend_degrees('C_014', plot=True)
Le graphique qu’il donne montre la tendance. On remarque que, même s’il y a quelques mois plus faibles entre les deux, globalement, les montants ont tendance à augmenter avec le temps.

La tendance est de 32 degrés, pointant ainsi vers le haut, indiquant une relation forte avec ce client.
- C_003.
- Il s’agit d’un client en tendance baissière qui achète moins au fil du temps.
# Example of customer stop buying
get_trend_degrees('C_003', plot=True)

Ici, les dépenses au fil des mois diminuent nettement, faisant pointer la pente de cette courbe vers le bas. La ligne est de 29 degrés négatifs, indiquant que ce client s’éloigne de la marque, il faut donc l’inciter à revenir.
Avant de partir
Eh bien, c’est terminé. Ce projet démontre une approche simple et interprétable pour détecter le déclin du comportement d’achat des clients à l’aide de la régression linéaire.
Au lieu de nous appuyer sur des modèles de désabonnement complexes, nous analysons les tendances d’achat au fil du temps pour identifier les moments où les clients se désengagent lentement.
Ce modèle simple peut nous donner une bonne idée de la direction vers laquelle le client se dirige, s’il s’agit d’une meilleure relation avec la marque ou s’il s’en éloigne.
Certes, avec d’autres données de l’entreprise, il est possible d’améliorer cette logique, d’appliquer un seuil ajusté et d’identifier rapidement les désabonnements potentiels chaque mois, sur la base des données passées.
Avant de conclure, je voudrais accorder un crédit approprié au message original qui m’a inspiré à en savoir plus sur cette implémentation. C’est un message de Matheus da Rocha que tu peux trouver ici, dans ce lien.
Enfin, découvrez-en davantage sur moi sur mon site Internet.
Dépôt GitHub
Ici vous trouvez le code complet et la documentation.
https://github.com/gurezende/Linear-Regression-Churn/tree/main
Références
[2. Numpy Arctan] https://numpy.org/doc/2.1/reference/generated/numpy.arctan.html
[3. Arctan Explanation] https://www.cuemath.com/trigonometry/arctan/
[4. Numpy Degrees] https://numpy.org/doc/2.1/reference/generated/numpy.degrees.html
[5. Scipy Lineregress] https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html



