Vai al contenuto principale
Python
Data Science
Data Visualization
Analisi dei dati

Tutorial: analisi delle serie temporali con Python

Ottieni i dati di Google Trends per keyword come "diet" e "gym" e osserva come variano nel tempo mentre impari trend e stagionalità nelle serie temporali.
Hugo Bowne-Anderson's photo
Hugo Bowne-Anderson
Aggiornato · 15 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

Crea il tuo account gratuito

Pratica and corso your progress.

Continua Con Google
Continuando, accetti i nostri Termini di utilizzo, la nostra Informativa sulla privacy e che i tuoi dati siano conservati negli Stati Uniti.

Nella sessione Facebook Live del 4 gennaio, abbiamo esaminato i dati di Google Trends per le keyword "diet", "gym" e "finance" per vedere come variano nel tempo. Ci siamo chiesti se a gennaio, quando tutti cerchiamo di ricominciare da capo, ci fossero più ricerche per questi termini.

In questo tutorial, ripercorrerai passo dopo passo il codice che abbiamo messo insieme durante la sessione. Non farai molta matematica: l'enfasi sarà tutta sull'esplorazione visiva del dataset in questione.


Per approfondire pandas, dai un'occhiata al percorso Data Manipulation with Python di DataCamp. Per saperne di più sulle serie temporali con pandas, vedi il corso Manipulating Time Series Data in Python.

Importazione di pacchetti e dati

Resta quindi la domanda: a gennaio, quando tutti cerchiamo di ricominciare da capo, potrebbero esserci più ricerche per questi termini?

Scopriamolo andando qui e controllando i dati. Nota che questo tutorial è ispirato a questo articolo di FiveThirtyEight.

Puoi anche scaricare i dati in formato .csv, salvarli su file e importarli nel tuo ambiente Python per eseguire la tua analisi. Lo farai adesso. Andiamo!

Per iniziare, importerai alcuni pacchetti: in questo caso userai numpy, pandas, matplotlib e seaborn.

Inoltre, se vuoi che le immagini vengano visualizzate nel Jupyter Notebook, puoi usare la magic di IPython aggiungendo %matplotlib inline al tuo codice. In alternativa, puoi passare ai default di Seaborn con sns.set():

# Import packages
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set()

Importa i dati che hai scaricato con .read_csv() e visualizza le prime righe con .head().

Nota che aggiungi l'argomento skiprows per saltare la prima riga all'inizio del file.

 df = pd.read_csv('data/multiTimeline.csv', skiprows=1)
df.head()
  Month diet: (Worldwide) gym: (Worldwide) finance: (Worldwide)
0 2004-01 100 31 48
1 2004-02 75 26 49
2 2004-03 67 24 47
3 2004-04 70 22 48
4 2004-05 72 22 43

Puoi anche usare il metodo .info() per controllare i tipi di dato, il numero di righe e altro ancora:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 168 entries, 0 to 167
Data columns (total 4 columns):
Month                   168 non-null object
diet: (Worldwide)       168 non-null int64
gym: (Worldwide)        168 non-null int64
finance: (Worldwide)    168 non-null int64
dtypes: int64(3), object(1)
memory usage: 5.3+ KB

Ora che hai importato i tuoi dati da Google Trends e dato un'occhiata veloce, è il momento di sistemarli e portarli nella forma che desideri per prepararli all'analisi.

Pulisci e prepara i dati

La prima cosa da fare è rinominare le colonne del tuo DataFrame df in modo che non contengano spazi. Ci sono vari modi per farlo, ma per ora riassegnerai a df.columns un elenco con i nomi che vuoi dare alle colonne.

Ricontrolla il risultato della riassegnazione chiamando df.head():

df.columns = ['month', 'diet', 'gym', 'finance']
df.head()
  month diet gym finance
0 2004-01 100 31 48
1 2004-02 75 26 49
2 2004-03 67 24 47
3 2004-04 70 22 48
4 2004-05 72 22 43

Successivamente, trasformerai la colonna 'month' in un tipo DateTime e la imposterai come indice del DataFrame.

Nota che lo fai perché dal risultato del metodo .info() hai visto che la colonna 'Month' era in realtà di tipo object. Questo tipo generico racchiude di tutto, dalle stringhe agli interi, ecc. Non è esattamente quello che vuoi quando lavori con dati di serie temporali. Per questo userai .to_datetime() per convertire la colonna 'month' del tuo DataFrame in un DateTime.

