Team I.A. Italia

10 min

Esempio pratico di Machine Learning con Python : Stimare / Prevedere il prezzo degli appartamenti

Aggiornato il: 15 apr 2021

Prerequisiti :

Stimare prezzo di una casa

Introduzione

Personalmente penso che i progetti sono il modo migliore per approfondire la conoscenza della scienza dei dati e delle applicazioni dell'intelligenza artificiale. Infatti, non solo i neofiti, ma anche i professionisti esperti di livello medio possono aggiornare il proprio curriculum con nuovi progetti interessanti. Dopotutto, non sono facili. Ci vuole molto tempo per creare un progetto che possa davvero mostrare la profondità e l'ampiezza delle tue conoscenze.

Spero che questo progetto ti aiuti ad acquisire le conoscenze necessarie e che il tuo curriculum venga inserito più rapidamente nella rosa dei candidati. Questo progetto mostra tutti i passaggi (da zero) effettuati per risolvere un problema di Machine Learning. Per la tua comprensione, ho preso un set di dati semplice ma impegnativo in cui puoi anche progettare le funzionalità a tua discrezione.

Questo progetto è più adatto a persone che hanno una conoscenza di base di Python.

Anche se sei assolutamente nuovo, provalo. E fai domande nei commenti qui sotto.

Processo di previsioni di machine learning

"Continua a tormentare i dati finché non iniziano a rivelare i loro segreti nascosti."

Fare previsioni utilizzando l'apprendimento automatico non significa solo acquisire i dati e fornirli agli algoritmi. L'algoritmo potrebbe emettere qualche previsione ma non è quello a cui stai mirando.

Il processo è il seguente:

  1. Capire il problema: prima di iniziare a lavorare sui dati, è necessario comprendere il problema che stiamo cercando di risolvere. Se conosci già la soluzione al problema di machine learning, pensa a quali fattori potrebbero svolgere un ruolo fondamentale nella risoluzione del problema e passa al terzo step. Se ancora devi elaborare una strategia o una risoluzione passa al secondo step.

  2. Facciamo qualche ipotesi: Questo è abbastanza importante, ma spesso viene dimenticato. In parole semplici, la generazione di ipotesi si riferisce alla creazione di un insieme di caratteristiche che potrebbero influenzare la variabile obiettivo/target. Possiamo farlo prima di esaminare i dati per evitare pensieri o conclusioni affrettate. Questo passaggio spesso aiuta a creare nuove funzionalità.

  3. Iniziamo a lavorare sui dati: ora, scarichiamo i dati e li esaminiamo. Determina quali funzionalità (possibili standardizazioni o normalizazioni ad esempio) dei dati sono disponibili e quali no. Rispondere a queste domande ci metterà sulla strada giusta.

  4. Creiamo il nostro modello:Utilizzando un algoritmo appropriato, addestriamo il modello sul set di dati specificato.

  5. Valutazione del modello: una volta addestrato il modello, valutiamo le prestazioni del modello utilizzando una metrica di errore adeguata. Qui, cerchiamo anche l'importanza della variabile, cioè quali variabili si sono dimostrate significative nel determinare la variabile di destinazione. Di conseguenza, possiamo selezionare le migliori variabili e addestrare nuovamente il modello.

  6. Testiamo il nostro modello: Infine, testiamo il modello sul set di dati invisibili (dati di test). Seguiremo questo processo nel progetto per arrivare alle nostre previsioni finali. Iniziamo.

  7. Scarica Gratis il progetto

1) Capire il problema

Il set di dati per questo progetto è stato preso dal set di appartamenti di Kaggle. Come accennato in precedenza, il set di dati è semplice. Questo progetto mira a prevedere i prezzi delle case (residenziali) ad Ames, USA. In questo caso il nostro problema è andare a creare un modello in grado di predire il prezzo di questi appartamenti in base alle caratteristiche che abbiamo.

2) Facciamo qualche ipotesi

Bene, ora arriva la parte divertente.

Quali fattori riesci a pensare in questo momento che possono influenzare i prezzi delle case? Mentre leggi questo, voglio che tu annoti anche i tuoi fattori.

La definizione di un'ipotesi ha due parti: ipotesi nulla (0) e ipotesi concreta (1). Possono essere intese come:

0 - Non esiste alcun impatto di una particolare caratteristica sulla variabile dipendente.

1 - Esiste un impatto diretto di una caratteristica particolare sulla variabile dipendente.

