Python - La libreria pandas - Confronto con SQL

pandas logo

Come visto nell'articolo precedente, la libreria pandas vi permette di manipolare tabelle, file .csv o di Excel, in modo molto simile a come trattereste delle tabelle SQL, avendo solo sistemato python dal pacchetto Anaconda.

In questo piccolo tutorial vedremo diverse funzionalità di pandas paragonabili alle operazioni SQL che conoscete, dalla semplice SELECT di colonne a operazioni più complesse.
Come sempre, questi tutorial sono fatti per presentarvi possibili soluzioni ai vostri problemi di programmazione. Vi invitiamo a consultare direttamente la pagina ufficiale di pandas per ulteriori approfindimenti.

Il primo passo, tuttavia, sarà quello di crearsi un DataFrame di pandas ad hoc per questo tutorial.

import pandas as pd
import numpy as np

df = pd.DataFrame(columns=['ID','COLORS', 'VAL_NUM', 'JOBS'])
df['ID'] = ['id1', 'id2', 'id3', 'id4', 'id5']
df['COLORS'] = ['red', 'blue', 'blue', 'red', 'green']
df['VAL_NUM'] = [0.75, 1.0, 0.5, 2.0, 1.25]
df['JOBS'] = ['image analyst', 'computer engineer', 'data analyst', 'computer scientist', 'electrical engineer']

Adesso in df abbiamo una semplice tabella di prova con un campo di identificativi, due colonne di variabili categoriche ed una di variabili numeriche.