Attenzione! Assicurati di includere l'argomento inplace quando imposti l'indice del DataFrame df in modo da modificare effettivamente l'indice originale e impostarlo sulla colonna 'month'.

df.month = pd.to_datetime(df.month)
df.set_index('month', inplace=True)
df.head()
  diet gym finance
month      
2004-01-01 100 31 48
2004-02-01 75 26 49
2004-03-01 67 24 47
2004-04-01 70 22 48
2004-05-01 72 22 43

Ora è il momento di esplorare visivamente il tuo DataFrame.

Un po' di Exploratory Data Analysis (EDA)

Puoi usare il metodo di visualizzazione integrato di pandas .plot() per tracciare i dati come 3 grafici a linee in un'unica figura (uno per ciascuna colonna, ovvero 'diet', 'gym' e 'finance').

Nota che puoi anche specificare alcuni argomenti di questo metodo, come figsize, linewidth e fontsize per impostare rispettivamente dimensione della figura, spessore delle linee e dimensione dei caratteri del grafico.

Inoltre, noterai che ciò che vedi sull'asse x non sono i mesi, come suggerisce l'etichetta predefinita, ma gli anni. Per rendere il grafico un po' più accurato, specificherai l'etichetta sull'asse x come 'Year' e imposterai anche la dimensione del font a 20.

Suggerimento: se vuoi sopprimere l'output di Matplotlib, aggiungi semplicemente un punto e virgola ; all'ultima riga di codice!

df.plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico a linee con pandas

Nota che questi dati sono relativi. Come si legge su Google Trends:

I numeri rappresentano l'interesse di ricerca relativo al punto più alto del grafico per l'area e il periodo indicati. Un valore di 100 è il picco di popolarità del termine. Un valore di 50 significa che il termine è popolare la metà. Allo stesso modo, un punteggio di 0 significa che il termine è stato meno dell'1% popolare rispetto al picco.

Se vuoi, puoi anche tracciare la sola colonna 'diet' come serie temporale:

df[['diet']].plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale con pandas

Nota: la prima cosa da notare è la stagionalità: ogni gennaio c'è un grande balzo. Inoltre, sembra esserci una tendenza: pare salire leggermente, poi scendere, poi risalire e poi ridiscendere. In altre parole, queste serie temporali sembrano avere componenti di trend e stagionali.

Tenendo questo a mente, imparerai come identificare i trend nelle tue serie temporali!

Trend e stagionalità nei dati di serie temporali

Identificare i trend nelle serie temporali

Ci sono diversi modi per identificare i trend nelle serie temporali. Un modo comune è calcolare una media mobile, cioè, per ogni punto temporale, calcolare la media dei punti che lo circondano. Il numero di punti è specificato da una ampiezza della finestra, che devi scegliere.

Poiché prendi la media, questo tende a smussare il rumore e la stagionalità. Ecco un esempio: guarda questa media mobile di 'diet' usando i metodi integrati di pandas.

Per scegliere l'ampiezza della finestra, qui ha senso provare prima dodici mesi, dato che stai parlando di stagionalità annuale.

diet = df[['diet']]
diet.rolling(12).mean().plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale

Nota che nel blocco di codice sopra hai usato due coppie di parentesi quadre per estrarre la colonna 'diet' come DataFrame; se avessi usato una sola coppia, come df['diet'], avresti creato una Series di pandas.

Nel blocco di codice qui sopra, hai anche concatenato metodi: hai chiamato metodi su un oggetto uno dopo l'altro. Il method chaining è piuttosto diffuso e pandas è uno dei pacchetti che permette davvero di usare al massimo questo stile di programmazione!

Ora hai il trend che cercavi! Hai rimosso gran parte della stagionalità rispetto al grafico precedente.

Puoi anche tracciare la media mobile di 'gym' usando i metodi integrati di pandas con la stessa finestra usata per i dati di 'diet':

gym = df[['gym']]
gym.rolling(12).mean().plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale 2

Hai rimosso con successo la stagionalità e vedi un trend crescente per "gym"! Ma come si confrontano questi due termini di ricerca?

Puoi capirlo tracciando i trend di 'gym' e 'diet' nella stessa figura:

df_rm = pd.concat([diet.rolling(12).mean(), gym.rolling(12).mean()], axis=1)
df_rm.plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale 3

Hai creato un nuovo DataFrame df_rm con due colonne contenenti la media mobile di 'diet' e 'gym'. Hai usato la funzione pd.concat(), che prende un elenco di colonne come primo argomento e, poiché vuoi concatenarle come colonne, hai aggiunto anche l'argomento axis impostato a 1.

