Spesso le persone che entrano nel campo della Data Science hanno aspettative non completamente realistiche su ciò che li aspetta. Molti pensano che ora scriveranno fantastici modelli di rete neurale, creeranno un assistente vocale come Iron Man o batteranno tutti sui mercati finanziari.
Ma il lavoro Dati di Scientist è legato ai dati, e uno dei momenti più importanti e dispendiosi in termini di tempo è la preparazione dei dati prima di presentarli a una rete neurale o di analizzarli in un certo modo.
In questo articolo, il nostro team descriverà come elaborare facilmente e rapidamente i dati con istruzioni passo passo e codice. Abbiamo cercato di rendere il codice abbastanza flessibile e applicabile a diversi set di dati.
Molti professionisti potrebbero non trovare nulla di straordinario in questo articolo, ma i principianti potranno raccogliere qualcosa di nuovo, e anche chi ha desiderato a lungo creare un notebook per una rapida e strutturata elaborazione dei dati può copiare il codice e adattarlo alle proprie esigenze, oppure
Abbiamo ottenuto il dataset. Cosa fare dopo?
Quindi, lo standard: è necessario comprendere con cosa abbiamo a che fare, avere una visione generale. Per questo utilizziamo pandas per identificare semplicemente 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 memorizziamo nella variabile df
df.head(3) #guardiamo le prime 3 righe per capire come appaiono i valori 
df.info() #Mostriamo informazioni sulle colonne 
Guardiamo i valori delle colonne:
- Corrisponde il numero di righe di ogni colonna al numero totale di righe?
- Qual è l'essenza dei dati in ogni colonna?
- Quale colonna vogliamo rendere target per fare previsioni su di essa?
Le risposte a queste domande ci permetteranno di analizzare il dataset e tracciare un piano delle prossime azioni.
Inoltre, per uno sguardo più approfondito sui valori di ogni colonna, possiamo utilizzare la funzione pandas describe(). Tuttavia, il difetto di questa funzione è che non fornisce informazioni su colonne con valori di tipo string. Ci occuperemo di ciò più tardi.
df.describe() 
Una visualizzazione magica
Diamo un'occhiata a dove mancano completamente i valori:
import seaborn as sns
sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis') 
È stata una piccola panoramica, adesso ci avventureremo in cose più interessanti
Cercheremo di trovare e, se possibile, rimuovere le colonne in cui c'è solo un valore in tutte le righe (non influenzeranno in alcun modo il risultato):
df = df[[c for c
in list(df)
if len(df[c].unique()) > 1]] #Riscriviamo il dataset, mantenendo solo quelle colonne in cui ci sono più di un valore unicoOra ci proteggiamo e proteggiamo il successo del nostro progetto da righe duplicate (righe che contengono le stesse informazioni nello stesso ordine di una delle righe esistenti):
df.drop_duplicates(inplace=True) #Facciamo questo, se lo consideriamo necessario.
#In alcuni progetti non è opportuno eliminare tali dati sin dall'inizio.Suddividiamo il dataset in due: uno con valori qualitativi e l'altro con valori quantitativi
Qui è necessario fare una piccola precisazione: se le righe con dati mancanti nei dati qualitativi e quantitativi non si correlano fortemente tra loro, sarà necessario decidere cosa dobbiamo sacrificare: tutte le righe con dati mancanti, solo una parte di esse o colonne specifiche. Se le righe si correlano, abbiamo il pieno diritto di separare il dataset in due. In caso contrario, sarà necessario prima affrontare le righe in cui i dati mancanti nei qualitativi e quantitativi non si correlano e solo dopo separare il dataset in due.
df_numerical = df.select_dtypes(include = [np.number])
df_categorical = df.select_dtypes(exclude = [np.number])Lo facciamo per facilitarci l'elaborazione di questi due diversi tipi di dati; in seguito comprenderemo quanto questo semplifichi la nostra vita.
Lavoriamo con i dati quantitativi
La prima cosa da fare è determinare se ci siano "colonne-spia" nei dati quantitativi. Chiamiamo queste colonne così perché si spacciano per dati quantitativi, mentre in realtà funzionano come qualitativi.
Come possiamo identificarli? Certo, tutto dipende dalla natura dei dati che stai analizzando, ma generalmente tali colonne possono contenere 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 numerici
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 qualitativiFinalmente abbiamo separato completamente i dati numerici da quelli qualitativi e ora possiamo lavorarci su come si deve. Prima di tutto, dobbiamo capire dove abbiamo valori mancanti (NaN, e in alcuni casi anche 0 saranno considerati come valori mancanti).
for i in df_numerical.columns:
print(i, df[i][df[i]==0].count())A questo punto è importante comprendere in quali colonne gli zeri possono significare valori mancanti: è collegato a come sono stati raccolti i dati? O potrebbe essere legato ai valori dei dati? Queste domande devono essere affrontate caso per caso.
Dunque, se abbiamo deciso che i dati possono essere assenti là dove ci sono zeri, è necessario sostituire gli zeri con NaN, per facilitare la gestione di 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') # Si può anche utilizzare df_numerical.info() 
Qui dovrebbero essere evidenziati in giallo quei valori all'interno delle colonne che mancano. 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 altri?
Ecco uno schema approssimativo che può aiutarti a decidere cosa fare con i valori mancanti:

