Mickaël Tits CETIC mickael.tits@cetic.be
Dans ce chapitre, nous allons explorer plus prodonfément les possibilités d'exploration de données (data mining) avec Pandas.
Chargez d'abord le dataframe préparé lors du chapitre précédent.
import pandas as pd
#Si vous venez d'exécuter le notebook précédent, vous pouvez simplement récupérer le fichier temporaire créé.
#df = pd.read_csv("houses.csv", index_col=0)
#Vous pouvez aussi récupérer une version du fichier hébergée ici:
df = pd.read_csv("https://raw.githubusercontent.com/titsitits/Python_Data_Science/master/Donn%C3%A9es/houses.csv", index_col=0)
df
address | price | rooms | surface | website | |
---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb |
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan |
#Extract city
def get_city(address):
#Le nom de la rue est la partie après le dernier nombre, ou une virgule si aucun code postal n'est renseigné. On cherche donc un nombre en commençant par la fin ( range(len(address),0,-1) )
for i in range(len(address)-1,0,-1):
c = address[i]
if c in "0123456789,":
#c est un nombre (ou une virgule), on peut sortir de la boucle
break
#On extrait le nom de la ville
city = address[i+2:]
return city
df = df.assign(city = df["address"].apply(get_city))
df = df.assign(price_per_m2 = df.price/df.surface)
df = df.assign(price_per_room = df.price/df.rooms)
df
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb | Namur | 2666.666667 | 100000.000000 |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb | Charleroi | 1000.000000 | 30000.000000 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.000000 |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb | Fleurus | 1352.941176 | 76666.666667 |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan | Namur | 1750.000000 | 87500.000000 |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan | Bruxelles | 3181.818182 | 233333.333333 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb | Namur | 2000.000000 | 93333.333333 |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb | Namur | 2000.000000 | 80000.000000 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.000000 |
#Ou (idem)
df["city"] = df["address"].apply(get_city)
df["price_per_m2"] = df.price/df.surface
df["price_per_room"] = df.price/df.rooms
df
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb | Namur | 2666.666667 | 100000.000000 |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb | Charleroi | 1000.000000 | 30000.000000 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.000000 |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb | Fleurus | 1352.941176 | 76666.666667 |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan | Namur | 1750.000000 | 87500.000000 |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan | Bruxelles | 3181.818182 | 233333.333333 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb | Namur | 2000.000000 | 93333.333333 |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb | Namur | 2000.000000 | 80000.000000 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.000000 |
df.groupby("website").mean()
price | rooms | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|---|
website | |||||
immovlan | 456000.0 | 4.20 | 184.00 | 2473.291741 | 117366.666667 |
immoweb | 298750.0 | 3.75 | 166.25 | 1964.690564 | 84083.333333 |
Le prix/m2 et le prix/pièce est en moyenne plus élevé sur immovlan.
df.groupby("city").mean()
price | rooms | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|---|
city | |||||
Bruxelles | 452000.0 | 3.6 | 156 | 2867.736185 | 131200.000000 |
Charleroi | 150000.0 | 5.0 | 150 | 1000.000000 | 30000.000000 |
Fleurus | 280000.0 | 4.0 | 245 | 1192.095588 | 71333.333333 |
Namur | 340000.0 | 4.0 | 166 | 2072.222222 | 86166.666667 |
Quelques observations:
On peut identifier deux types de variables: des variables continues (tel que le prix ou la surface), et des variables catégorielles, tel que la ville ou la plateforme.
Les variables continues permettent d'extraire toutes sortes de statistiques, et peuvent être comparées entre elles, par exemple par une analyse de corrélation ou une comparaison d'histogrammes, ou par des modèles prédictifs (e.g.: régression linéaire).
Les variables catégorielles permettent quand à elles une analyse comparative de catégories (une analyse factorielle), par comparaison des statistiques extraites sur les variables continues pour chaque catégorie.
Certaines variables peuvent également être considérées de plusieurs manières: le nombre de pièces est une variable discrète. Etant donné que le nombre de valeurs différentes est très limité, on pourrait la considérer comme une variable catégorielle (plus spécifiquement comme une variable ordinale, i.e. une échelle).
A l'inverse, l'adresse pourrait être considérée comme une variable continue si on la traduisait en coordonnées GPS, ou en une distance (à vol d'oiseau ou par la route) à un lieu de référence (distance au magasin le plus proche, l'autoroute la plus proche, à la capitale, à la frontière, etc.).
La méthode .corr() permet de calculer les corrélations 2 par 2 pour toutes les variables numériques.
df.corr()
price | rooms | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|---|
price | 1.000000 | -0.160783 | 0.233623 | 0.750157 | 0.890961 |
rooms | -0.160783 | 1.000000 | 0.410615 | -0.411927 | -0.553127 |
surface | 0.233623 | 0.410615 | 1.000000 | -0.397963 | 0.049693 |
price_per_m2 | 0.750157 | -0.411927 | -0.397963 | 1.000000 | 0.753682 |
price_per_room | 0.890961 | -0.553127 | 0.049693 | 0.753682 | 1.000000 |
Les corrélations entre les variables continues peuvent être fortement influencées par d'autres facteurs (catégoriels par exemple). Par exemple, on s'attend à ce que le prix augmente avec la surface pour des maisons donc les autres caractéristiques sont semblables, mais il est évident qu'une maison à la capitale est généralement plus chère qu'une maison de la même surface à la campagne.
bxldf = df[df.city == "Bruxelles"]
bxldf
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan | Bruxelles | 3181.818182 | 233333.333333 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
bxldf.corr()
price | rooms | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|---|
price | 1.000000 | 0.007169 | 0.949677 | 0.618822 | 0.874520 |
rooms | 0.007169 | 1.000000 | 0.147841 | -0.201748 | -0.478613 |
surface | 0.949677 | 0.147841 | 1.000000 | 0.347179 | 0.761512 |
price_per_m2 | 0.618822 | -0.201748 | 0.347179 | 1.000000 | 0.642289 |
price_per_room | 0.874520 | -0.478613 | 0.761512 | 0.642289 | 1.000000 |
Si on n'analyse que les maisons Bruxelloises, on constate une corrélation forte entre la surface et le prix.
df.groupby("rooms").mean()
price | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|
rooms | ||||
3.0 | 378000.0 | 154 | 2440.285205 | 126000.0 |
4.0 | 367500.0 | 165 | 2270.833333 | 91875.0 |
5.0 | 327500.0 | 205 | 1699.805964 | 65500.0 |
df[df.rooms == 5]
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb | Charleroi | 1000.000000 | 30000.0 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.0 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.0 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.0 |
On remarque que ces résultats sont principalement dus à une maison particulière, celle de Charleroi: le prix par nombre de chambres est anormalement bas, en comparaison à toutes les autres maisons du dataset. Nous verrons plus loin comment gérer les données inhabituelles
cat1 = "city"
cat2 = "rooms"
#cat2 = "website"
count_analysis = df.groupby([cat1,cat2])["price"].count().unstack(fill_value=0).transpose()
count_analysis
city | Bruxelles | Charleroi | Fleurus | Namur |
---|---|---|---|---|
rooms | ||||
3.0 | 3 | 0 | 1 | 1 |
4.0 | 1 | 0 | 0 | 3 |
5.0 | 1 | 1 | 1 | 1 |
price_analysis = df.groupby([cat1,cat2])["price"].mean().unstack(fill_value=0).transpose()
price_analysis
city | Bruxelles | Charleroi | Fleurus | Namur |
---|---|---|---|---|
rooms | ||||
3.0 | 460000.0 | 0.0 | 230000.0 | 280000.000000 |
4.0 | 400000.0 | 0.0 | 0.0 | 356666.666667 |
5.0 | 480000.0 | 150000.0 | 330000.0 | 350000.000000 |
Les anomalies sont des observations très différentes de la masse des données. Par exemple, si pour un dataset de 100 maisons, toutes sont entre 200000 et 400000 et une seule est à 100000, elle peut-être considérée comme une anomalie. Ou si on a 100 maisons à Bruxelles et une seule à Philippeville, on peut également considérer cette dernière comme anormale. Elle risque en effet d'être tellement différente des autres qu'elle aura une forte influence sur les statistiques. Lors d'une analyse statistique exploratoire, il est donc pertinent d'omettre ces données inhabituelles. A l'inverse, il est également parfois intéressant de détecter les valeurs exceptionnelles, permettant par exemple d'identifier des causes de problèmes (sur des données issues de capteurs d'usines par exemples); ou dans le présent contexte des éventuelles bonnes affaires immobilières (ou des fraudeurs: blanchiment d'argent ou arnaque ?).
En l'occurrence, dans notre dataset de test, on pourrait considérer la maison de Charleroi comme anormale: son prix par pièce est beaucoup moins élevé que celui de toutes les autres.
Les anomalies peuvent se détecter de deux manières: les statistiques et la visualisation graphique.
df
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb | Namur | 2666.666667 | 100000.000000 |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb | Charleroi | 1000.000000 | 30000.000000 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.000000 |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb | Fleurus | 1352.941176 | 76666.666667 |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan | Namur | 1750.000000 | 87500.000000 |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan | Bruxelles | 3181.818182 | 233333.333333 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb | Namur | 2000.000000 | 93333.333333 |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb | Namur | 2000.000000 | 80000.000000 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.000000 |
#Inter-quantile range
Q1 = df.price_per_room.quantile(0.25)
Q3 = df.price_per_room.quantile(0.75)
IQR = Q3 - Q1
h = 2
print("limits:", (Q1 - h * IQR), "to", (Q3 + h * IQR))
#Les données s'écartant fortement des quantiles sont potentiellement des outliers
is_outlier = (df.price_per_room < (Q1 - h * IQR)) | (df.price_per_room > (Q3 + h * IQR))
df.loc[is_outlier]
limits: 30000.000000000015 to 146666.66666666666
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
3 | Rue de L'Eglise 42, Charleroi | 150000.0 | 5.0 | 150 | immoweb | Charleroi | 1000.000000 | 30000.000000 |
11 | Rue de la Loi 50, Bruxelles | 700000.0 | 3.0 | 220 | immovlan | Bruxelles | 3181.818182 | 233333.333333 |
df2 = df[~is_outlier] #détection statistique d'outliers
df2.to_csv("houses_features.csv")
df2
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb | Namur | 2666.666667 | 100000.000000 |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.000000 |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb | Fleurus | 1352.941176 | 76666.666667 |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan | Namur | 1750.000000 | 87500.000000 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb | Namur | 2000.000000 | 93333.333333 |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb | Namur | 2000.000000 | 80000.000000 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.000000 |
Matplotlib
¶Matplotlib est une librairie permettent la visualisation graphique des données. Elle est habituellement utilisée avec les trois librairies présentées plus haut (Numpy, Scipy, Pandas).
from matplotlib import pyplot as plt
plt.scatter(df.surface, df.price)
plt.xlabel("Surface")
plt.ylabel("Price")
Text(0, 0.5, 'Price')
from matplotlib import pyplot as plt
plt.bar(df.address,df.price_per_room)
plt.xticks(rotation=90)
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], <a list of 13 Text xticklabel objects>)
#méthode intégrée de pandas
df.plot.bar(y="price_per_room")
plt.xticks(rotation=90)
(array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), <a list of 13 Text xticklabel objects>)
#On retire les données extrêmes
df2 = df.drop([3,11]) #détection manuelle (visuelle)
df2
address | price | rooms | surface | website | city | price_per_m2 | price_per_room | |
---|---|---|---|---|---|---|---|---|
0 | Rue de Fer 26, 5000 Namur | 400000.0 | 4.0 | 150 | immoweb | Namur | 2666.666667 | 100000.000000 |
2 | Porte de Namur 25, Bruxelles | 400000.0 | 3.0 | 120 | immoweb | Bruxelles | 3333.333333 | 133333.333333 |
4 | Rue Saint-ghislain 30, 6224 Fleurus | 330000.0 | 5.0 | 320 | immoweb | Fleurus | 1031.250000 | 66000.000000 |
6 | Rue de la Closière 20, Fleurus | 230000.0 | 3.0 | 170 | immoweb | Fleurus | 1352.941176 | 76666.666667 |
10 | Rue de Bruxelles 42, 5000 Namur | 350000.0 | 4.0 | 200 | immovlan | Namur | 1750.000000 | 87500.000000 |
12 | Rue de la Loi 51, Bruxelles | 280000.0 | 3.0 | 120 | immoweb | Bruxelles | 2333.333333 | 93333.333333 |
13 | Rue de la Loi 52, Bruxelles | 400000.0 | 4.0 | 150 | immovlan | Bruxelles | 2666.666667 | 100000.000000 |
14 | Rue de la Loi 53, Bruxelles | 480000.0 | 5.0 | 170 | immovlan | Bruxelles | 2823.529412 | 96000.000000 |
15 | Rue de Fer 27, Namur | 280000.0 | 3.0 | 140 | immoweb | Namur | 2000.000000 | 93333.333333 |
16 | Rue de Fer 28, Namur | 320000.0 | 4.0 | 160 | immoweb | Namur | 2000.000000 | 80000.000000 |
17 | Rue de Fer 29, Namur | 350000.0 | 5.0 | 180 | immovlan | Namur | 1944.444444 | 70000.000000 |
df2.groupby("rooms").mean()
price | surface | price_per_m2 | price_per_room | |
---|---|---|---|---|
rooms | ||||
3.0 | 297500.000000 | 137.500000 | 2254.901961 | 99166.666667 |
4.0 | 367500.000000 | 165.000000 | 2270.833333 | 91875.000000 |
5.0 | 386666.666667 | 223.333333 | 1933.074619 | 77333.333333 |
result = df2.groupby("rooms").mean()
#Divide each column by its sum (so that sum is 1) - so that multiple bar plots with various orders are visible
result = result/result.sum()
result.plot(kind="bar")
<matplotlib.axes._subplots.AxesSubplot at 0x7f7293705c88>
#plus lisible (on transpose pour avoir un graphe par varible plutôt que par nombre de chambres)
result.transpose().plot(kind="bar")
<matplotlib.axes._subplots.AxesSubplot at 0x7f72937c8e48>
On remarque que:
website_comparison = df.groupby("website").mean()
website_comparison.plot.bar(y="price")
<matplotlib.axes._subplots.AxesSubplot at 0x7f72935993c8>
#DF.plot: afficher une courbe. On trie d'abord les maisons par surface croissante pour afficher la courbe (DF.sort_values("surface"))
bxldf.sort_values("surface").plot("surface","price")
<matplotlib.axes._subplots.AxesSubplot at 0x7f72935f6518>
count_analysis.plot.pie(subplots = True, figsize = (15,15))
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7f72934e2d30>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f72935035c0>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f72934ada20>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f7293454e80>], dtype=object)
price_analysis.plot.bar(subplots = True, figsize = (10,10))
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7f72933c9390>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f7293405860>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f72933accc0>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f7293361160>], dtype=object)
Vous pouvez maintenant passer au Chapitre 7: Introduction au Machine Learning