Poi hai tracciato il DataFrame con il metodo plot(), proprio come prima! Dunque, rimuovendo la stagionalità, vedi che diet ha potenzialmente una qualche forma di stagionalità, mentre gym è in crescita!

Identificati i trend nei dati, è il momento di pensare alla stagionalità, ovvero la natura ripetitiva della serie temporale. Come hai visto all'inizio del tutorial, sembravano esserci sia componenti di trend sia componenti stagionali.

Pattern stagionali nei dati di serie temporali

Un modo per ragionare sulle componenti stagionali è rimuovere il trend da una serie temporale, così da indagare più facilmente la stagionalità. Per rimuovere il trend, puoi sottrarre il trend calcolato sopra (media mobile) dal segnale originale. Tuttavia, questo dipenderà da quanti punti hai mediato.

Un altro modo per rimuovere il trend è la "differenziazione", in cui guardi la differenza tra punti dati successivi (chiamata "differenziazione di primo ordine", perché consideri la differenza tra un punto e quello che lo precede).

Differenziazione di primo ordine

Puoi usare pandas e i metodi diff() e plot() per calcolare e tracciare la differenza di primo ordine della Series 'diet':

diet.diff().plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale 3

Vedi che hai rimosso gran parte del trend e puoi davvero scorgere i picchi di gennaio ogni anno. Ogni gennaio c'è un enorme picco di 20 o più punti percentuali sull'elemento di ricerca più alto che hai visto!

Nota: puoi anche eseguire la differenziazione di 2° ordine, ossia guardare la differenza tra un punto e i due che lo precedono, se il trend non è ancora completamente rimosso. Vedi qui per maggiori informazioni sulla differenziazione.

La differenziazione è molto utile per trasformare la tua serie temporale in una serie stazionaria. Senza entrare troppo nel dettaglio, una serie stazionaria è una serie le cui proprietà statistiche (come media e varianza) non cambiano nel tempo. Queste serie sono utili perché molti metodi di forecasting per serie temporali si basano sull'assunzione che la serie sia approssimativamente stazionaria.

Con tutto questo a disposizione, ora analizzerai la periodicità nella tua serie temporale guardando la sua funzione di autocorrelazione. Ma prima, faremo una breve deviazione sulla correlazione.

Periodicità e autocorrelazione

Una serie temporale è periodica se si ripete a intervalli equidistanti, ad esempio ogni 12 mesi.

Un altro modo di vederla è: se la serie ha un picco in un punto, allora avrà un picco 12 mesi dopo; se ha un minimo in un punto, avrà un minimo 12 mesi dopo.

Ancora un altro modo di pensarci è che la serie temporale è correlata con se stessa traslata di 12 mesi. Ciò significa che, se sposti la serie di 12 mesi avanti o indietro, in qualche modo si sovrappone a se stessa.

Considerare la correlazione di una serie con una versione traslata di se stessa è proprio il concetto di autocorrelazione.

Ci arriverai tra un attimo.

Per prima cosa, rinfreschiamoci la memoria sulla correlazione e adottiamo un approccio intuitivo al concetto!

Il coefficiente di correlazione tra due variabili cattura quanto sono linearmente correlate. Per capirlo, guarderai un esempio pratico con l'aiuto del dataset iris, che contiene misurazioni di fiori.

Per studiarlo più nel dettaglio, importerai il dataset iris da scikit-learn, lo trasformerai in un DataFrame e ne visualizzerai le prime righe con .head():

from sklearn import datasets
iris = datasets.load_iris()
df_iris = pd.DataFrame(data= np.c_[iris['data'], iris['target']],
                     columns= iris['feature_names'] + ['target'])
df_iris.head()
  sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target
0 5.1 3.5 1.4 0.2 0.0
1 4.9 3.0 1.4 0.2 0.0
2 4.7 3.2 1.3 0.2 0.0
3 4.6 3.1 1.5 0.2 0.0
4 5.0 3.6 1.4 0.2 0.0

Per capire questo dataset, ricorda che tutti i fiori hanno un sepalo e un petalo. Il sepalo racchiude i petali ed è tipicamente verde e simile a una foglia, mentre i petali sono solitamente colorati. La colonna 'target', che è la variabile target, è la specie dei fiori di iris, che può essere Versicolor, Virginica o Setosa. Nella tabella sopra, sono codificate come 0, 1 e 2.

Ora, per ragionare sulla correlazione, osserverai come la lunghezza del sepalo dei fiori di iris è correlata con la larghezza del sepalo. Per farlo, userai pandas o seaborn per costruire uno scatter plot di 'sepal length' contro 'sepal width':

sns.lmplot(x='sepal length (cm)', y='sepal width (cm)', fit_reg=False, data=df_iris);

grafico di correlazione

Nota che hai disattivato la regressione lineare impostando l'argomento fit_reg a False.

La lunghezza e la larghezza del sepalo sono positivamente o negativamente correlate su tutti i fiori? E all'interno di ciascuna specie sono positivamente o negativamente correlate? Questa è una distinzione essenziale.

Ricorda che nel primo caso, se la lunghezza del sepalo aumenta, anche la larghezza del sepalo aumenta in modo lineare. Nel secondo caso, se la lunghezza del sepalo aumenta, la larghezza del sepalo diminuisce in modo lineare.

A prima vista, nel grafico sopra sembra esserci una correlazione negativa: all'aumentare della lunghezza del sepalo, la larghezza del sepalo diminuisce leggermente.

Ora costruiamo uno scatter plot di 'sepal length' contro 'sepal width', colorato in base al target (species):

sns.lmplot(x='sepal length (cm)', y='sepal width (cm)', fit_reg=False, data=df_iris, hue='target');

grafico di correlazione 2

A prima vista, sembra che il grafico sopra mostri una correlazione positiva: per ogni specie di iris, quando la lunghezza del sepalo aumenta, anche la larghezza del sepalo aumenta.

Le visualizzazioni sono ottime per farsi un'intuizione sulla correlazione, ma per approfondire puoi calcolare effettivamente un coefficiente di correlazione.

Puoi calcolare i coefficienti di correlazione di ogni coppia di misurazioni con il metodo .corr():

df_iris.corr()
  sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target
sepal length (cm) 1.000000 -0.109369 0.871754 0.817954 0.782561
sepal width (cm) -0.109369 1.000000 -0.420516 -0.356544 -0.419446
petal length (cm) 0.871754 -0.420516 1.000000 0.962757 0.949043
petal width (cm) 0.817954 -0.356544 0.962757 1.000000 0.956464
target 0.782561 -0.419446 0.949043 0.956464 1.000000

Nota che "sepal length (cm)" e "sepal width (cm)" sembrano essere negativamente correlati! E lo sono, sull'intera popolazione di fiori misurati. Vedi che il coefficiente di correlazione è -0,1. Tuttavia, non sono negativamente correlati all'interno di ciascuna specie, dato che il coefficiente è 0,78.

Per chi fosse interessato, questo è noto come paradosso di Simpson ed è fondamentale quando si pensa all'inferenza causale. Puoi leggere di più qui.

Esploriamo ancora. Calcoliamo i coefficienti di correlazione di ogni coppia di misure all'interno di ciascuna specie. Il modo per farlo è concatenare i metodi .groupby() e .corr(), raggruppare per target e stampare il coefficiente di correlazione:

df_iris.groupby(['target']).corr()
    petal length (cm) petal width (cm) sepal length (cm) sepal width (cm)
target          
0.0 petal length (cm) 1.000000 0.306308 0.263874 0.176695
petal width (cm) 0.306308 1.000000 0.279092 0.279973
sepal length (cm) 0.263874 0.279092 1.000000 0.746780
sepal width (cm) 0.176695 0.279973 0.746780 1.000000
1.0 petal length (cm) 1.000000 0.786668 0.754049 0.560522
petal width (cm) 0.786668 1.000000 0.546461 0.663999
sepal length (cm) 0.754049 0.546461 1.000000 0.525911
sepal width (cm) 0.560522 0.663999 0.525911 1.000000
2.0 petal length (cm) 1.000000 0.322108 0.864225 0.401045
petal width (cm) 0.322108 1.000000 0.281108 0.537728
sepal length (cm) 0.864225 0.281108 1.000000 0.457228
sepal width (cm) 0.401045 0.537728 0.457228 1.000000

In questa matrice di correlazione puoi vedere che:

  • Per il target 0, lunghezza e larghezza del sepalo hanno una correlazione di 0,75;
  • Per il target 1, hai un coefficiente di 0,5; e
  • Per il target 2, ottieni una correlazione di 0,46.

Si tratta tutte di correlazioni positive in diminuzione, ma sono tutte molto più positive rispetto alla correlazione negativa originale.

Questo è estremamente istruttivo ed è un chiaro promemoria dell'importanza di analizzare a fondo i dati.