Sulla base di un criterio decisionale (diciamo, livello di significatività del 5%) definiamo due classi :

  • "Rifiuto"

  • "Accetto"

In pratica, durante la creazione del modello cerchiamo valori di probabilità (p). Se il valore p<0.05, Rifiuto e quindi si avvera l'ipotesi nulla. Se p> 0.05 ci troviamo nel caso di ipotesi concreta e quindi quella caratteristica la Accettiamo perchè ha una correlazione con il nostro target. Alcuni fattori a cui posso pensare che influenzano direttamente i prezzi delle case sono i seguenti:

  • Area della casa

  • Quanti anni ha la casa

  • Posizione della casa

  • Quanto è vicino / lontano il mercato

  • Connettività della posizione della casa con i trasporti

  • Quanti piani ha la casa

  • Quale materiale viene utilizzato nella costruzione

  • Disponibilità di acqua / elettricità

  • Area giochi / parchi per bambini (se presenti)

  • Se la terrazza è disponibile

  • Se il parcheggio è disponibile

  • Se la sicurezza è disponibile

…continua a pensare. Sono sicuro che puoi inventarne molti altri oltre a questi.

3) Iniziamo a lavorare sui dati

Puoi scaricare i dati e caricarli nel tuo IDE python.

Test.csv Train.csv

Il set di dati è costituito da 81 variabili esplicative. Sì, non sarà una passeggiata per chì vorrà approfondire fino in fondo tutto il Dataset. Ma impareremo come gestire così tante variabili. La variabile di destinazione è SalePrice.

Iniziamo a scrivere un po di codice e a divertiamoci.


 
#Importiamo le librerie necessarie
 
import numpy as np
 
import pandas as pd
 
import seaborn as sns
 
from scipy import stats
 
from scipy.stats import norm
 
import matplotlib.pyplot as plt
 

 
#Impostiamo la grandezza del grafico di matplotlib
 
%matplotlib inline
 
plt.rcParams['figure.figsize'] = (10.0, 8.0)
 

 
#Carichiamo i dati che hai scaricato dal link
 
train = pd.read_csv("train.csv")
 
test = pd.read_csv("test.csv")
 

 
#Stampiamo quante righe e colonne ha il nostro dataset
 
print ('Train contiene {0} righe e {1} colonne'.format(train.shape[0],train.shape[1]))
 
print ('----------------------------')
 
print ('Test contiene {0} righe e {1} colonne'.format(test.shape[0],test.shape[1]))
 

 
output :
 
Train contiene 1460 righe e 81 colonne
 
----------------------------
 
Test contiene 1459 righe e 80 colonne
 

In alternativa, puoi anche controllare le informazioni sul set di dati utilizzando il comando info ().

train.info()
 

 
output :
 
<class 'pandas.core.frame.DataFrame'>
 
RangeIndex: 1460 entries, 0 to 1459
 
Data columns (total 81 columns):
 
# Column Non-Null Count Dtype
 
--- ------ -------------- -----
 
0 Id 1460 non-null int64
 
1 MSSubClass 1460 non-null int64
 
2 MSZoning 1460 non-null object
 
3 LotFrontage 1201 non-null float64
 
.....
 
77 YrSold 1460 non-null int64
 
78 SaleType 1460 non-null object
 
79 SaleCondition 1460 non-null object
 
80 SalePrice 1460 non-null int64
 
dtypes: float64(3), int64(35), object(43)
 
memory usage: 924.0+ KB

Controlliamo se il set di dati ha valori mancanti. Questo è molto importante perchè in alcuni casi questi dati vengono completamente ignorati o scartati. In questo caso noi ci concentreremo solo sulle variabile numeriche e non nulle.


 
train.columns[train.isnull().any()]
 

 
Output:
 
Index(['LotFrontage', 'Alley', 'MasVnrType', 'MasVnrArea', 'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2', 'Electrical', 'FireplaceQu', 'GarageType', 'GarageYrBlt', 'GarageFinish', 'GarageQual', 'GarageCond', 'PoolQC', 'Fence', 'MiscFeature'], dtype='object')
 

Procediamo e controlliamo la distribuzione della variabile target.

#Distribuzione della variabile target
 
sns.distplot(train['SalePrice'])
 

 
Output:

sns.distplot(train['SalePrice'])