0. Rimuoviamo le colonne non necessarie
df_numerical.drop(labels=["colonna1","colonna2"], axis=1, inplace=True)1. Il numero di valori mancanti in questa colonna supera il 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 mancanti2. Rimuoviamo le righe con valori mancanti
df_numerical.dropna(inplace=True)#Rimuoviamo le righe con valori vuoti, se poi saranno sufficienti dati per l'apprendimento3.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 tabella3.2. Inseriamo un valore costante
from sklearn.impute import SimpleImputer #importiamo SimpleImputer, che aiuterà a inserire i valori
imputer = SimpleImputer(strategy='constant', fill_value="") #inseriamo un valore specifico usando 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 valori precedenti3.3. Inseriamo la media o il valore più frequente
from sklearn.impute import SimpleImputer #importiamo SimpleImputer, che aiuterà a inserire i valori
imputer = SimpleImputer(strategy='mean', missing_values=np.nan) #invece di mean possiamo anche usare most_frequent
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 valori precedenti3.4. Inseriamo un valore calcolato da un altro modello
A volte i valori possono essere calcolati utilizzando modelli di regressione, impiegando modelli dalla libreria sklearn o altre librerie simili. Il nostro team dedicherà un articolo separato su come fare questo in un prossimo futuro.
Dunque, la narrazione sui dati quantitativi si interromperà qui, perché ci sono molte altre sfumature su come fare al meglio la preparazione e il preprocessing dei dati per differenti compiti, e le basi per i dati quantitativi sono state trattate in questo articolo. Ora è il momento di tornare ai dati qualitativi, che abbiamo separato alcuni passaggi fa dai dati quantitativi. Potete modificare questo notebook come preferite, adattandolo a diversi compiti, affinché il preprocessing dei dati avvenga molto rapidamente!
Dati qualitativi
Principalmente per i dati qualitativi viene utilizzato il metodo One-hot-encoding, per formattarli da string (o object) a numero. Prima di passare a questo punto, utilizziamo lo schema e il codice qui sopra per comprendere i valori mancanti.
df_categorical.nunique()sns.heatmap(df_categorical.isnull(), yticklabels=False, cbar=False, cmap='viridis') 
0. Rimuoviamo le colonne non necessarie
df_categorical.drop(labels=["colonna1", "colonna2"], axis=1, inplace=True)1. Il numero di valori mancanti in questa colonna supera il 50%?
print(df_categorical.isnull().sum() / df_numerical.shape[0] * 100)df_categorical.drop(labels=["colonna1", "colonna2"], axis=1, inplace=True) # Rimuoviamo se qualche colonna
# ha più del 50% di valori mancanti2. Rimuoviamo le righe con valori mancanti
df_categorical.dropna(inplace=True) # Rimuoviamo le righe con valori mancanti,
# se rimangono dati sufficienti per l'apprendimento3.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 gestito i valori mancanti nei dati qualitativi. Ora è il momento di effettuare il one-hot-encoding per i valori presenti nel vostro database. Questo metodo è molto utilizzato affinché il vostro 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 la separazione dei dati qualitativi e quantitativi: è ora di unirli di nuovo.
new_df = pd.concat([df_numerical, df_categorical], axis=1)Dopo aver unito i dataset in uno solo, alla fine possiamo utilizzare la trasformazione dei dati con MinMaxScaler dalla libreria sklearn. Questo porterà i nostri valori in un range da 0 a 1, il che aiuterà nell'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 tutto: reti neurali, algoritmi ML standard, ecc!
In questo articolo non abbiamo considerato il lavoro con i dati relativi alle serie temporali, poiché per tali dati è opportuno utilizzare tecniche di elaborazione leggermente diverse, a seconda del tuo compito. In futuro, il nostro team dedicherà a questo argomento un articolo separato e speriamo che possa portare qualcosa di interessante, nuovo e utile nella tua vita, proprio come questo.
Fonte: habr.com