Ora che hai dato un'occhiata più da vicino alla correlazione, sei pronto per analizzare la periodicità nella tua serie temporale guardando la sua funzione di autocorrelazione!

Per cominciare, traccia di nuovo tutte le tue serie temporali per ricordarti come appaiono:

df.plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale 4

Poi calcola i coefficienti di correlazione di tutte queste serie temporali con .corr():

df.corr()
  diet gym finance
diet 1.000000 -0.100764 -0.034639
gym -0.100764 1.000000 -0.284279
finance -0.034639 -0.284279 1.000000

Che cosa ti dice quanto sopra?

Concentriamoci su 'diet' e 'gym': sono negativamente correlati. Molto interessante! Ricorda che hai una componente stagionale e una di trend. Dal coefficiente di correlazione, "diet" e "gym" sono negativamente correlati. Tuttavia, guardando le serie temporali, sembra che le loro componenti stagionali siano positivamente correlate e i loro trend negativamente correlati.

Il coefficiente di correlazione sta infatti catturando entrambe queste componenti.

Quello che vuoi fare ora è tracciare le differenze di primo ordine di queste serie temporali e poi calcolarne la correlazione, perché quella sarà approssimativamente la correlazione delle componenti stagionali. Ricorda che rimuovere il trend può rivelare correlazioni nella stagionalità.

Inizia tracciando le differenze di primo ordine con .diff() e .plot():

df.diff().plot(figsize=(20,10), linewidth=5, fontsize=20)
plt.xlabel('Year', fontsize=20);

grafico serie temporale 5

Vedi che 'diet' e 'gym' sono incredibilmente correlati una volta rimosso il trend. Ora calcolerai i coefficienti di correlazione delle differenze di primo ordine di queste serie temporali:

df.diff().corr()
  diet gym finance
diet 1.000000 0.758707 0.373828
gym 0.758707 1.000000 0.301111
finance 0.373828 0.301111 1.000000

Nota che ancora una volta c'era una lieve correlazione negativa quando consideravi insieme trend e componente stagionale. Ora vedi che sulla componente stagionale 'diet' e 'gym' sono altamente correlati, con un coefficiente di 0,76.

Autocorrelazione

Ora che hai approfondito la correlazione tra variabili e tra serie temporali, è il momento di tracciare l'autocorrelazione della serie 'diet': sull'asse x hai il lag e sull'asse y quanto la serie è correlata con se stessa a quel lag.

Quindi, se la serie originale si ripete ogni due giorni, ti aspetteresti un picco nella funzione di autocorrelazione a 2 giorni.

Qui guarderai il grafico e ciò che dovresti aspettarti è un picco nella funzione di autocorrelazione a 12 mesi: la serie è correlata con se stessa traslata di dodici mesi.

Usa l'interfaccia di pandas per il plotting, che ha la funzione autocorrelation_plot(). Puoi usarla per tracciare la serie 'diet':

pd.plotting.autocorrelation_plot(diet);

grafico di autocorrelazione

Se includessi più lag negli assi, vedresti che è a 12 mesi che hai questo enorme picco di correlazione. Hai un altro picco a 24 mesi, dove è di nuovo correlata con se stessa. Ce n'è un altro a 36, ma man mano che ti allontani, la correlazione diminuisce.

Ovviamente, hai una correlazione della serie con se stessa a lag 0.

Le linee tratteggiate nel grafico sopra indicano la significatività statistica della correlazione. In questo caso, puoi dire che la serie 'diet' è realmente autocorrelata con un lag di dodici mesi.

Hai identificato la stagionalità di questa ripetizione a 12 mesi!

Conclusione

In questo tutorial abbiamo coperto molto! Hai esaminato i dati di Google Trends per le keyword "diet", "gym" e dato una veloce occhiata a "finance" per vedere come variano nel tempo. Hai affrontato concetti come stagionalità, trend, correlazione, autocorrelazione, ...

Per chi ha voglia di approfondire subito, ci sono due cose che puoi fare:

Argomenti
Python
Data Science
Data Visualization
Analisi dei dati

Scopri di più su Python

Corso

Analisi delle serie temporali in Python

4 ore
70.9K
In questo corso di quattro ore imparerai le basi dell'analisi dei dati delle serie temporali in Python.
Vedi i dettagliInizia Il Corso

Crea il tuo account gratuito

Pratica and corso your progress.

Continua Con Google
Continuando, accetti i nostri Termini di utilizzo, la nostra Informativa sulla privacy e che i tuoi dati siano conservati negli Stati Uniti.
Mostra altro
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

Mostra altro