Taccuino-guida per un rapido Data preprocessing

Spesso le persone che si avventurano nel campo della Data Science hanno aspettative poco realistiche su ciò che li attende. Molti pensano che ora scriveranno facilmente reti neurali, creeranno un assistente vocale simile a Iron Man o batteranno tutti nei mercati finanziari.
Ma il lavoro Data del Scientist è legato ai dati, e uno dei momenti più importanti e dispendiosi in termini di tempo è la preparazione dei dati prima di passarli a una rete neurale o analizzarli in un certo modo.

In questo articolo, il nostro team descriverà come elaborare i dati in modo facile e veloce con istruzioni passo-passo e codice. Abbiamo cercato di rendere il codice abbastanza flessibile da poter essere applicato a diversi dataset.

Molti professionisti potrebbero non trovare nulla di straordinario in questo articolo, ma i principianti potranno apprendere qualcosa di nuovo; inoltre, chi sogna da tempo di creare un notebook personale per un'elaborazione dei dati rapida e strutturata può copiare il codice e formattarlo a proprio piacimento, oppure scaricare un notebook già pronto da Github.

Abbiamo ottenuto il dataset. Cosa fare dopo?

Quindi, il primo passo è capire di cosa stiamo parlando, avere una visione d'insieme. Utilizziamo pandas per identificare i diversi tipi di dati.

import pandas as pd #importiamo pandas
import numpy as np  #importiamo numpy
df = pd.read_csv("AB_NYC_2019.csv") #leggiamo il dataset e lo assegniamo alla variabile df

df.head(3) #guardiamo le prime 3 righe per capire come appaiono i valori

Taccuino-guida per un rapido Data preprocessing

df.info() #Mostriamo informazioni sulle colonne

Taccuino-guida per un rapido Data preprocessing

Esaminiamo i valori delle colonne:

  1. Il numero di righe in ogni colonna corrisponde al numero totale di righe?
  2. Qual è il significato dei dati in ciascuna colonna?
  3. Quale colonna vogliamo impostare come target per fare previsioni?

Le risposte a queste domande ci permetteranno di analizzare il dataset e delineare un piano per i prossimi passi.

Inoltre, per avere uno sguardo più profondo sui valori in ogni colonna, possiamo utilizzare la funzione pandas describe(). Tuttavia, il difetto di questa funzione è che non fornisce informazioni sulle colonne con valori stringa. Li affronteremo in seguito.

df.describe()

Taccuino-guida per un rapido Data preprocessing

Magica visualizzazione

Vediamo dove mancano completamente i valori:

import seaborn as sns
sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')

Taccuino-guida per un rapido Data preprocessing

Questo è stato un breve sguardo dall'alto, ora ci introdiamo in argomenti più interessanti.

Cerchiamo di trovare e, se possibile, rimuovere le colonne che hanno solo un valore in tutte le righe (non influenzeranno il risultato):

df = df[[c for c in list(df) if len(df[c].unique()) > 1]] #Riassegniamo il dataset mantenendo solo le colonne con più di un valore unico.

Ora ci proteggiamo e proteggiamo il successo del nostro progetto dalle righe duplicate (righe che contengono le stesse informazioni nello stesso ordine di una delle righe esistenti):

df.drop_duplicates(inplace=True) #Facciamo ciò se lo riteniamo necessario.
                                 #In alcuni progetti, non è opportuno rimuovere tali dati fin dall'inizio.

Dividiamo il dataset in due: uno con valori qualitativi e l'altro con valori quantitativi.

È necessario fare una piccola precisazione: se le righe con dati mancanti non sono fortemente correlate tra i dati qualitativi e quantitativi, sarà necessario decidere cosa sacrificare: tutte le righe con dati mancanti, solo una parte di esse o colonne specifiche. Se invece le righe sono correlate, abbiamo il pieno diritto di dividere il dataset in due. In caso contrario, dobbiamo prima affrontare le righe in cui non corrispondono i dati mancanti nei dati qualitativi e quantitativi, e solo dopo dividere il dataset in due.

df_numerical = df.select_dtypes(include = [np.number])
df_categorical = df.select_dtypes(exclude = [np.number])

Lo facciamo per rendere più facile l'elaborazione di questi due diversi tipi di dati — in seguito capiremo quanto semplifica la nostra vita.

Lavoriamo con dati quantitativi

La prima cosa da fare è determinare se ci sono 'colonne-spie' nei dati quantitativi. Chiamiamo queste colonne così perché si spacciano per dati quantitativi, ma funzionano come qualitativi.

