Una introduzione a Jupyter per l'analisi di dati

 


Siete stufi di usare Calc di Libreoffice o i vari cloni di Excel?


In questo articolo facciamo una breve introduzione all'uso delle librerie python che si usano nell'analisi di dati mostrando come fare interrogazioni su un file di nostro interesse.


Ci sono due strumenti particolarmente potenti che ci permettono di iniziare ad "andare oltre" il foglio di calcolo: la libreria pandas e jupyter notebooks (una sorta di elaboratore di testi che permette di fare calcoli all'interno del documento stesso).


Useremo Visual Studio Code perché integra tutto questo workflow con le sue estensioni (su Ubuntu lo possiamo installare come Snap con sudo snap install --classic code).

Ci posizioniamo in una nuova cartella (con Apri cartella) e creiamo un nuovo file con estensione .ipynb.

All'apertura di questo nuovo file Code ci chiederà di installare le estensioni python e jupyter che si occuperanno anche di scaricare le librerie python richieste (tramite il gestore di pacchetti pip).

Proviamo a giocare con un file interessante, i prezzi dei carburanti che si trovano sul portale open data del Ministero (su questa pagina).

Abbiamo visto che aprendo il nuovo file l'editor si è trasformato in "blocchi" che possiamo aggiungere e riordinare. Questo ci permette di eseguire anche indipendentemente i singoli blocchi senza eseguire tutte le volte tutto il programma, e ci torna utile se vogliamo fare più cose.

Intanto apriamo il terminale in basso dal menu Visualizza -> Terminale. Da questo andiamo ad installare altra roba che ci servirà


sudo apt-get install libsnappy-dev
pip3 install  pylint ipykernel python-snappy fastparquet pyarrow dask openpyxl


Primo esercizio: scarichiamo il file direttamente dal programma! Utilizziamo la libreria requests che permette di fare richieste http e salviamo il risultato in un file all'interno della cartella nella quale stiamo lavorando.


import requests
s= requests.get('https://www.mise.gov.it/images/exportCSV/prezzo_alle_8.csv')
open('prezzi.csv', 'wb').write(s.content)


A questo punto possiamo leggere il file all'interno di un "dataframe" (una struttura dati che assomiglia al foglio di calcolo a cui siamo abituati)


import pandas as pd
file='prezzi.csv'
df = pd.read_csv(file,low_memory=False, skiprows=[0], header=0, sep=';')


Abbiamo letto il file e salvato all'interno della variabile df il suo contenuto. I parametri che abbiamo utilizzato istruiscono la funzione a considerare il punto e virgola come separatore dei campi, a saltare la prima riga (se lo apriamo con gedit notiamo che nella prima riga c'è l'ora di estrazione che non ci serve) ed utilizzare la nuova prima riga come intestazione dei campi.


Una cosa che possiamo fare nel caso di lavorazioni su file di grandi dimensioni è convertire il file in un formato binario che ci permetterà di aprirlo più velocemente le prossime volte.


df.to_parquet('prezzi.parquet', engine='fastparquet')


Notiamo che nella cartella si è salvato il file ed è circa un terzo del file originale come dimensione.

Nelle letture successive lo apriremo semplicemente con il comando


df = pd.read_parquet('prezzi.parquet', engine='fastparquet')


In una nuova cella possiamo ad esempio vedere la struttura del dataframe con quante righe ci sono ed il tipo dei campi


df.info()


Oppure possiamo vedere le prime 5 righe


df.head()


A noi ci interessa fare una ricerca sul distributore più conveniente, però vediamo che qui c'è solo l'identificatore.

Dobbiamo ripetere la prima parte anche per il file dell'anagrafica e ci ritroviamo pertanto con due dataframe:


prezzi = pd.read_parquet('prezzi.parquet', engine='fastparquet')
anagrafica = pd.read_parquet('anagrafica.parquet', engine='fastparquet')


Li possiamo unire con la funzione merge (chi conosce SQL penserà alla join delle interrogazioni) sulla colonna idImpianto che è presente in entrambi i file:


merged = pd.merge(prezzi, anagrafica, on = ['idImpianto'], how = 'left')


Adesso cerchiamo tutti i distributori nel mio comune, per fare un filtro le istruzioni sono <variabile del dataframe> e poi tra quadre la condizione del filtro, nel caso sottostante diciamo di cercare nella colonna Comune del dataframe tutte le righe con valore GENOVA; il risultato lo salviamo nella variabile df1 e la mostriamo a video


df1 = merged[(merged['Comune'] == 'GENOVA')]
df1


Qual'è il prezzo migliore per la mia macchina a diesel? Posso filtrare ancora per il tipo di carburante e selezionare quello migliore, ordinando per prezzo ascendente e mostrando i primi 10.


df1[df1['descCarburante'] == 'Gasolio'].sort_values(by=["prezzo"], ascending=True).head(10)


Noto che il primo prezzo è un po' strano (troppo basso ed aggiornato più di una settimana fa), quindi metto una condizione in più guardando le date. Ma attensione: quando abbiamo letto il csv dei prezzi, la libreria ha capito che il campo dtComu è un oggetto, ma per noi deve essere una data altrimenti non possiamo giocarci, la possiamo trasformare semplicemente convertendo e sovrascrivendo la stessa colonna


df1['dtComu'] = pd.to_datetime(df1['dtComu'])


Consideriamo gli ultimi 7 giorni, quindi generiamo la data di 7 giorni fa e la convertiamo nello stesso formato della  nostra colonna

import datetime as dt
lastweek = dt.date.today() - dt.timedelta(days=7)
lastweek = pd.to_datetime(dt.date.today() - dt.timedelta(days=7))


E modifichiamo la selezione di prima inserendo la nuova condizione.


df1[(df1['descCarburante'] == 'Gasolio') & (df1['dtComu'] > lastweek)].sort_values(by=["prezzo"], ascending=True).head(10)


Vale la pena fare diversi chilometri per risparmiare 1 millesimo al litro? Una domanda alla quale si può rispondere sia con il buonsenso sia con Python, sta a noi decidere.

Adesso che abbiamo fatto la nostra prima ricerca possiamo allargarci con la documentazione di pandas e con altre librerie che ci permettono ad esempio di fare grafici.

Documentazione di Visual Studio Code sui notebook

Documentazione di Pandas

Questi post potrebbero interessarti

disqus

Licenza

Licenza Creative Commons

Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Non commerciale - Non opere derivate 4.0 Internazionale. Questo blog non rappresenta una testata giornalistica, in quanto viene aggiornato senza alcuna periodicità. Non può, pertanto, considerarsi un prodotto editoriale, ai sensi della legge n. 62 del 7/03/2001.

Disclaimer immagini Le immagini utilizzate in questo blog appartengono ai loro rispettivi autori e sono utilizzati per scopi educativi, personali e senza scopo di lucro. Ogni eventuale violazione del copyright non è intenzionale, ma se si riconosce un'immagine protetta da copyright, fatemelo sapere qui, e sarò lieto di aggiungere i credits o modificarla o rimuoverla.

Disclaimer images Images used on this blog belong to their respective authors and are used for educational, personal and no profit purposes. Any eventual copyright infringement is not intentional, but if you recognize a copyrighted image, please let me know here, and I'll happily provide to add the right credits or modify or remove it.