Vediamo che la variabile target SalePrice ha una distribuzione asimmetrica a destra. Avremo bisogno di registrare la trasformazione di questa variabile in modo che diventi normalmente distribuita. Una variabile target normalmente distribuita (o vicina al normale) aiuta a modellare meglio la relazione tra le variabili target e indipendenti. Inoltre, gli algoritmi lineari assumono una varianza costante nel termine di errore. In alternativa, possiamo anche confermare questo comportamento distorto utilizzando la metrica di asimmetria.

#skewness
 
print "Il skewness del prezzo è {}".format(train['SalePrice'].skew())
 

 
Output:
 
The skewness of SalePrice is 1.88287575977

Registriamo la trasformazione di questa variabile e vediamo se la distribuzione di questa variabile può avvicinarsi alla normalità.

#Trasformiamo la variabile di target
 
target = np.log(train['SalePrice'])
 
print('Skewness è', target.skew())
 
sns.distplot(target)
 

 
Output:
 
Skewness is 0.12133506220520406)

Che trasformazione

Come hai visto, la trasformazione logaritmica della variabile target ci ha aiutato a correggere la sua distribuzione asimmetrica e la nuova distribuzione sembra più vicina alla normalità. Dato che abbiamo 80 variabili, visualizzarne una per una non sarebbe un approccio astuto. Invece, siccome lo studio risulterebbe molto lungo e complesso ci dedicheremo solo alle variabile numeriche tralasciando le categoriche.

#Separiamo il dataset in altri 2 numerico e categorico
 
numeric_data = train.select_dtypes(include=[np.number])
 
cat_data = train.select_dtypes(exclude=[np.number])
 
print ("ci sono {} colonne numeriche e {} categoriche".format(numeric_data.shape[1],cat_data.shape[1]))
 

 
Output:
 
Ci sono 38 colonne numeriche e 43 categoriche.

Dovremmo rimuovere la variabile Id dai dati numerici.

del numeric_data['Id']

Ora, siamo interessati a conoscere il comportamento di correlazione delle variabili numeriche. Su 38 variabili, presumo che alcune debbano essere correlate. Se trovate, possiamo successivamente rimuovere le variabili non correlate poiché non forniranno alcuna informazione utile al modello.

#correlation plot
 
corr = numeric_data.corr()
 
sns.heatmap(corr)

Notare l'ultima riga di questa mappa. Possiamo vedere la correlazione di tutte le variabili con SalePrice. Come puoi vedere, alcune variabili sembrano essere fortemente correlate con la variabile target. Qui, un punteggio di correlazione numerica ci aiuterà a capire meglio il grafico.

print (corr['SalePrice'].sort_values(ascending=False)[:15], '\n') #top 15 variabili correlate
 
print ('----------------------')
 
print (corr['SalePrice'].sort_values(ascending=False)[-5:])
 
#last 5 variabili non correlate
 

 
Output:
 
SalePrice 1.000000
 
OverallQual 0.790982
 
GrLivArea 0.708624
 
GarageCars 0.640409
 
GarageArea 0.623431
 
TotalBsmtSF 0.6135811
 
stFlrSF 0.605852
 
FullBath 0.560664
 
TotRmsAbvGrd 0.533723
 
YearBuilt 0.522897
 
YearRemodAdd 0.507101
 
GarageYrBlt 0.486362
 
MasVnrArea 0.477493
 
Fireplaces 0.466929
 
BsmtFinSF1 0.386420
 
Name: SalePrice, dtype: float64

Qui vediamo che la OverallQual caratteristica è correlata al 79% con la variabile target. Overallqual variabile si riferisce al materiale complessivo e alla qualità dei materiali della casa completata. Bene, anche questo ha senso. Le persone di solito considerano questi parametri per la loro casa dei sogni. Inoltre, GrLivArea è correlato al 70% con la variabile target. GrLivAreasi riferisce alla zona giorno (in sq ft.). Le seguenti variabili mostrano che le persone si preoccupano anche se la casa ha un garage, l'area di quel garage, le dimensioni dell'area seminterrato, ecc.

Tracciamo dei grafici qualitativi per vedere meglio che tipo di correlazioni hanno OverallQual e GrLivAreasi con il nostro target.

Per quanto riguarda la variabile OverallQual procederemo dividendola in classi per poi rappresentarla in funzione del prezzo crescente per vedere cosa accade al prezzo con l'aumentare della qualità dei materiali. Il codice è il seguente

train['OverallQual'].unique()
 

 
Output:
 
array([ 7, 6, 8, 5, 9, 4, 10, 3, 1, 2])
 

 

 
#grafichiamo le 10 classi di OverallQual in corrispondenza del prezzo
 