Come possiamo identificarli? Naturalmente, tutto dipende dalla natura dei dati che stai analizzando, ma in generale queste colonne possono avere pochi dati unici (circa 3-10 valori unici).

print(df_numerical.nunique())

Dopo aver identificato le colonne-spia, le sposteremo dai dati quantitativi a quelli qualitativi:

spy_columns = df_numerical[['colonna1', 'colonna2', 'colonna3']]  # selezioniamo le colonne-spia e le registriamo in un dataframe separato
df_numerical.drop(labels=['colonna1', 'colonna2', 'colonna3'], axis=1, inplace=True)  # rimuoviamo queste colonne dai dati quantitativi
df_categorical.insert(1, 'colonna1', spy_columns['colonna1'])  # aggiungiamo la prima colonna-spia ai dati qualitativi
df_categorical.insert(1, 'colonna2', spy_columns['colonna2'])  # aggiungiamo la seconda colonna-spia ai dati qualitativi
df_categorical.insert(1, 'colonna3', spy_columns['colonna3'])  # aggiungiamo la terza colonna-spia ai dati qualitativi

Finalmente abbiamo separato completamente i dati quantitativi da quelli qualitativi e ora possiamo lavorarci a dovere. Prima di tutto, dobbiamo capire dove abbiamo valori vuoti (NaN e, in alcuni casi, 0 saranno considerati come valori vuoti).

for i in df_numerical.columns:
    print(i, df[i][df[i]==0].count())

A questo punto è fondamentale comprendere in quali colonne gli zeri possono significare valori mancanti: è legato al modo in cui sono stati raccolti i dati? O potrebbe riguardare i valori dei dati? Queste domande devono essere affrontate in ogni singolo caso.

Quindi, se abbiamo deciso che i dati possono essere assenti dove ci sono zeri, dobbiamo sostituire gli zeri con NaN, in modo da lavorare più facilmente con questi dati mancanti:

df_numerical[["colonna 1", "colonna 2"]] = df_numerical[["colonna 1", "colonna 2"]].replace(0, nan)

Ora vediamo dove abbiamo dati mancanti:

sns.heatmap(df_numerical.isnull(), yticklabels=False, cbar=False, cmap='viridis') # Puoi anche usare df_numerical.info()

Taccuino-guida per un rapido Data preprocessing

Qui dovrebbero essere evidenziati in giallo i valori all'interno delle colonne che sono assenti. E ora inizia la parte interessante — come comportarsi con questi valori? Eliminare le righe con questi valori o le colonne? O riempire questi valori vuoti con qualcos'altro?

Ecco uno schema approssimativo che può aiutarti a decidere cosa si può fare con i valori vuoti:

Taccuino-guida per un rapido Data preprocessing

0. Rimuovere colonne non necessarie

df_numerical.drop(labels=["colonna1", "colonna2"], axis=1, inplace=True)

1. Il numero di valori vuoti in questa colonna è superiore al 50%?

print(df_numerical.isnull().sum() / df_numerical.shape[0] * 100)

df_numerical.drop(labels=["colonna1","colonna2"], axis=1, inplace=True)#Rimuoviamo se qualche colonna ha più di 50 valori vuoti

2. Rimuoviamo le righe con valori vuoti

df_numerical.dropna(inplace=True)#Rimuoviamo le righe con valori vuoti, a condizione che restino abbastanza dati per l'apprendimento

3.1. Inseriamo un valore casuale

import random #importiamo random
df_numerical["colonna"].fillna(lambda x: random.choice(df[df[column] != np.nan]["colonna"]), inplace=True) #inseriamo valori casuali nelle celle vuote della tabella

3.2. Inseriamo un valore costante

from sklearn.impute import SimpleImputer #importiamo SimpleImputer che ci aiuterà a inserire valori
imputer = SimpleImputer(strategy='constant', fill_value="") #inseriamo un valore specifico utilizzando SimpleImputer
df_numerical[["nuova_colonna1",'nuova_colonna2','nuova_colonna3']] = imputer.fit_transform(df_numerical[['colonna1', 'colonna2', 'colonna3']]) #Applichiamo questo alla nostra tabella
df_numerical.drop(labels = ["colonna1","colonna2","colonna3"], axis = 1, inplace = True) #Rimuoviamo le colonne con i vecchi valori

3.3. Inseriamo la media o il valore più frequente

