Notebook 2 Analyse des données¶

Importation du Notebook 1

In [180]:
import pandas as pd

import numpy as np
import seaborn as sns 
import matplotlib.pyplot as plt
from scipy import stats
In [181]:
donnees2 = pd.read_csv('donnees2.csv')
donnees2
Out[181]:
id_prod date session_id client_id price categ sex birth age
0 0_1518 2022-05-20 13:21:29.043970 s_211425 c_103 4.18 0.0 f 1986 37
1 1_251 2022-02-02 07:55:19.149409 s_158752 c_8534 15.99 1.0 m 1988 35
2 0_1277 2022-06-18 15:44:33.155329 s_225667 c_6714 7.99 0.0 f 1968 55
3 2_209 2021-06-24 04:19:29.835891 s_52962 c_6941 69.99 2.0 m 2000 23
4 0_1509 2023-01-11 08:22:08.194479 s_325227 c_4232 4.99 0.0 m 1980 43
... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 13:05:06.246925 s_150195 c_8489 12.99 0.0 f 1951 72
679328 1_639 2022-03-19 16:03:23.429229 s_181434 c_4370 10.99 1.0 f 1977 46
679329 0_1425 2022-12-20 04:33:37.584749 s_314704 c_304 12.99 0.0 f 1988 35
679330 0_1994 2021-07-16 20:36:35.350579 s_63204 c_2227 4.98 0.0 m 1986 37
679331 1_523 2022-09-28 01:12:01.973763 s_274568 c_3873 23.99 1.0 m 1995 28

679332 rows × 9 columns

I- Questions Antoine (Analyse des différents indicateurs de vente)¶

a. différents indicateurs et graphiques autour du chiffre d'affaires¶

Describe de la variable "price"¶

Max, min, moyenne, median, ecart-type

In [182]:
donnees2['price'].describe(include='all')
Out[182]:
count    679332.000000
mean         17.452345
std          18.326510
min           0.620000
25%           8.870000
50%          13.990000
75%          18.990000
max         300.000000
Name: price, dtype: float64

Variance

In [183]:
donnees2['price'].var()
Out[183]:
335.86097957484003

Describe de la variable "price" par categorie¶

Max, min, moyenne, median, ecart-type

In [184]:
donnees2.groupby(by='categ')['price'].describe()
Out[184]:
count mean std min 25% 50% 75% max
categ
0.0 415680.0 10.637843 4.932238 0.62 6.29 9.99 14.45 40.99
1.0 227169.0 20.485730 7.584894 2.00 15.81 19.08 24.98 80.99
2.0 36483.0 76.207412 39.749015 30.99 53.99 62.83 73.72 300.00

Variance

In [185]:
donnees2[['price','categ']].groupby('categ').var()
Out[185]:
price
categ
0.0 24.326974
1.0 57.530610
2.0 1579.984161
In [186]:
sns.boxplot(x='categ', y='price',data=donnees2)
plt.title("Boxplot sur la variable prix par rapport à la catégorie", pad=20)
plt.show()
No description has been provided for this image

La catégorie 2 est la plus chère

Describe de la variable price par tranche d'âge¶

Définition des tranches d'âge

In [187]:
donnees2['age'].min()
Out[187]:
19
In [188]:
donnees2['age'].max()
Out[188]:
94
In [189]:
donnees2['age_cat']= pd.cut(donnees2['age'], 
                            bins= [18,30,40,50,60,70,80,90,100], 
                            labels= [']18-30]',']30-40]', ']40-50]',']50-60]',']60-70]',']70-80]',']80-90]',']90-100]'])
In [190]:
donnees2
Out[190]:
id_prod date session_id client_id price categ sex birth age age_cat
0 0_1518 2022-05-20 13:21:29.043970 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40]
1 1_251 2022-02-02 07:55:19.149409 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40]
2 0_1277 2022-06-18 15:44:33.155329 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60]
3 2_209 2021-06-24 04:19:29.835891 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30]
4 0_1509 2023-01-11 08:22:08.194479 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50]
... ... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 13:05:06.246925 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80]
679328 1_639 2022-03-19 16:03:23.429229 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50]
679329 0_1425 2022-12-20 04:33:37.584749 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40]
679330 0_1994 2021-07-16 20:36:35.350579 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40]
679331 1_523 2022-09-28 01:12:01.973763 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30]

679332 rows × 10 columns

In [191]:
donnees2[donnees2['age']==30]
Out[191]:
id_prod date session_id client_id price categ sex birth age age_cat
302 1_652 2021-06-13 02:38:07.929888 s_47897 c_5739 27.52 1.0 m 1993 30 ]18-30]
430 0_1347 2021-11-11 07:16:04.592923 s_117901 c_5365 5.99 0.0 m 1993 30 ]18-30]
454 2_46 2021-08-25 07:32:34.090052 s_80370 c_3176 41.31 2.0 m 1993 30 ]18-30]
600 1_376 2022-04-29 05:52:28.866283 s_200947 c_2503 17.49 1.0 m 1993 30 ]18-30]
642 1_277 2022-02-05 22:20:29.834375 s_160542 c_3641 25.99 1.0 m 1993 30 ]18-30]
... ... ... ... ... ... ... ... ... ... ...
678554 0_1298 2021-03-11 14:56:01.898237 s_4873 c_1559 18.32 0.0 m 1993 30 ]18-30]
678717 1_369 2022-12-31 13:27:45.093038 s_319955 c_1018 23.99 1.0 f 1993 30 ]18-30]
678907 2_185 2022-06-21 10:29:57.071599 s_227005 c_2527 43.99 2.0 f 1993 30 ]18-30]
679015 0_1600 2021-10-14 01:11:32.206966 s_104428 c_4653 13.23 0.0 m 1993 30 ]18-30]
679206 1_644 2021-12-25 02:21:15.709734 s_139569 c_6113 25.79 1.0 f 1993 30 ]18-30]

4553 rows × 10 columns

Describe

In [192]:
donnees2.groupby(by='age_cat')['price'].describe()
Out[192]:
count mean std min 25% 50% 75% max
age_cat
]18-30] 74041.0 41.394067 39.076017 0.62 14.99 25.99 57.99 300.00
]30-40] 181444.0 14.068553 11.755676 0.62 7.99 11.99 17.29 247.22
]40-50] 227765.0 13.195886 8.821735 0.62 7.45 11.99 16.99 300.00
]50-60] 105921.0 16.258741 10.970972 0.66 9.99 14.99 19.99 247.22
]60-70] 55952.0 16.793220 11.322644 0.62 10.71 15.99 20.99 236.99
]70-80] 22526.0 16.632380 10.025043 0.99 10.71 15.99 20.99 158.17
]80-90] 10775.0 16.830731 10.559323 0.62 10.73 15.99 20.99 225.17
]90-100] 908.0 16.623744 9.372838 2.35 10.79 15.99 20.99 145.99

variance

In [193]:
donnees2[['price','age_cat']].groupby('age_cat').var()
Out[193]:
price
age_cat
]18-30] 1526.935136
]30-40] 138.195924
]40-50] 77.823003
]50-60] 120.362217
]60-70] 128.202261
]70-80] 100.501486
]80-90] 111.499296
]90-100] 87.850089
In [194]:
sns.boxplot(x='age_cat', y='price',data=donnees2,showmeans=True)
plt.title("Boxplot sur la variable price par rapport à age_cat", pad=20)
plt.show()
No description has been provided for this image

La categorie 18-30 dépense le plus. On voit que leur médiane est de loin supérieur à celle des autres categories

Evolution du chiffre d'affaire (par jour puis par mois)¶

Convertion date en format yyyy-mm-dd

In [195]:
donnees2.dtypes
Out[195]:
id_prod         object
date            object
session_id      object
client_id       object
price          float64
categ          float64
sex             object
birth            int64
age              int64
age_cat       category
dtype: object
In [196]:
donnees2['date']=pd.to_datetime(donnees2['date'],format ='%Y-%m-%d')
donnees2['date']=donnees2['date'].dt.strftime('%Y-%m-%d')
donnees2['date']=pd.to_datetime(donnees2['date'],format ='%Y-%m-%d')
donnees2
Out[196]:
id_prod date session_id client_id price categ sex birth age age_cat
0 0_1518 2022-05-20 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40]
1 1_251 2022-02-02 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40]
2 0_1277 2022-06-18 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60]
3 2_209 2021-06-24 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30]
4 0_1509 2023-01-11 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50]
... ... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80]
679328 1_639 2022-03-19 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50]
679329 0_1425 2022-12-20 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40]
679330 0_1994 2021-07-16 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40]
679331 1_523 2022-09-28 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30]

679332 rows × 10 columns

Courbe évolution ca par jour

In [197]:
donnees_jour_ca = donnees2.groupby([donnees2['date'].dt.date])['price'].sum()
#donnees_jour_ca['date']= donnees2.groupby([donnees2['date'].dt.date])['price'].sum()[0]
#donnees_jour_ca['price']= donnees2.groupby([donnees2['date'].dt.date])['price'].sum()[1]

donnees_jour_ca
Out[197]:
date
2021-03-01    16575.21
2021-03-02    15496.44
2021-03-03    15198.69
2021-03-04    15196.07
2021-03-05    17471.37
                ...   
2023-02-24    15207.89
2023-02-25    15761.25
2023-02-26    16304.72
2023-02-27    19170.81
2023-02-28    18105.15
Name: price, Length: 730, dtype: float64
In [198]:
donnees_jour_ca.info()
<class 'pandas.core.series.Series'>
Index: 730 entries, 2021-03-01 to 2023-02-28
Series name: price
Non-Null Count  Dtype  
--------------  -----  
730 non-null    float64
dtypes: float64(1)
memory usage: 27.6+ KB
In [199]:
donnees3= donnees_jour_ca.reset_index(name='price')
donnees3['date']=pd.to_datetime(donnees2['date'],format ='%Y-%m-%d')
donnees3
Out[199]:
date price
0 2022-05-20 16575.21
1 2022-02-02 15496.44
2 2022-06-18 15198.69
3 2021-06-24 15196.07
4 2023-01-11 17471.37
... ... ...
725 2022-10-11 15207.89
726 2022-03-07 15761.25
727 2022-06-14 16304.72
728 2022-01-12 19170.81
729 2022-11-03 18105.15

730 rows × 2 columns

In [200]:
donnees3.dtypes
Out[200]:
date     datetime64[ns]
price           float64
dtype: object
In [201]:
df = donnees3.sort_values('date')
df
Out[201]:
date price
112 2021-03-01 15619.79
404 2021-03-02 15009.22
420 2021-03-03 17298.11
702 2021-03-05 16718.43
149 2021-03-07 15848.94
... ... ...
456 2023-02-26 15244.74
44 2023-02-26 15956.47
507 2023-02-27 17017.96
636 2023-02-28 15794.71
364 2023-02-28 18868.26

730 rows × 2 columns

In [202]:
plt.figure(figsize=(18,8))
plt.plot(df['date'],df['price'],marker='o', linestyle='--', color='blue')
plt.title("Evolution du chiffre d'affaire par jour", fontname='Arial',fontsize=30)
plt.xlabel("jour", fontname='Arial', fontsize=18)
plt.ylabel("chiffre d'affaire produit en milliers d'euros", fontname='Arial', fontsize=18)
plt.show()
No description has been provided for this image

evolution du ca par mois

In [203]:
df1= donnees2.set_index(donnees2.date)
df1['date']= pd.to_datetime(df1['date'])
df1
Out[203]:
id_prod date session_id client_id price categ sex birth age age_cat
date
2022-05-20 0_1518 2022-05-20 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40]
2022-02-02 1_251 2022-02-02 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40]
2022-06-18 0_1277 2022-06-18 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60]
2021-06-24 2_209 2021-06-24 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30]
2023-01-11 0_1509 2023-01-11 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50]
... ... ... ... ... ... ... ... ... ... ...
2022-01-15 0_1551 2022-01-15 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80]
2022-03-19 1_639 2022-03-19 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50]
2022-12-20 0_1425 2022-12-20 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40]
2021-07-16 0_1994 2021-07-16 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40]
2022-09-28 1_523 2022-09-28 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30]

679332 rows × 10 columns

In [204]:
donnees4= df1.groupby(pd.Grouper(freq="M"))["price"].sum().reset_index()
donnees4
Out[204]:
date price
0 2021-03-31 482530.52
1 2021-04-30 476249.16
2 2021-05-31 493023.39
3 2021-06-30 484158.49
4 2021-07-31 482875.36
5 2021-08-31 482374.70
6 2021-09-30 507360.56
7 2021-10-31 320868.67
8 2021-11-30 516267.63
9 2021-12-31 525987.21
10 2022-01-31 525388.94
11 2022-02-28 535681.39
12 2022-03-31 515566.42
13 2022-04-30 493138.80
14 2022-05-31 517292.44
15 2022-06-30 496086.05
16 2022-07-31 510903.00
17 2022-08-31 506547.19
18 2022-09-30 494204.44
19 2022-10-31 508017.67
20 2022-11-30 496774.83
21 2022-12-31 510279.44
22 2023-01-31 517610.48
23 2023-02-28 456749.69
In [205]:
plt.figure(figsize=(18,8))
plt.plot(donnees4['date'],donnees4['price'],marker='o', linestyle='--', color='purple')
plt.title("Evolution du chiffre d'affaire par mois", fontname='Arial',fontsize=30)
plt.xlabel("mois", fontname='Arial', fontsize=18)
plt.ylabel("chiffre d'affaire produit en milliers d'euros", fontname='Arial', fontsize=18)
plt.show()
No description has been provided for this image

chute du CA au mois de nov 2021. Debut de chute en mars 2023

Graphique avec la moyenne mobile de la variable price¶

In [129]:
price = df1['price']
price
Out[129]:
date
2022-05-20     4.18
2022-02-02    15.99
2022-06-18     7.99
2021-06-24    69.99
2023-01-11     4.99
              ...  
2022-01-15    12.99
2022-03-19    10.99
2022-12-20    12.99
2021-07-16     4.98
2022-09-28    23.99
Name: price, Length: 679332, dtype: float64

affichage de l'evolution du prix par jour puis par semaine puis par mois

In [130]:
fig, ax = plt.subplots(3, figsize=(18,7))

price_j = price.resample('D').sum()
price_j.plot(ax=ax[0],legend=False)
ax[0].set_ylabel('Décompte journalier des prix')

price_w =  price.resample('W').sum()
price_w.plot(ax=ax[1], legend=False)
ax[1].set_ylabel('Décompte hebdo des prix');

price_m =  price.resample('M').sum()
price_m.plot(ax=ax[2], legend=False)
ax[2].set_ylabel('Décompte mois des prix');
No description has been provided for this image

confirme le commentaire precedent

decomposition en moyenne mobile de la variable price permettant d'évaluer la tendance globale

In [206]:
plt.figure(figsize=(20,12))
plt.plot(price_j)
plt.plot(price_j.rolling(30, center=True).mean()) #moyen sur 30
plt.show()
No description has been provided for this image

b. zoom sur les références¶

faire un zoom sur les références, pour voir un peu les tops et les flops, la répartition par catégorie, etc.

Produits les plus vendus

In [207]:
top_produits = donnees2.groupby('id_prod')['session_id'].count().reset_index(name='count').sort_values(['count'], ascending=False)

top_produits
Out[207]:
id_prod count
2592 1_369 2252
2645 1_417 2189
2642 1_414 2180
2734 1_498 2128
2654 1_425 2096
... ... ...
313 0_1284 1
1793 0_549 1
549 0_1498 1
1785 0_541 1
2167 0_886 1

3266 rows × 2 columns

Produit les moins vendus

In [208]:
flops_produits = donnees2.groupby('id_prod')['session_id'].count().reset_index(name='count').sort_values(['count'], ascending=True)
flops_produits
Out[208]:
id_prod count
1793 0_549 1
1327 0_2201 1
3176 2_23 1
313 0_1284 1
752 0_1683 1
... ... ...
2654 1_425 2096
2734 1_498 2128
2642 1_414 2180
2645 1_417 2189
2592 1_369 2252

3266 rows × 2 columns

par catégorie

In [209]:
data_categ = donnees2.groupby('categ').agg({"id_prod" :[np.size], "price" :[np.sum]}).reset_index()
data_categ['prop_CA']= round((data_categ['price', 'sum']/data_categ['price', 'sum'].sum())*100,2)
data_categ['prop_size']= round((data_categ['id_prod', 'size']/data_categ['id_prod', 'size'].sum())*100,2)
data_categ
Out[209]:
categ id_prod price prop_CA prop_size
size sum
0 0.0 415680 4421938.76 37.30 61.19
1 1.0 227169 4653722.69 39.25 33.44
2 2.0 36483 2780275.02 23.45 5.37

On voit que le CA le plus elevee provient de la categorie 1. tandis que le nombre de vente le plus elevee provient de la categorie 0. Tres peu de vente de la catégorie 2 bien que le CA n'est pas négligeable.

Poid des catégories en nb de vente (volume)¶

In [210]:
categ = data_categ['categ']
id_size_cat = data_categ['id_prod','size']
plt.figure(figsize=(12,5))
plt.bar(categ ,id_size_cat, width = 0.5, color = 'seagreen',  edgecolor = 'white')
plt.title('Volume des ventes par catégorie', fontsize=15)
plt.xlabel('Category', fontsize=10)
plt.ylabel('Quantity', fontsize=10)
plt.show()
No description has been provided for this image
In [211]:
# Proportion des catégories en volume
labels_categ = data_categ['categ']
colors3 = ['seagreen', 'darkgreen', 'teal']
plt.figure(figsize=(12,5))
plt.pie(data_categ['prop_size'], labels=labels_categ, autopct='%1.1f%%', colors=colors3)
plt.title('Proportion des ventes par catégorie', fontsize=15)
plt.legend()
plt.show()
No description has been provided for this image
In [212]:
#Distribution des prix par categories 
plt.figure(figsize=(12,5))
sns.boxplot(
    data=donnees2, y='categ', x='price', 
    showmeans=True, showfliers=False, orient='h', palette='Greens')
plt.title('Distribution des prix par catégorie', fontsize=15)
plt.show()
No description has been provided for this image

les produits les moins chers proviennent de la catégories 0 . Et les plus chers de la categorie 2.

c. Courbe de Lorenz¶

j’aimerais avoir quelques informations sur les profils de nos clients, et également la répartition du chiffre d'affaires entre eux, via une courbe de Lorenz.

Je calcule le CA par client