pivot = train.pivot_table(index='OverallQual', values='SalePrice', aggfunc=np.median)
 
pivot.plot(kind='bar', color='red')
 

 
Outptu:

Grafico che indica l'aumento del prezzo in funzione dei diversi materiali della casa

Questo comportamento è abbastanza normale. Man mano che la qualità complessiva di una casa aumenta, aumenta anche il suo prezzo di vendita. Visualizziamo la successiva variabile correlata GrLivAreae comprendiamo il loro comportamento.

#GrLivArea
 
sns.jointplot(x=train['GrLivArea'], y=train['SalePrice'])
 

 
Outptu:
 

Ti suggerisce qualcosa?

Come visto sopra, anche qui vediamo una correlazione diretta della zona giorno con il prezzo di vendita. Tuttavia, possiamo individuare un valore anomalo GrLivArea> 5000. Ho visto valori anomali giocare un ruolo significativo nel rovinare le prestazioni di un modello. Quindi, ce ne sbarazzeremo. Se ti piace questa attività, puoi visualizzare anche altre variabili correlate. Arrivati a questo punto bisognerebbe applicare i ragionamenti fatti per le variabili GrLivAreae e OverallQual per tutte le variabili che abbiamo a disposizione. Essendo questo un articolo di tutorial ci fermeremo a queste due variabili per l'analisi dell'esempio pratico di machine learning per non risultare troppo complesso o pesante per chi è alle prime armi. Ti invito comunque a giocare con le altre variabili e a creare un modello migliore di quello che creeremo all'interno dell'articolo.

Ora elaboriamo le nostre variabili per avere un modello performante.

#rimuoviamo i valori anomali
 
train.drop(train[train['GrLivArea'] > 4000].index, inplace=True)
 
train.shape #removed 4 rows`
 

 
Output:
 
(1456, 81)
 

A questo punto ricreiamo i nostri dataset utilizzando solo le variabili che abbiamo scelto.

Nel nostro caso saranno solo due. Ma ti invito a trovarne altre per rendere il tutto più divertente.


 
#ridivido le x e y di allenamento e test
 
newdataset = train[['GrLivArea','OverallQual','SalePrice']]
 

 
X_train = train[['GrLivArea','OverallQual']]
 
y_train = train['SalePrice']
 

 

 
X_test = train[['GrLivArea','OverallQual']]
 
y_test = train['SalePrice']
 

Creiamo adesso un Pairplot e la Heatmap per avere una visione più completa delle correlazioni.

sns.pairplot(newdataset)
 
plt.show()
 

 
Output:

Pairplot

Heatmap

4) Creiamo il nostro modello

Ora che abbiamo un idea più concreta del nostro problema, delle ipotesi e che abbiamo lavorato il dato possiamo concentrarci nella creazione del nostro modello.

In questo caso utilizzeremo due modelli diversi.

Utilizzeremo prima il Random_Forest_Regression_Model e successivamente il Linear_Regression_Model così da poter successivamente confrontare i due modelli.

Ho scritto questi due modelli come delle funzioni in modo tale che potrai riutilizzarli con i tuoi dati passandogli solamente il dataset e il target.

Vediamo adesso il Random_Forest_Regression_Model:

def Random_Forest_Regression_Model(dataset,target):
 
X = dataset.loc[:, dataset.columns != target]
 
y = dataset[target]
 

 
from sklearn.ensemble import RandomForestRegressor
 
from sklearn.model_selection import train_test_split
 

 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
 
model = RandomForestRegressor(random_state=1)
 
model.fit(X_train, y_train)
 
pred = model.predict(X_test)# Visualizing Feature Importance
 
feat_importances = pd.Series(model.feature_importances_, index=X.columns)
 
feat_importances.nlargest(25).plot(kind='barh',figsize=(10,10))
 
plt.show()
 

 
y_pred = model.predict(X)
 
labels = dataset[target]
 
df_temp = pd.DataFrame({'Previsto': labels, 'Predetto':y_pred})
 
df_temp.head()# Creating Line Graph
 

 
from matplotlib.pyplot import figure
 

 
figure(num=None, figsize=(15, 6), dpi=80, facecolor='w', edgecolor='k')
 
y1 = df_temp['Previsto']
 
y2 = df_temp['Predetto']
 
plt.plot(y1, label = 'Previsto')
 
plt.plot(y2, label = 'Predetto')
 
plt.legend()
 