Vi riporto qui un elenco delle funzioni pandas che utilizzeremo nell'articolo:

  • copy()
  • groupby()
  • reset_index()
  • rename()
  • merge()




    SELECT

    In SQL, se avessimo una tabella simile a quella contenuta in df, per mostrare solo il contenuto delle colonne 'ID' e 'COLORS' dovremmo fare:

    SELECT 'ID', 'COLORS'
    FROM 'df'
    

    la stessa cosa possiamo ottenerla in pandas scrivendo:

    print df[['ID', 'COLORS']]
    

    ATTENZIONE: nel codice precedente è semplicemente stampato a video il contenuto. Se voleste immagazzinare il contenuto delle due colonne in un altro DataFrame dovete utilizzare la funzione copy() perchè l'assegnazione è fatta per riferimento, non per copia. Magari è un concetto già chiaro a voi lettori, ma può capitare a tutti di fare cappellate.

    # riferimento
    df_rif = df[['ID', 'COLORS']]
    # copia
    df_cop = df[['ID', 'COLORS']].copy()
    




    ORDER BY

    Altra operazione fondamentale nella manipolazione delle tabelle. Se volete ordinare un DataFrame pandas secondo un attributo vi basterà la funzione sort():

    print df.sort('VAL_NUM', ascending=False, inplace=False)
    

    Si ricorda che il parametro ascending, corrispettivo di ASC in SQL, è di default impostato a True, quindi l'ordinamento, se non specificato diversamente, sarà di tipo ascendente.

    Il parametro inplace è invece di default impostato a False. Così facendo, l'operazione di sort non modificherà direttamente df, ma restituirà un DataFrame ordinato secondo la colonna scelta. Se si volesse modificare direttamente df, il parametro inplace dovrebbe essere impostato a True.



    GROUP BY

    Immaginiamo che per ogni colore nella tabella, vogliamo sapere le occorrenze di questi all'interno di df. L'operazione è simile ad un GROUP BY in SQL:

    SELECT 'COLORS', COUNT(*)
    FROM 'DF'
    GROUP BY 'COLORS'
    

    Ecco come ce la possiamo cavare con pandas:

    print df.groupby('COLORS').size()
    

    Se poi volessimo salvare il risultato del groupby() in un nuovo DataFrame:

    df_colors = pd.DataFrame({'N': df.groupby('COLORS').size()}).reset_index()
    

    il metodo reset_index() richiamato dal DataFrame permette di reimpostare gli indici di default, altrimenti sarebbero utilizzati come indici i valori di COLORS. Il risultato del groupby è salvato nella colonna N.

    Così come per SQL, si possono calcolare statistiche più "complesse" come il valore massimo, minimo, la media, la somma, ecc...

    import numpy as np
    df_colors = pd.DataFrame(df.groupby('COLORS').agg({'ID': np.size, 'VAL_NUM': np.mean})).reset_index()
    
    # rinominiamo 'ID' con 'N' come nell'esempio precedente
    df_colors.rename(column={'ID': 'N'}, inplace=True)
    

    Come si vede dall'esempio, basta scegliere la giusta funzione da passare. Nel caso precedente sono entrambe funzioni di numpy.




    WHERE

    Come si può effettuare un semplice SELECT, allo stesso modo possiamo decidere le righe da selezionare secondo una regola. Mettiamo di nuovo a confronto SQL con pandas:

    SELECT *
    FROM df
    WHERE 'COLORS'='blue'
    


    print df[df['COLORS']=='blue']
    

    Quando scrivete df[...] pandas si aspetta che tra le parentesi quadre ci sia una lista di valori booleani, con dimensione compatibile con il numero di righe del DataFrame.

    Quello che verrà stampato a video saranno le righe del DataFrame per le quali è True la condizione espressa tra le parentesi quadre.

    Allo stesso modo si possono unire insieme più condizioni:

    SELECT *
    FROM df
    WHERE 'COLORS'='blue' AND 'VAL_NUM'<1
    


    print df[(df['COLORS']=='blue') && (df['VAL_NUM']<1)]
    

    Utilizzando le funzioni di manipolazione di stringhe di python, si possono ottenere risultati simili all'uso di LIKE in SQL:

    SELECT *
    FROM df
    WHERE JOBS LIKE '%engineer%'; 
    


    print df[df['JOBS'].str.contains('engineer')]
    




    JOIN

    Un'altra importante caratteristica di pandas è la possibilità di effettuare JOIN come in SQL tra tabelle che condividono attributi coerenti tra loro. Nel codice seguente andremo a creare un altro DataFrame da unire con il precedente.

    import pandas as pd
    import numpy as np
    
    df2 = pd.DataFrame(columns=['ID', 'NAME'])
    df2['ID'] = ['id1', 'id2', 'id3', 'id4', 'id5', 'id6', 'id7', 'id8']
    df2['NAME'] = ['Paul', 'Albert', 'Carl', 'Simon', 'Jack', 'Henry', 'Mark', 'Pete']
    
    # inner join
    print pd.merge(df,df2,on='ID',how='inner')
    
    # outer join
    print pd.merge(df,df2,on='ID',how='outer')
    
    

    La funzione merge() restituisce un DataFrame dato dalla JOIN di altri due DataFrame secondo una colonna indicata dal parametro on.
    Il parametro how specifica il tipo di join da effettuare. Oltre ai casi mostrati, accetta anche come valori 'left' e 'right' se si volesse fare un JOIN LEFT OUTER o RIGHT OUTER.

    Se si volesse effettuare una JOIN tra due DataFrame i cui attributi di riferimento hanno nome differente (poniamo ad esempio che l'attributo identificativo di df2 sia nella colonna IDEN), i parametri del merge() cambierebbero come mostrato di seguito:

    import pandas as pd
    import numpy as np
    
    df2 = pd.DataFrame(columns=['ID', 'NAME'])
    df2['IDEN'] = ['id1', 'id2', 'id3', 'id4', 'id5', 'id6', 'id7', 'id8']
    df2['NAME'] = ['Paul', 'Albert', 'Carl', 'Simon', 'Jack', 'Henry', 'Mark', 'Pete']
    
    # inner join
    print pd.merge(df,df2,left_on='ID',right_on='IDEN',how='inner')
    
    # outer join
    print pd.merge(df,df2,left_on='ID',right_on='IDEN',how='outer')
    
    




    BONUS TRACK!

    Con questo articolo volevo concludere per ora i tutorial su pandas, in attesa in futuro di una raccolta di tips and tricks per la libreria. Vi voglio lasciare però con un primo trucchetto piuttosto carino:

    ipotizziamo che dobbiate aggiungere al DataFrame df una nuova colonna il cui contenuto sarà la stringa 'OK' se il valore in 'VAL_NUM' è maggiore di 1, o la stringa 'NO' in caso contrario; python vi permette di definire una funzione ad hoc per lo scopo e di ri-applicarla su tutta una colonna del DataFrame.

    def add_new_column(n):
    	if n>1:
    		return 'OK'
    	else:
    		return 'NO'
    
    df['FLAG']=list(map(add_new_column,df['VAL_NUM'])
    
    

    La built-in function map applica la funzione passata come primo parametro all'oggetto iterabile passato come secondo parametro. Il risultato è poi trasformato in una lista e assegnato alla nuova colonna del DataFrame.

  • Alessio Antonielli

    Ingegnere informatico, appassionato di cinema, musica, videogiochi e serie tv. Insomma, le solite cose che vi aspettereste da un ex studente di Ingegneria Informatica, giusto per rafforzare lo stereotipo…

    Python - La libreria pandas - Confronto con SQL ultima modifica: 2016-02-16T12:30:55+00:00 da Alessio Antonielli


    Advertisment ad adsense adlogger