In [213]:
ca_client = donnees2.groupby('client_id')['price'].sum()
df_ca_client = ca_client.reset_index(name='price')
df_ca_client.sort_values(['price'], ascending=False)
Out[213]:
client_id price
677 c_1609 324033.35
4388 c_4958 289760.34
6337 c_6714 153658.86
2724 c_3454 113667.90
2513 c_3263 5276.87
... ... ...
4044 c_4648 11.20
1556 c_240 11.06
7889 c_8114 9.98
7918 c_8140 8.30
8151 c_8351 6.31

8600 rows × 2 columns

J'affiche le résultat via la Courbe de lorenz

In [214]:
globale = df_ca_client['price']
lorenz = np.cumsum(np.sort(globale)) / globale.sum()
lorenz = np.append([0], lorenz) # La courbe de Lorenz commence à 0
y = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
x = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
plt.plot(x,y, label ="Droite d'équirépartition")
plt.plot(np.linspace(0,1, len(lorenz)), lorenz, drawstyle='steps-post', label = 'Courbe de Lorenz')
plt.legend()
plt.show()
No description has been provided for this image

La zone entre la droite d'équirépartition et la courbe de Lorenz représente l'inégalité dans la distribution. On peut donc voir qu'ici il y a une distribution non équitable du CA entre les clients. Notons: 50% du CA est généré par 80% des clients

courbe de lorenz sur les references (=id prod)

In [215]:
ca_prod=donnees2.groupby('id_prod')['price'].sum()
df_ca_prod = ca_prod.reset_index(name='price')
df_ca_prod.sort_values(['price'], ascending=False)
Out[215]:
id_prod price
3097 2_159 94893.50
3071 2_135 69334.95
3046 2_112 65407.76
3035 2_102 60736.78
3153 2_209 56971.86
... ... ...
665 0_1601 1.99
2080 0_807 1.99
719 0_1653 1.98
313 0_1284 1.38
595 0_1539 0.99

3266 rows × 2 columns

In [216]:
globale = df_ca_prod['price']
lorenz = np.cumsum(np.sort(globale)) / globale.sum()
lorenz = np.append([0], lorenz) # La courbe de Lorenz commence à 0
y = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
x = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
plt.plot(x,y, label ="Droite d'équirépartition")
plt.plot(np.linspace(0,1, len(lorenz)), lorenz, drawstyle='steps-post', label = 'Courbe de Lorenz')
plt.legend()
plt.show()
No description has been provided for this image

plus forte inégalité. Distribution non équitable des produits par rapport au CA. Il y a 50% des produits qui représente 90% du CA

d. Information profil client¶

In [217]:
donnees2
Out[217]:
id_prod date session_id client_id price categ sex birth age age_cat
0 0_1518 2022-05-20 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40]
1 1_251 2022-02-02 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40]
2 0_1277 2022-06-18 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60]
3 2_209 2021-06-24 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30]
4 0_1509 2023-01-11 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50]
... ... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80]
679328 1_639 2022-03-19 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50]
679329 0_1425 2022-12-20 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40]
679330 0_1994 2021-07-16 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40]
679331 1_523 2022-09-28 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30]

679332 rows × 10 columns

In [218]:
client_classe_dage= donnees2.groupby('age_cat')['price'].sum()
client_classe_dage = client_classe_dage.reset_index(name='price')
client_classe_dage['prop_CA']= round((client_classe_dage['price']/client_classe_dage['price'].sum())*100,2)
client_classe_dage
Out[218]:
age_cat price prop_CA
0 ]18-30] 3064858.12 25.85
1 ]30-40] 2552654.54 21.53
2 ]40-50] 3005561.01 25.35
3 ]50-60] 1722142.06 14.53
4 ]60-70] 939614.26 7.93
5 ]70-80] 374660.99 3.16
6 ]80-90] 181351.13 1.53
7 ]90-100] 15094.36 0.13
In [219]:
labels_categ = client_classe_dage['prop_CA']
plt.figure(figsize=(12,13))
plt.pie(client_classe_dage['prop_CA'], labels=client_classe_dage['age_cat'],autopct='%1.1f%%')
plt.title('Proportion du CA par classe dage', fontsize=15)
plt.legend()
plt.show()
No description has been provided for this image

Classe d'age qui a le plus gros CA : 18-30ans

proportion CA par rapport au genre

In [220]:
client_genre= donnees2.groupby('sex')['price'].sum()
client_genre = client_genre.reset_index(name='price')
client_genre['prop_CA']= round((client_genre['price']/client_genre['price'].sum())*100,2)
client_genre
Out[220]:
sex price prop_CA
0 f 5860851.96 49.43
1 m 5995084.51 50.57
In [221]:
labels_categ = client_genre['prop_CA']
plt.figure(figsize=(12,13))
plt.pie(client_genre['prop_CA'], labels=client_genre['sex'],autopct='%1.1f%%')
plt.title('Proportion du CA par rapport au genre', fontsize=15)
plt.legend()
plt.show()
No description has been provided for this image