plt.show()
 
from sklearn.metrics import mean_absolute_error as mae print(f'Errore Medio Assoluto ( MAE ) : {mae(y,y_pred)}')
 
from sklearn.metrics import mean_squared_error, r2_score
 
# Mean Error
 
print('Mean squared error: %.2f' % mean_squared_error(y_pred, y))
 
# Se il coefficente di determinazione è 1 il modello è perfetto
 
print('Coefficient of determination: %.2f' % r2_score(y_pred, y))
 
return model
 

 
modelloRfM = Random_Forest_Regression_Model(newdataset,'SalePrice')
 

 
Output:
 
Errore Medio Assoluto ( MAE ) : 16674.011430222203
 
Mean squared error: 639043357.06
 
Coefficient of determination: 0.88

Correlazioni Random Forest Model

Grafico Predetto Vs Previsto


 
Passiamo ora alla regressione lineare. In realtà non andrai ad usare più modelli solitamente ma in questo caso ne vedremmo due per poi paragonarli e capire quali sono gli indicatori che ci aiutano a capire quale sia il migliore.

Volendo in questo caso avere un modello performante ed un modello non performante effettueremo lo regressione utilizzando solo GrLivArea e il target SalePrice.

Scriviamo il codice ed eseguiamolo

def visualizza_Linear_Regression_Model(dataset, target):
 
X = dataset.loc[:, dataset.columns != target]
 
y = dataset[target]
 

 
from sklearn.linear_model import LinearRegression
 
from sklearn.model_selection import train_test_split
 
from sklearn.metrics import mean_absolute_error as mae
 

 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
 
model = LinearRegression()
 
model.fit(X_train, y_train)
 
y_pred = model.predict(X)
 

 
from matplotlib.pyplot import figure
 

 
# Plot outputs
 
plt.scatter(X, y, color='black')
 
plt.plot(X, y_pred, color='blue', linewidth=3)
 
plt.xticks(())
 
plt.yticks(())
 
plt.show()
 

 
from sklearn.metrics import mean_squared_error, r2_score
 

 
# Stampiamo il coefficente
 
print('Coefficients: \n', model.coef_)
 
# Mean Error
 
print('Mean squared error: %.2f' % mean_squared_error(y_pred, y))
 
# Se il coefficente di determinazione è 1 il modello è perfetto
 
print('Coefficient of determination: %.2f' % r2_score(y_pred, y))
 

 
return model
 

 
modelloLM = visualizza_Linear_Regression_Model(newdataset[['GrLivArea','SalePrice']],'SalePrice')
 

 

 
Output:
 
Coefficients:
 
[111.91917371]
 
Mean squared error: 2827781279.81
 
Coefficient of determination: 0.08

Regressione Lineare

5) Valutiamo i Modelli

Arrivati a questo punto, dove esserci divertiti a scrivere codice e a rubare ai dati informazioni nascoste, arriva un momento molto importante:

"Dobbiamo capire quanto il nostro modello è affidabile"

Riportiamo qui sotto i dati che abbiamo calcolato.

Come ci salta subito all'occhio il Random Forest Model è il modello più affidabile. Proprio come volevamo.

Solitamente quando si valuta un modello esistono diversi tipi di metriche che è possibile utilizzare. Io solitamente consiglio di utilizzare sempre questi tre campi, perche secondo un mio parere ci danno una visione generale sulle capacità del modello.

6) Testiamo il modello

Questo passaggio è fondamentale su vuoi capire a pieno quali sono i punti di "certezza" e "incertezza" del modello che hai creato. Nel nostro caso sarebbe inutile andare ad effettuare delle previsioni con i modelli che abbiamo creato, poichè, anche se "sembra" affidabile all'88% il nostro modello è stato allenato su un set molto ristretto di caratteristche e quindi non rispecchia nemmeno vagamente la realtà degli appartamenti Americani.

Arrivati a questo punto il Tutorial è terminato. Ti consiglio di non fermarti qui ma di espandere il progetto fino a dove riesci, utilizzando tutte le variabile che ritieni fondamentali per stimare il prezzo di questi appartamenti. Per qualsiasi Problema o Errore Scrivilo qui nei commenti oppure fai una domanda nel forum. Il nostro Team di Esperti di AI è pronto ad aiutarti.

Per scaricare gratuitamente devi prima registrati/accede al portale.

Scorri in fondo alla pagina per registrati o accedere

Sostienici condividendo e commentando l'articolo, Grazie !