from sklearn.impute import SimpleImputer # importiamo SimpleImputer, che aiuterà a riempire i valori
imputer = SimpleImputer(strategy='mean', missing_values = np.nan) # al posto di mean si può usare anche most_frequent
df_numerical[["nuova_colonna1", 'nuova_colonna2', 'nuova_colonna3']] = imputer.fit_transform(df_numerical[['colonna1', 'colonna2', 'colonna3']]) # Applichiamo a nostra tabella
df_numerical.drop(labels = ["colonna1", "colonna2", "colonna3"], axis = 1, inplace = True) # Rimuoviamo le colonne con i vecchi valori

3.4. Inserire un valore calcolato da un altro modello

A volte i valori possono essere calcolati usando modelli di regressione, utilizzando i modelli della libreria sklearn o altre librerie simili. Il nostro team dedicherà un articolo separato su come farlo in un prossimo futuro.

Dunque, mentre il racconto sui dati quantitativi si interromperà, ci sono molte altre sfumature su come eseguire al meglio la preparazione e il preprocessing dei dati per vari compiti, e le basi per i dati quantitativi sono state considerate in questo articolo. Ora è il momento di tornare ai dati qualitativi, che abbiamo separato alcuni passaggi fa dai quantitativi. Puoi modificare questo notebook come preferisci, adattandolo a diverse esigenze, in modo che il preprocessing dei dati avvenga molto rapidamente!

Dati qualitativi

Per i dati qualitativi viene principalmente utilizzato il metodo One-hot-encoding, per formattarli da stringa (o oggetto) a numero. Prima di passare a questo punto, utilizziamo lo schema e il codice sopra per affrontare i valori nulli.

df_categorical.nunique()

sns.heatmap(df_categorical.isnull(), yticklabels=False, cbar=False, cmap='viridis')

Taccuino-guida per un rapido Data preprocessing

0. Rimuovere colonne non necessarie

df_categorical.drop(labels=["colonna1", "colonna2"], axis=1, inplace=True)

1. Il numero di valori vuoti in questa colonna è superiore al 50%?

print(df_categorical.isnull().sum() / df_numerical.shape[0] * 100)

df_categorical.drop(labels=["colonna1", "colonna2"], axis=1, inplace=True) #Rimuovi se qualche colonna 
                                                                          #ha più del 50% di valori nulli

2. Rimuoviamo le righe con valori vuoti

df_categorical.dropna(inplace=True)#Rimuoviamo le righe con valori nulli, 
                                   #se poi rimangono abbastanza dati per l'apprendimento

3.1. Inseriamo un valore casuale

import random
df_categorical["colonna"].fillna(lambda x: random.choice(df[df[column] != np.nan]["colonna"]), inplace=True)

3.2. Inseriamo un valore costante

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='constant', fill_value="")
df_categorical[["nuova_colonna1", 'nuova_colonna2', 'nuova_colonna3']] = imputer.fit_transform(df_categorical[['colonna1', 'colonna2', 'colonna3']])
df_categorical.drop(labels=["colonna1", "colonna2", "colonna3"], axis=1, inplace=True)

Finalmente abbiamo risolto i valori nulli nei dati qualitativi. Ora è il momento di effettuare la codifica one-hot per i valori presenti nel tuo database. Questo metodo è comunemente utilizzato affinché il tuo algoritmo possa apprendere tenendo conto dei dati qualitativi.

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    res = res.drop([feature_to_encode], axis=1)
    return(res)

features_to_encode = ["colonna1", "colonna2", "colonna3"]
for feature in features_to_encode:
    df_categorical = encode_and_bind(df_categorical, feature))

Infine, abbiamo completato l'elaborazione dei dati qualitativi e quantitativi separatamente — è ora di combinarli nuovamente.

new_df = pd.concat([df_numerical, df_categorical], axis=1)

Dopo aver unito i dataset in uno solo, possiamo finalmente utilizzare la trasformazione dei dati con MinMaxScaler della libreria sklearn. Questo porterà i nostri valori nell'intervallo da 0 a 1, il che sarà utile per l'addestramento del modello in futuro.

from sklearn.preprocessing import MinMaxScaler
min_max_scaler = MinMaxScaler()
new_df = min_max_scaler.fit_transform(new_df)

Questi dati sono ora pronti per qualsiasi cosa: reti neurali, algoritmi ML standard, ecc.!

In questo articolo non abbiamo considerato il lavoro con dati relativi alle serie temporali, in quanto per tali dati è necessario utilizzare tecniche di elaborazione leggermente diverse, a seconda del vostro obiettivo. In futuro, il nostro team dedicherà un articolo specifico a questo argomento e speriamo che possa portare qualcosa di interessante, nuovo e utile nella vostra vita, proprio come questo.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster