Sales prediction of soda
Importations
Importation des librairies
Importation du dataset
Le dataset nous fournit directement un ensemble d'apprentissage et un ensemble de test, j'ai décidé de concaténer les deux afin de pouvoir faire par la suite de la validation croisée sur les différents algorithmes testés. Après sélection du meilleur algorithme par validation croisée, le modèle final sera créé et testé respectivement sur l'ensemble de train et de test fournis par ce dataset. L'ensemble d'apprentissage contient des données sur les ventes de soda dans certaines villes et Grèce de 2012 à 2017 tandis que celui de test contient des données sur ces mêmes villes en 2018.
Description des données
Taille des datasets
donnée de train : (7560, 12)
donnée de test : (1080, 12)
toutes nos données : (8640, 12)
L'ensemble de train possède 7560 lignes pour 12 attributs, celui de test 1080 lignes. Le dataset obtenus après concaténation possède 8640 lignes et 12 attributs
Types
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7560 entries, 0 to 7559
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 6480 non-null float64
1 date 6480 non-null object
2 city 6480 non-null object
3 lat 6429 non-null float64
4 long 6434 non-null float64
5 pop 6480 non-null float64
6 shop 6480 non-null object
7 brand 6480 non-null object
8 container 6464 non-null object
9 capacity 6465 non-null object
10 price 6480 non-null float64
11 quantity 6480 non-null float64
dtypes: float64(6), object(6)
memory usage: 708.9+ KB
None
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1080 entries, 0 to 1079
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 1080 non-null int64
1 date 1080 non-null object
2 city 1080 non-null object
3 lat 1072 non-null float64
4 long 1067 non-null float64
5 pop 1080 non-null int64
6 shop 1080 non-null object
7 brand 1080 non-null object
8 container 1077 non-null object
9 capacity 1076 non-null object
10 price 1080 non-null float64
11 quantity 1080 non-null int64
dtypes: float64(3), int64(3), object(6)
memory usage: 101.4+ KB
None
L'ensemble de train et de test possède bien le même type d'attribut et donc d'informations. Nous nous concentrerons maintenant sur le dataset df pour la suite de l'analyse et de la description de nos données.
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8640 entries, 0 to 8639
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 7560 non-null float64
1 date 7560 non-null object
2 city 7560 non-null object
3 lat 7501 non-null float64
4 long 7501 non-null float64
5 pop 7560 non-null float64
6 shop 7560 non-null object
7 brand 7560 non-null object
8 container 7541 non-null object
9 capacity 7541 non-null object
10 price 7560 non-null float64
11 quantity 7560 non-null float64
dtypes: float64(6), object(6)
memory usage: 810.1+ KB
None
La date est considérée comme un objet il faut donc le convertir en un type date, les autres types ont été bien inférés.
Conversion en un type date
Description rapide des données
On remarque une grande disparité des valeurs pour le prix et la quantité. La moyenne du prix est de 1.19, pourtant 25% des valeurs sont au dessus de 1.51 et 50% au dessus de 0.93. Pour la quantité la moyenne est de 16572 mais 50% des valeurs sont au dessus de 25312 et 25% au dessus de 37751. Pour illustrer cette disparité nous pouvons réaliser des boîtes à moustaches.
Boite à moustache des quantités
Pour expliquer cette disparité nous pouvons premièrement regarder la variation des quantités de soda vendu au cours du temps.
Vente au cours du temps
Le premier graphique nous montre la quantité de soda vendu de début 2012 à fin 2018. On remarque clairement une hausse des ventes en fonction du mois de l'année et ce de 2012 à 2018. Le deuxième graphique vient confirmer cette tendance en montrant le nombre de ventes par mois (en moyenne de 2012 à 2018), on remarque une hausse des ventes durant les mois les plus chauds de l'année. La variation des quantités de ventes de soda durant l'année s'explique donc par la variation de la température entre les différents mois de l'année.
Boite à moustache des prix
Pour le prix, cette disparité est facilement explicable. Le prix dépend du type de soda, de sa taille (en ml) et du magasin qui vend le produit.
Nous réaliserons une analyse plus détaillé des données après avoir réalisé le nettoyage de celles ci :
Nettoyage des données
Nombre de ligne où l'id n'est pas renseigné (ces lignes ne possèdes aucunes informations)
On remarque que 1080 lignes sont incorrectes et ne peuvent pas être remplacé (aucunes informations n'est renseigné dans ces 1080 lignes), ces 1080 lignes ne peuvent pas être remplacé et doivent être supprimé.
Suppression des lignes avec un champ NA
(7434, 14)
On a supprimé 1184 lignes dont les 1080 calculées précédemment, soit 104 “vraies” suppression. Si le nombre de lignes supprimées avait été plus élevé nous aurions pu remplacer certaines valeurs, ici presque toutes nos lignes sont correctes (sans compter celle sans aucunes informations) on peut donc les supprimer.
Suppression de la colonne id
La colonne id n'est pas utile et peut être supprimée.
Les différents containers
container capacity
can 330ml 2477
glass 500ml 2475
plastic 1.5lt 2482
Name: container, dtype: int64
On remarque que le type de container contient toujours la même capacité. On peut donc se passer de la colonne container (ou capacity).
Suppression de la colonne container
Numérisation de la colonne capacity
Les différentes valeurs de la colonne capacity peuvent être ordonnées selon un ordre (330ml < 500ml < 1.5lt) nous pouvons donc remplacer ces valeurs par des nombres. Ceci nous permet d'ajouter une colonne de moins lors de la binarisation des variables catégoriques.
Binarisation des variables catégoriques
Analyse des données
Corrélation entre les différents attributs
On remarque une corrélation négative entre le prix et la quantité de vente (ce qui est plutôt logique). On remarque aussi une corrélation positive entre le prix et la capacité, encore une fois ceci est logique, plus le soda est grand (en ml) plus celui-ci coûte cher.
Quantité de ventes en fonction du prix (et de la taille du soda)
Répartition des capacités des sodas
capacity
1 2477
2 2475
3 2482
Name: capacity, dtype: int64
Répartition des données par magasin et par ville
shop city
shop_1 Athens 1234
shop_2 Irakleion 1240
shop_3 Athens 1235
shop_4 Thessaloniki 1245
shop_5 Larisa 1238
shop_6 Patra 1242
Name: shop, dtype: int64
Le nombre de réponses par magasin est quasiment équivalent, le cas contraire aurait pu amener un biais. Nous remarquons aussi que deux magasins différents sont référencés pour la ville d'Athènes
Répartition des données par villes
city
Athens 2469
Irakleion 1240
Larisa 1238
Patra 1242
Thessaloniki 1245
Name: city, dtype: int64
Nous remarquons deux fois plus de réponses pour la ville d'Athènes, cela est dû au fait que deux magasins différents y sont référencés.
Nombre de réponse par ans et par magasin
shop year
shop_1 2012.0 179
2013.0 176
2014.0 179
2015.0 177
2016.0 172
2017.0 178
2018.0 173
shop_2 2012.0 175
2013.0 179
2014.0 179
2015.0 176
2016.0 175
2017.0 177
2018.0 179
shop_3 2012.0 176
2013.0 178
2014.0 176
2015.0 178
2016.0 178
2017.0 175
2018.0 174
shop_4 2012.0 179
2013.0 178
2014.0 178
2015.0 177
2016.0 176
2017.0 178
2018.0 179
shop_5 2012.0 178
2013.0 176
2014.0 177
2015.0 177
2016.0 177
2017.0 177
2018.0 176
shop_6 2012.0 177
2013.0 176
2014.0 179
2015.0 176
2016.0 180
2017.0 177
2018.0 177
Name: shop, dtype: int64
Le nombre de réponses par an et par différents magasins est homogène avec de petites variations entre les magasins et les années.
Nombre de vente total par magasin
shop
shop_1 31845994.0
shop_2 38557886.0
shop_3 25568244.0
shop_4 41754048.0
shop_5 29024308.0
shop_6 51861119.0
Name: quantity, dtype: float64
Nombre de vente par ville
Nombre de vente par type de soda
Apprentissage et test
Séparation des données en deux ensembles, nos données pour prédire et ce que l'on veut prédire
Evaluation croisée sur différents models de regression
Nous réalisons une évaluation croisée sur 5 ensembles différents (la valeur par défaut de cross_validate). Cette validation croisée nous permet de réduire le biais dû à la sélection de nos ensemble d'apprentissage et de test.
0.3908975239728387
score moyens 0.5725498795395755
temps moyens d'execution 0.029867076873779298 seconde(s)
score moyens 0.5727942520675664
temps moyens d'execution 0.02095060348510742 seconde(s)
score moyens -0.05494205751393313
temps moyens d'execution 3.9347066402435305 seconde(s)
score moyens 0.8391348302207959
temps moyens d'execution 0.05315852165222168 seconde(s)
score moyens 0.04256108762733905
temps moyens d'execution 6.009259128570557 seconde(s)
score moyens 0.9310070225141784
temps moyens d'execution 3.1562034130096435 seconde(s)
score moyens 0.8959493783494038
temps moyens d'execution 0.8880146026611329 seconde(s)
Model final
Choix de l'algorithme
L'arbre de décision, la forêt aléatoire et le gradient boosting nous donnent de bons résultats. Nous allons maintenant entraîner et tester ces algorithmes sur notre ensemble d'apprentissage et de test que nous avons importé au début du projet afin de choisir notre modèle final.
Score de l'arbre de decision : 0.8198687838901607
Score de la fôret aleatoire : 0.922902366892775
Score du gradient boosting : 0.8846342800225722
Conclusion
En conclusion, le deuxième modèle obtenu par forêt aléatoire est le plus efficace avec une précision de + ou moins 92% (ce qui confirme les résultats obtenus par validation croisée) et c'est donc celui qu'il faut choisir pour faire de la prédiction. Tous les résultats obtenus ont été réalisés sur des algorithmes dont les paramètres n'ont pas été modifiés et laissés en valeur par défaut, il aurait aussi été intéressant de tester ces différents algorithmes en faisant varier leurs paramètres.