Le CA n'est pas impacté selon le genre

II- Questions de Julie (Analyse ciblée sur les clients)¶

Le lien entre le genre d’un client et les catégories des livres achetés¶

In [222]:
sns.countplot(data=donnees2,x='categ',hue='sex')
plt.title('Le lien entre le genre d’un client et les catégories des livres achetés')
plt.show()
No description has been provided for this image
In [223]:
TabContingence = pd.crosstab(donnees2['categ'], donnees2['sex'], margins=False)
print('Table de contingence :')
print(TabContingence)
Table de contingence :
sex         f       m
categ                
0.0    206220  209460
1.0    114899  112270
2.0     17283   19200

Les categories sont independantes du genre ? (h0) On procède à un test d'independance entre les 2 variables qualitatives

In [224]:
stats.chi2_contingency(TabContingence)
Out[224]:
(147.00253568681114,
 1.1989607410166063e-32,
 2,
 array([[207066.56444861, 208613.43555139],
        [113161.81769444, 114007.18230556],
        [ 18173.61785695,  18309.38214305]]))
In [225]:
pvalue=stats.chi2_contingency(TabContingence)[1]
pvalue
Out[225]:
1.1989607410166063e-32

pvalue est inferieur à 0.5 donc H0 est fausse . Les categories sont dependantes du genre.

Le lien entre l’âge des clients et le montant total des achats¶

In [226]:
client_classe_dage
Out[226]:
age_cat price prop_CA
0 ]18-30] 3064858.12 25.85
1 ]30-40] 2552654.54 21.53
2 ]40-50] 3005561.01 25.35
3 ]50-60] 1722142.06 14.53
4 ]60-70] 939614.26 7.93
5 ]70-80] 374660.99 3.16
6 ]80-90] 181351.13 1.53
7 ]90-100] 15094.36 0.13
In [227]:
fig, ax = plt.subplots()
plt.figure(figsize=(20,15))

#bar_labels = ['red', 'blue', '_red', 'orange']
#bar_colors = ['tab:red', 'tab:blue', 'tab:red', 'tab:orange']

ax.bar(client_classe_dage['age_cat'], client_classe_dage['price'], color= ['green','yellow','red','blue','orange','pink','purple','grey'])

ax.set_ylabel('montant total')
ax.set_title('Montant total pour chaque catégorie dage')

plt.show()
No description has been provided for this image
<Figure size 2000x1500 with 0 Axes>

la classe ]18-30] apporte le plus gros CA vu que le montant total d'achat pour cette categorie est la plus haute

In [228]:
client_ca=donnees2.pivot_table(
    index='client_id', values='price',
    aggfunc='sum').reset_index().rename(
    columns={'price': 'montant_achats'})
client_ca
Out[228]:
client_id montant_achats
0 c_1 558.18
1 c_10 1353.60
2 c_100 254.85
3 c_1000 2261.89
4 c_1001 1812.86
... ... ...
8595 c_995 189.41
8596 c_996 1625.58
8597 c_997 1490.01
8598 c_998 2779.88
8599 c_999 701.40

8600 rows × 2 columns

In [229]:
df2 = donnees2.merge(client_ca,on='client_id', how='left')
df2.sample(3)
Out[229]:
id_prod date session_id client_id price categ sex birth age age_cat montant_achats
353043 0_2038 2022-11-09 s_295002 c_605 4.39 0.0 m 1991 32 ]30-40] 3971.93
152375 0_999 2021-09-16 s_90932 c_1611 9.99 0.0 m 1981 42 ]40-50] 2758.27
163708 0_1328 2021-04-30 s_28047 c_6881 8.52 0.0 m 1980 43 ]40-50] 3088.84
In [230]:
plt.figure(figsize=(8, 4))
sns.boxplot(data=df2, y='age_cat', x='montant_achats', showfliers=False)
plt.title('Montant d\'achat par age')
plt.show()
No description has been provided for this image

On déduis que la classe ]40-50] est celle qui contient les clients qui dépensent le plus cher. Bien que les clients agés entre ]40-50] ne soient pas aussi nombreux que la classe ]18-30]

In [231]:
plt.figure(figsize=(8, 4))
sns.scatterplot(data=df2.sample(200), x='age', y='montant_achats', hue='age_cat')
plt.ylim([0, 5000])
plt.title('Distribution des prix par classe d\'âge')
plt.show()
No description has been provided for this image

H0: L'age n'est pas corrélé au montant d'achat Ha: Les 2 variables sont corrélées

In [232]:
stats.pearsonr(df2['age'], df2['montant_achats'])
Out[232]:
PearsonRResult(statistic=-0.04999539338547815, pvalue=0.0)

Une negative correlation indique 2 variables sont dans opposite directions. La valeur de p est inférieure à 0,05, on rejete l'hypothèse nulle. l’âge des clients et le montant total des achats sont corrélées.

Le lien entre l’âge des clients et la fréquence d’achat¶

In [233]:
client_frq=donnees2.pivot_table(
    index='client_id', values='session_id',
    aggfunc='count').reset_index().rename(
    columns={'session_id': 'freq_achats'})
client_frq
Out[233]:
client_id freq_achats
0 c_1 39
1 c_10 58
2 c_100 8
3 c_1000 125
4 c_1001 102
... ... ...
8595 c_995 14
8596 c_996 95
8597 c_997 59
8598 c_998 53
8599 c_999 46

8600 rows × 2 columns

In [234]:
client_age= donnees2[['client_id','age_cat']]
client_age
Out[234]:
client_id age_cat
0 c_103 ]30-40]
1 c_8534 ]30-40]
2 c_6714 ]50-60]
3 c_6941 ]18-30]
4 c_4232 ]40-50]
... ... ...
679327 c_8489 ]70-80]
679328 c_4370 ]40-50]
679329 c_304 ]30-40]
679330 c_2227 ]30-40]
679331 c_3873 ]18-30]

679332 rows × 2 columns

In [235]:
client_age.value_counts(subset=['client_id'])
Out[235]:
client_id
c_1609       25488
c_6714        9187
c_3454        6773
c_4958        5195
c_3263         403
             ...  
c_240            1
c_5962           1
c_8351           1
c_4478           1
c_6292           1
Length: 8600, dtype: int64
In [236]:
client_age.drop_duplicates(subset=['client_id'],inplace=True)
client_age
C:\Users\User\AppData\Local\Temp\ipykernel_18096\1785311510.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  client_age.drop_duplicates(subset=['client_id'],inplace=True)
Out[236]:
client_id age_cat
0 c_103 ]30-40]
1 c_8534 ]30-40]
2 c_6714 ]50-60]
3 c_6941 ]18-30]
4 c_4232 ]40-50]
... ... ...
542530 c_5401 ]30-40]
566887 c_3615 ]18-30]
567963 c_8114 ]60-70]
577591 c_240 ]18-30]
600335 c_305 ]18-30]

8600 rows × 2 columns

In [237]:
frq_age= client_frq.merge(client_age,on='client_id', how='outer')
In [238]:
frq_age
Out[238]:
client_id freq_achats age_cat
0 c_1 39 ]60-70]
1 c_10 58 ]60-70]
2 c_100 8 ]30-40]
3 c_1000 125 ]50-60]
4 c_1001 102 ]40-50]
... ... ... ...
8595 c_995 14 ]60-70]
8596 c_996 95 ]50-60]
8597 c_997 59 ]18-30]
8598 c_998 53 ]18-30]
8599 c_999 46 ]50-60]

8600 rows × 3 columns

In [239]:
df3 = df2.merge(frq_age,on='client_id', how='left')
df3
Out[239]:
id_prod date session_id client_id price categ sex birth age age_cat_x montant_achats freq_achats age_cat_y
0 0_1518 2022-05-20 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40] 2288.49 195 ]30-40]
1 1_251 2022-02-02 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40] 3498.14 247 ]30-40]
2 0_1277 2022-06-18 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60] 153658.86 9187 ]50-60]
3 2_209 2021-06-24 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30] 886.50 17 ]18-30]
4 0_1509 2023-01-11 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50] 2381.56 168 ]40-50]
... ... ... ... ... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80] 1088.84 73 ]70-80]
679328 1_639 2022-03-19 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50] 1186.77 84 ]40-50]
679329 0_1425 2022-12-20 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40] 1692.89 117 ]30-40]
679330 0_1994 2021-07-16 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40] 3056.29 234 ]30-40]
679331 1_523 2022-09-28 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30] 2207.57 86 ]18-30]

679332 rows × 13 columns

In [240]:
plt.figure(figsize=(8, 4))
sns.boxplot(data=frq_age, y='age_cat', x='freq_achats', showfliers=False)
plt.title('Fréquence achat par age')
plt.show()
No description has been provided for this image

Plus forte frequence d'achat : ]40-50] Plus faible frequence d'achat : ]18-30] donc si on prend un client de cette catégorie, il ne revient pas souvent malgré que cette catégorie est la plus présente (en nombre)

In [241]:
plt.figure(figsize=(8, 4))
sns.scatterplot(data=frq_age.sample(150), x='age_cat', y='freq_achats', hue='age_cat')
plt.ylim([0, 1000])
plt.title('Distribution Fréquence d\'achat par classe d\'âge')
plt.show()
No description has been provided for this image

Test de Pearson. H0: L'age n'est pas corrélé au fréquence d'achat Ha: Les 2 variables sont corrélées

In [242]:
stats.pearsonr(df3['age'], df3['freq_achats'])
Out[242]:
PearsonRResult(statistic=-0.01860895810424756, pvalue=4.189586899241133e-53)

La valeur de pvalue < 0,05, onrejete l'hypothèse nulle. l’âge des clients et fréquence d'achats sont corrélés.

Le lien entre l’âge des clients et la taille du panier moyen¶

average basket= diviser CA par le nombre de commandes

In [243]:
df3['avg_b']=round (df3['montant_achats']/df3['freq_achats'],2)
df3
Out[243]:
id_prod date session_id client_id price categ sex birth age age_cat_x montant_achats freq_achats age_cat_y avg_b
0 0_1518 2022-05-20 s_211425 c_103 4.18 0.0 f 1986 37 ]30-40] 2288.49 195 ]30-40] 11.74
1 1_251 2022-02-02 s_158752 c_8534 15.99 1.0 m 1988 35 ]30-40] 3498.14 247 ]30-40] 14.16
2 0_1277 2022-06-18 s_225667 c_6714 7.99 0.0 f 1968 55 ]50-60] 153658.86 9187 ]50-60] 16.73
3 2_209 2021-06-24 s_52962 c_6941 69.99 2.0 m 2000 23 ]18-30] 886.50 17 ]18-30] 52.15
4 0_1509 2023-01-11 s_325227 c_4232 4.99 0.0 m 1980 43 ]40-50] 2381.56 168 ]40-50] 14.18
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
679327 0_1551 2022-01-15 s_150195 c_8489 12.99 0.0 f 1951 72 ]70-80] 1088.84 73 ]70-80] 14.92
679328 1_639 2022-03-19 s_181434 c_4370 10.99 1.0 f 1977 46 ]40-50] 1186.77 84 ]40-50] 14.13
679329 0_1425 2022-12-20 s_314704 c_304 12.99 0.0 f 1988 35 ]30-40] 1692.89 117 ]30-40] 14.47
679330 0_1994 2021-07-16 s_63204 c_2227 4.98 0.0 m 1986 37 ]30-40] 3056.29 234 ]30-40] 13.06
679331 1_523 2022-09-28 s_274568 c_3873 23.99 1.0 m 1995 28 ]18-30] 2207.57 86 ]18-30] 25.67

679332 rows × 14 columns

In [244]:
plt.figure(figsize=(8, 4))
sns.boxplot(data=df3, y='age_cat_y', x='avg_b', showfliers=False)
plt.title('Panier moyen par age')
plt.show()
No description has been provided for this image

Plus gros panier moyen : ]18-30]

In [245]:
plt.figure(figsize=(8, 4))
sns.scatterplot(data=df3.sample(150), x='age', y='avg_b', hue='age_cat_y')
plt.title('Distribution panier moyen par âge')
plt.show()
No description has been provided for this image

h0: L'age n'est pas corrélé au panier moyen Ha: Les 2 variables sont corrélées

In [246]:
stats.pearsonr(df3['age'], df3['avg_b'])
Out[246]:
PearsonRResult(statistic=-0.3754538317993842, pvalue=0.0)

stats pearson négative, p_value < 0.05, l'age et panier moyen sont corrélés.

le lien entre l’âge des clients et les catégories des livres achetés¶

L'analyse de la variance est utile pour vérifier la corrélation entre une qualitative et une quantitative.

In [172]:
plt.figure(figsize=(8,5))
sns.displot(data=donnees2, x='age', hue='categ', kind='kde', fill=True)
plt.title('Volume des transactions par âge et catégorie')
plt.show()
<Figure size 800x500 with 0 Axes>
No description has been provided for this image

Les 3 catégories sont consommées par toutes les classes d'âge. Mais les acheteurs de la catégorie 0 sont principalement les clients 30-50 ans, tandis que la catégorie 2 est consommée quasi exclusivement par les moins de 30 ans

In [173]:
sns.boxplot(data=donnees2, x='age', y='categ', orient='h', showfliers=False, showmeans=True)
plt.title('Distribution des âges par catégorie')
plt.show()
No description has been provided for this image
In [174]:
stats.jarque_bera(donnees2['age'])
Out[174]:
Jarque_beraResult(statistic=41537.86286418314, pvalue=0.0)

H0: L'age n'est pas corrélé aux catégoriex Ha: Les 2 variables sont corrélées

In [175]:
stats.kruskal(donnees2['age'], donnees2['categ'])
Out[175]:
KruskalResult(statistic=1054255.3347514754, pvalue=0.0)

P_value valide la corrélation entre age et catégorie