  {"id":1496,"date":"2019-12-28T13:42:24","date_gmt":"2019-12-28T12:42:24","guid":{"rendered":"https:\/\/www.gironi.it\/blog\/?p=1496"},"modified":"2026-06-18T14:21:29","modified_gmt":"2026-06-18T13:21:29","slug":"analisi-delle-serie-storiche0-e-previsioni-di-serie-temporali-in-r-con-il-metodo-holt-winters","status":"publish","type":"post","link":"https:\/\/www.gironi.it\/blog\/analisi-delle-serie-storiche0-e-previsioni-di-serie-temporali-in-r-con-il-metodo-holt-winters\/","title":{"rendered":"Analisi delle serie storiche e previsioni di serie temporali in R"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Cosa si intende per serie storica, o serie temporale<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Una <strong>serie storica<\/strong> consta dei valori osservati in un insieme di periodi ordinati sequenzialmente.  <strong>Questo, per chi fa SEO, \u00e8 gi\u00e0 un elemento del massimo interesse<\/strong>.       <\/p>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><strong>I dati di traffico del nostro sito web, considerati lungo una sequenza temporale, sono infatti un esempio di serie storica. <\/strong>            <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L&#8217;analisi delle serie storiche \u00e8 un insieme di metodi che ci consentono di ricavare schemi o statistiche significative dai dati con informazioni temporali.<\/p>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\">In termini molto generali, possiamo dire che <strong>una serie temporale \u00e8 una sequenza di variabili casuali indicizzate nel tempo<\/strong>.       <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lo scopo dell&#8217;analisi di una serie storica pu\u00f2 essere di tipo <strong>descrittivo<\/strong> (si pensi alla decomposizione della serie per rimuovere elementi di stagionalit\u00e0 o per evidenziare tendenze di fondo) oppure <strong>inferenziale<\/strong>, includendo in quest&#8217;ultimo la previsione dei valori per periodi di tempo futuri, ancora non occorsi (<em>forecasting<\/em>).             <\/p>\n\n\n\n<!--more-->\n\n\n\n<div style=\"border:1px solid #ccc;padding:1.2em 1.5em;margin:1.5em 0;border-radius:6px\">\n<h3 style=\"margin-top:0\">Di cosa parleremo<\/h3>\n<ul>\n<li><a href=\"#teoria-decomposizione\">Un po&#8217; di teoria: la decomposizione di una serie storica<\/a><\/li>\n<li><a href=\"#creare-serie-r\">Creare una serie temporale in R<\/a><\/li>\n<li><a href=\"#disegnare-serie\">Disegnare una o pi\u00f9 serie storiche<\/a><\/li>\n<li><a href=\"#smoothing\">Tecniche di lisciamento (smoothing)<\/a><\/li>\n<li><a href=\"#esempio-seo-ga4\">Un esempio SEO: da Google Analytics 4 alla serie storica<\/a><\/li>\n<li><a href=\"#seasonal-plot\">Il seasonal plot: la stagionalit\u00e0 a colpo d&#8217;occhio<\/a><\/li>\n<li><a href=\"#holt-winters\">Livellamento esponenziale con Holt-Winters e previsione<\/a><\/li>\n<li><a href=\"#arima\">Indagare le serie storiche con i modelli ARIMA<\/a><\/li>\n<li><a href=\"#arima-esempio\">Un esempio pratico di modello ARIMA<\/a><\/li>\n<li><a href=\"#prova-tu\">Prova tu<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"teoria-decomposizione\">Un po&#8217; di teoria. L&#8217;analisi classica delle serie temporali. La decomposizione di una serie storica.<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"> Il metodo classico di analisi delle serie storiche individua quattro influenze, o <strong>componenti<\/strong>:             <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li> <strong>Trend (T) <\/strong>:<strong> <\/strong>il movimento generale a lungo termine dei valori (Y) della serie storica, in un periodo di tempo ampio.                 <\/li>\n\n\n\n<li> <strong>Fluttuazioni cicliche (C) <\/strong>: movimenti ricorrenti di lunga durata.                 <\/li>\n\n\n\n<li> <strong>Variazioni stagionali (S) <\/strong>: fluttuazioni dovute al particolare periodo dell&#8217;anno, ad esempio la stagione estiva rispetto ai mesi invernali.                 <\/li>\n\n\n\n<li> <strong>Movimenti erratici o irregolari (I)<\/strong> : deviazioni irregolari dalla tendenza, che non possono essere ascritte a influenze cicliche oppure stagionali.                 <\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Secondo il modello dell&#8217;analisi classica delle serie storiche, il valore della variabile in ogni periodo \u00e8 determinato dalle influenze delle quattro componenti.     <\/strong>        <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lo scopo principale dell&#8217;analisi classica delle serie temporali \u00e8 proprio quello di <strong>scomporre la serie<\/strong>, per isolare le influenze delle varie componenti che determinano i valori della serie storica.             <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Le quattro componenti &#8220;classiche&#8221; e il loro legame<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Le quattro componenti possono essere tra loro legate <strong>in modo additivo:<\/strong>             <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\n<strong>Y = T + C + S + I<\/strong>\n            <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"> ovvero in modo <strong>moltiplicativo:<\/strong>             <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\n<strong>Y = T x C x S x I<\/strong>\n            <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ricordo che un modello moltiplicativo pu\u00f2 essere trasformato nel modello additivo sfruttando le propriet\u00e0 dei logaritmi:             <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"> <strong>log(Y) = log(T) + log(C) + log(S) + log(I)<\/strong>             <\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Un breve ripasso: le utili propriet\u00e0 dei logaritmi<\/h3>\n\n\n\n<p class=\"has-background has-light-gray-background-color\">\nIl logaritmo di un numero <i>n<\/i> nella base <i>c<\/i> (con c diverso da 1 e c &gt;0) \u00e8 l&#8217;esponente al quale \u00e8 necessario elevare la base <i>c<\/i> per ottenere <i>n<\/i>.<br><br>Dunque, se n = c<sup>b<\/sup> allora log<sub>c<\/sub> n = b\n<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Quando si moltiplicano tra loro dei numeri, il logaritmo del loro prodotto \u00e8 la somma dei loro logaritmi.<\/li>\n\n\n\n<li>Il logaritmo di una frazione \u00e8 il logaritmo del numeratore meno il logaritmo del denominatore.<\/li>\n\n\n\n<li>Il logaritmo di un numero con esponente \u00e8 il logaritmo moltiplicato per l&#8217;esponente del numero.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"creare-serie-r\">Creare una serie temporale in R partendo da un vettore o un data frame<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Esistono vari modi per trasformare un vettore di dati, una matrice oppure un data frame in una serie temporale.<br>In questa sede ci limiteremo agli strumenti offerti, per ottenere tale risultato, dal pacchetto base R.<br>La funzione di nostro interesse si chiama semplicemente <strong>ts()<\/strong> ed ha un utilizzo piuttosto intuitivo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vediamo un esempio pratico. Supponiamo di avere un vettore di dati salvato con il nome mieidati.csv nella cartella \/home del mio pc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La prima cosa che far\u00f2, sar\u00e0 quella di importare in R i miei dati che ipotizzo presenti in un file csv:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong># importo i dati da file csv in un dataframe<\/strong><br>dfmieidati &lt;- read.csv(\"\/home\/mieidati.csv\")<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong># creo un vettore con i dati che mi interessano<\/strong><br>mieidati &lt;- dfmieidati$miaosservazione<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ora non mi resta che invocare la funzione ts() con gli opportuni valori di inizio e di frequenza per creare la mia serie temporale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ipotizziamo che i dati siano mensili e comincino con gennaio 2012 e vadano fino a dicembre 2018:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">serietemporale &lt;- ts(mieidati, start=c(2012,1), end=c(2018,12), frequency=12)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">come si vede la forma tipica della funzione ts() \u00e8 <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ts(vettore, inizio, fine, frequenza) <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">dove per <strong>frequenza si intende il numero di osservazioni per unit\u00e0 di tempo<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Quindi avremo 1= annuale, 4=trimestrale, 12=mensile\u2026<\/strong><br><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Utili funzioni relative a una serie temporale<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Posso facilmente conoscere il tempo della prima osservazione di una serie storica usando il comando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">start()<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Analogamente, posso trovare l\u2019ultima osservazione con:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">end()<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Il comando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">frequency()<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">mi restituisce il numero delle osservazioni per unit\u00e0 di tempo, mentre l\u2019utilissimo comando<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">window()<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">consente di estrarre un sottoinsieme di dati. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Usando a mo&#8217; d&#8217;esempio un dataset compreso in R chiamato <em>Nile<\/em> contenente 100 letture annuali del fiume Nilo ad Aswan per gli anni dal 1871 al 1970 (lo useremo anche nel paragrafo che segue) il comando si presenta cos\u00ec:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">nile_sub &lt;- window(Nile, start=1940,end=1960)<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"disegnare-serie\">Disegnare una o pi\u00f9 serie storiche<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Uno dei vantaggi nell\u2019uso delle serie temporali \u00e8 rappresentato dalla semplicit\u00e0 nella rappresentazione grafica. Usando il dataset di esempio <em><strong>Nile<\/strong><\/em> presente in R, che \u00e8 gi\u00e0 un oggetto serie temporale \u2013 e posso verificarlo con il comando <strong>is.ts(Nile)<\/strong> -, mi baster\u00e0 il comando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">plot.ts(Nile)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">per avere un grafico dell\u2019andamento nel tempo della mia variabile. Ovviamente posso usare i vari attributi <em>xlab<\/em>, <em>ylab<\/em>,<em>main<\/em> ecc&#8230; per rendere ancora pi\u00f9 significativo e chiaro il mio grafico:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">plot(Nile, xlab=\"Anno\", ylab=\"Flusso annuale del fiume Nilo\", main=\"Serie Storica di esempio Nilo\")<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/nilo-esempio.png\" alt=\"serie storica di esempio: Nile\" class=\"wp-image-1747\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/nilo-esempio.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/nilo-esempio-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">plot della serie storica Nile<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Se il dataset contiene pi\u00f9 di un oggetto serie temporale, potr\u00f2 ottenere il grafico dei vari oggetti.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Usiamo un altro dataset di esempio presente in R chiamato <em>EuStockMarkets<\/em> che contiene, come si pu\u00f2 facilmente immaginare, le quotazioni dei listini FTSE, CAC, DAX e SMI :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">plot(EuStockMarkets, plot.type = \"multiple\")<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-multiple.png\" alt=\"Plot di pi\u00f9 oggetti temporali - esempio\" class=\"wp-image-1748\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-multiple.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-multiple-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">Plot di pi\u00f9 oggetti temporali<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Oppure potr\u00f2 disegnare i vari oggetti serie temporale tutti insieme \u2013 con colori differenti \u2013 nello stesso grafico:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">plot.ts(EuStockMarkets, plot.type = \"single\", col=c(\"red\",\"black\",\"blue\",\"green\"))<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-insieme.png\" alt=\"Plot di pi\u00f9 oggetti temporali nello stesso grafico - esempio\" class=\"wp-image-1750\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-insieme.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/eustockmarkets-insieme-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">Plot di pi\u00f9 oggetti temporali nello stesso grafico<\/figcaption><\/figure>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"smoothing\">Tecniche di lisciamento (<em>smoothing<\/em>)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Se andiamo a rappresentare graficamente una serie temporale, noteremo quasi sempre tutta una serie di piccole variazioni che possono rendere assai arduo l&#8217;obiettivo di individuare tendenze importanti e fare previsioni per il futuro. Proprio per approcciare questo problema sono state sviluppate varie tecniche di \u00ab<strong>lisciamento<\/strong>\u00bb (<em>smoothing<\/em>), che possiamo per semplicit\u00e0 suddividere in due grandi famiglie: le tecniche che si basano su <strong>medie mobili<\/strong> e le <strong>tecniche esponenziali<\/strong>.       <\/p>\n\n\n\n<p class=\"has-yellow-background-color has-background wp-block-paragraph\"><strong>MEDIA MOBILE<\/strong><br>Al posto del dato relativo al mese X calcolo la media di un numero n di mesi di cui X \u00e8 il punto centrale. <br>La componente casuale, si compensa se mettiamo assieme diversi mesi, la sua media \u00e8 uguale a 0 per un numero ragionevole di periodi.<br>La componente stagionale si ripete regolarmente nel corso dell\u2019anno, allora se distribuisco l\u2019effetto stagionale su tutti i 12 mesi, l\u2019effetto scompare. <br>Con la media mobile ottengo tutte e due gli effetti voluti: compenso la casualit\u00e0 e \u201cdistribuisco\u201d la stagionalit\u00e0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">R, come vedremo a breve, ci fornisce un aiuto fondamentale mettendoci a disposizione tutta una serie di strumenti per effettuare le nostre analisi con la massima praticit\u00e0.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esempio-seo-ga4\">Un esempio SEO: da Google Analytics 4 alla serie storica<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Come abbiamo visto, possiamo creare facilmente una serie storica in R usando il comando di base ts().<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dal momento che ho intenzione di usare l&#8217;analisi delle serie storiche a fini SEO per ricavare una tendenza e fare una previsione, ho bisogno di <strong>importare in R i dati della mia propriet\u00e0 Google Analytics 4<\/strong>. (n.b.: la prima versione di questo articolo usava l&#8217;API di Universal Analytics, che Google ha definitivamente dismesso a luglio 2024; il codice che segue \u00e8 aggiornato alla <strong>Data API di GA4<\/strong>.)<br><br>Posso farlo in maniera &#8220;automatica&#8221;, usando l&#8217;utilissima libreria <strong><a aria-label=\"googleAnalyticsR (apre in una nuova scheda)\" rel=\"noreferrer noopener\" href=\"https:\/\/code.markedmondson.me\/googleAnalyticsR\/\" target=\"_blank\">googleAnalyticsR<\/a><\/strong> \u2014 che supporta GA4 con la funzione <strong>ga_data()<\/strong> \u2014 oppure esportando manualmente i dati in un file csv.<br><br>Vediamo il primo caso:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># uso la libreria googleAnalyticsR\n# che ovviamente devo aver \n# correttamente installato\nlibrary(googleAnalyticsR)\n\n# Autorizzo Google Analytics\nga_auth()\n\n# setto l'ID numerico della propriet\u00e0 GA4\n# (Amministrazione &gt; Propriet\u00e0 &gt; Dettagli propriet\u00e0)\nproperty_id &lt;- 123456789\n\n# Recupero i dati che mi servono:\n# le sessioni mensili di tre anni\n# dalla Data API di GA4\ngadata &lt;- ga_data(property_id, \n          metrics = \"sessions\", \n          dimensions = \"yearMonth\",\n          date_range = c(\"2023-01-01\", \"2025-12-31\"),\n          limit = -1)\n\n# La Data API non garantisce l'ordine delle righe:\n# ordino per mese prima di costruire la serie\ngadata &lt;- gadata[order(gadata$yearMonth), ]\n\n# Converto i dati in una serie temporale \n# con cadenza mensile indicando frequency=12:\nga_ts &lt;- ts(gadata$sessions, start = c(2023,1), frequency = 12)<\/pre>\n\n\n\n<p class=\"has-white-background-color has-background wp-block-paragraph\">La procedura per ottenere lo stesso risultato senza passare dall&#8217;API \u00e8 altrettanto semplice.<br><br>Dall&#8217;interfaccia di GA4 apro il report che mi interessa (per esempio <em>Report &gt; Ciclo di vita &gt; Acquisizione &gt; Acquisizione traffico<\/em>), imposto l&#8217;intervallo di date e uso il bottone di condivisione per scaricare il file csv. In alternativa posso interrogare la Data API direttamente dal browser con il <a aria-label=\"Query Explorer GA4 (apre in una nuova scheda)\" rel=\"noreferrer noopener\" href=\"https:\/\/ga-dev-tools.google.com\/ga4\/query-explorer\/\" target=\"_blank\"><strong>Query Explorer per GA4<\/strong><\/a>: scelgo la propriet\u00e0, la metrica (<em>sessions<\/em>), la dimensione (<em>yearMonth<\/em>), l&#8217;intervallo di date, e scarico il risultato.<br><br>Apro poi il file con un editor di testo ed elimino le eventuali righe di intestazione generale e i totali in fondo. Se voglio, posso rinominare le colonne (&#8220;data&#8221; e &#8220;sessioni&#8221;) per una migliore leggibilit\u00e0.<br><br>Non ci resta che importare il csv e creare la serie temporale. Questione di due righe:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Importo un semplicissimo dataset \n# con mese e sessioni\nsitomese &lt;- read.csv(\"percorso\/sessioni-mensili.csv\", header = TRUE)\n\n# Converto i dati in una serie temporale\nsitomese_ts &lt;- ts(sitomese$sessioni, start = c(2023,1), frequency = 12)<\/pre>\n\n\n\n<p class=\"has-white-background-color has-background wp-block-paragraph\">Ora che ho la mia serie temporale, ho a disposizione una molteplicit\u00e0 di pacchetti R che mi forniscono tutti gli strumenti utili per analisi di qualunque tipo, dalle pi\u00f9 elementari a quelle pi\u00f9 approfondite.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Limitare l&#8217;effetto della stagionalit\u00e0 attraverso le medie mobili<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Installo il pacchetto <em>forecast<\/em> per poter usare l&#8217;utilissima funzione <strong>ma()<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">library(forecast)\nsitomese.filt&lt;-ma(sitomese_ts,order=12)\nsitomese.filt<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In questo modo si \u00e8 applicata una <strong>media ponderata<\/strong> alla nostra serie temporale, in modo da <strong>limitare l&#8217;effetto  della stagionalit\u00e0<\/strong>. Posso ora visualizzare la tendenza stimata con il sistema della media mobile:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">lines(sitomese.filt,col=\"red\")<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Elimino il trend stagionale usando la differenza<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Usando la differenza con la funzione diff() e un lag appropriato, ho la possibilit\u00e0 di eliminare il trend stagionale, qualora presente. Nel caso di una serie storica con dati mensili che comprende pi\u00f9 anni di osservazioni, mi basta usare un lag=12, come in questo banale esempio nel quale ipotizzo di lavorare su una serie temporale x:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># elimino il trend stagionale\n# ipotizzo dati mensili e la presenza di stagionalit\u00e0\ndx &lt;- diff(x, lag=12)\nts.plot(dx, main=\"Tendenza utenti destagionalizzata\")<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Decompongo la serie storica attraverso le medie mobili<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Abbiamo visto nel corso dell\u2019articolo che il metodo classico di analisi delle serie storiche individua quattro influenze, o <strong>componenti <\/strong><strong>e che l<\/strong><strong>o scopo principale \u00e8 proprio quello di <\/strong><strong>scomporre la serie<\/strong><strong>, per isolare le influenze delle varie componenti che determinano i valori della serie storica.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Passando dalla teoria alla pratica, vediamo come possiamo procedere.<br>Posso sfruttare la funzione <strong>decompose()<\/strong> del pacchetto <em>stats<\/em> per operare una classica decomposizione della mia serie temporale nelle componenti usando il sistema delle medie mobili e rappresentando in un solo chiarissimo grafico il tutto:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># decompongo la serie temporale. Ho scelto una decomposizione \n# moltiplicativa, ovviamente avrei\n# potuto scegliere una additiva\ncomponenti &lt;- decompose(sitomese_ts, type =\"multiplicative\")\nnames(componenti)\n# esploro nel grafico le componenti della serie storica\nplot(componenti)<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Decompongo la serie con il metodo LOESS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Un&#8217;alternativa pi\u00f9 raffinata per la decomposizione della serie \u00e8 quella che usa il metodo <strong>loess<\/strong> (Locally Weighted Smoothing). Si tratta di un insieme di metodi non-parametrici che adattano i modelli di regressione polinomiale ai sottoinsiemi di dati. Utilizziamo a tale scopo la funzione <strong>stl() <\/strong>del pacchetto <em>stats<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># uso stl per un decompose di tipo LOESS\nsitomese_loess &lt;- stl(sitomese_ts, s.window=\"periodic\")\nhead(sitomese_loess$time.series)\nplot(sitomese_loess)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Rispetto a decompose(), <strong>stl()<\/strong> ha due vantaggi che nella realt\u00e0 operativa pesano: consente alla componente stagionale di evolvere nel tempo (passando a s.window un valore numerico invece di &#8220;periodic&#8221;) ed \u00e8 pi\u00f9 robusta in presenza di valori anomali. E dalla decomposizione posso ricavare al volo la <strong>serie destagionalizzata<\/strong> \u2014 il traffico &#8220;depurato&#8221; dalla stagionalit\u00e0, quello che ci dice se stiamo davvero crescendo o se \u00e8 soltanto alta stagione \u2014 grazie alla funzione seasadj() del pacchetto <em>forecast<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">library(forecast)\n# la serie destagionalizzata: trend + residui\nsitomese_dest &lt;- seasadj(sitomese_loess)\nplot(sitomese_dest, main=\"Sessioni destagionalizzate\")<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"seasonal-plot\">Il seasonal plot: la stagionalit\u00e0 a colpo d&#8217;occhio<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">C&#8217;\u00e8 poi un grafico che, nella pratica quotidiana, vale da solo met\u00e0 dell&#8217;analisi della stagionalit\u00e0: il <strong>seasonal plot<\/strong> (grafico stagionale). L&#8217;idea \u00e8 semplice: invece di disegnare la serie come un&#8217;unica linea continua, sovrappongo gli anni \u2014 i mesi sull&#8217;asse orizzontale, una linea per ogni anno. Se le linee si somigliano (il crollo di agosto, il picco di novembre), la stagionalit\u00e0 c&#8217;\u00e8, si vede e si ripete; se una linea si stacca dalle altre, in quell&#8217;anno \u00e8 successo qualcosa che merita un&#8217;indagine. Disegno il seasonal plot con la funzione ggseasonplot() del pacchetto <em>forecast<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">library(forecast)\n# una linea per ogni anno, i mesi sull'asse x\nggseasonplot(sitomese_ts, year.labels = TRUE)\n\n# variante \"polare\": i mesi disposti in cerchio\nggseasonplot(sitomese_ts, polar = TRUE)<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"608\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2026\/06\/seasonal-plot-sessioni-mensili.png\" alt=\"Seasonal plot di tre anni di sessioni mensili: una linea per ogni anno, con il calo estivo che si ripete\" class=\"wp-image-3670\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2026\/06\/seasonal-plot-sessioni-mensili.png 962w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2026\/06\/seasonal-plot-sessioni-mensili-300x190.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">Il seasonal plot: tre anni sovrapposti, il profilo stagionale si ripete<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Tre anni a confronto in un colpo d&#8217;occhio: la crescita da un anno all&#8217;altro (le linee si spostano verso l&#8217;alto) e il profilo stagionale che si ripete, con il minimo estivo e la ripresa autunnale. In alternativa, il comando monthplot(sitomese_ts) di base R raggruppa le osservazioni per mese, mostrando per ogni mese la media e l&#8217;evoluzione negli anni.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"holt-winters\">Livellamento esponenziale con il metodo di Holt-Winters e previsione<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Le tecniche di lisciamento (<em>smoothing<\/em>) e previsione (<em>forecast<\/em>) ci offrono potenti modalit\u00e0 operative al fine di prevedere valori futuri dei dati delle serie temporali.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Al livello pi\u00f9 elementare, il livellamento pu\u00f2 essere realizzato utilizzando le <strong>medie mobili<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In R, possiamo usare <strong>HoltWinters<\/strong>, una funzione per eseguire il livellamento delle serie storiche.<br>La funzione contiene tre metodi di <em>smoothing<\/em> esponenziali. Tutti e tre i metodi usano la stessa funzione, HoltWinters. Tuttavia, possiamo invocarli separatamente in base ai valori dei parametri alpha, beta e gamma.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il livellamento esponenziale Holt-Winters fornisce previsioni attendibili solo se non \u00e8 presente autocorrelazione nei dati della serie temporale, cosa che pu\u00f2 essere verificata, come vedremo tra breve in pratica, con la funzione <strong>acf<\/strong> e con un <strong>test Box\u2013Pierce o Ljung\u2013Box<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dopo aver creato un modello di previsione, dobbiamo infatti valutarlo per capire se rappresenta correttamente i dati. In maniera analoga ad un modello di regressione, possiamo usare per questo scopo i <strong>residui<\/strong>. Se i residui seguono una distribuzione di tipo <strong>rumore bianco<\/strong> (<em>white noise<\/em>), allora la sequenza (o errore) dei residui \u00e8 generata da un processo di tipo stocastico. E quindi il nostro modello ben rappresenta la serie temporale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vediamo un esempio. Supponiamo di avere una serie storica x :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Usiamo la funzione forecast per una previsione: prossimi 6 periodi\nx.hw &lt;- HoltWinters(x)\nfuturo.pre &lt;- forecast(x.hw, h=6)\n# stampiamo a video un riepilogo\nsummary(futuro.pre)\n# disegniamo il grafico\nplot(futuro.pre)\n\n# disegniamo il grafico dei residui per stimare l\u2019autocorrelazione\nacf(futuro.pre$residuals,na.action = na.pass)\n# facciamo un test di autocorrelazione\nBox.test(futuro.pre$residuals)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>L\u2019autocorrelazione ci indica se i termini di una serie storica dipendono dal proprio passato.<\/strong><br><br>Se consideriamo una serie temporale x di lunghezza n, l\u2019autocorrelazione di lag 1 pu\u00f2 essere stimata come la correlazione della coppia di osservazioni (x[t], x[t-1]).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">R ci mette a disposizione un comodo comando: <strong>acf()<\/strong>.<br>Usando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">acf(x, lag.max = 1, plot = FALSE)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">sulla serie x viene automaticamente calcolata l\u2019autocorrelazione di grado -1.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">di default il comando acf(x) traccia un grafico, che mostra due righe orizzontali blu tratteggiate, che rappresentano l\u2019intervallo di confidenza al 95%. <br>La stima dell\u2019autocorrelazione \u00e8 indicata dall\u2019altezza delle barre verticali (<em>ovviamente l\u2019autocorrelazione al grado 0 \u00e8 sempre 1<\/em>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019intervallo di confidenza \u00e8 usato per determinare la significativit\u00e0 statistica dell\u2019autocorrelazione.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mostro a mo\u2019 d\u2019esempio l\u2019output della funzione acf() sulla serie storica Nile fornita da R:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/acf-nile.png\" alt=\"Esempio di grafico acf di autocorrelazione di una serie storica\" class=\"wp-image-1772\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/acf-nile.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/07\/acf-nile-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Se il coefficiente di autocorrelazione diminuisce e cade rapidamente tra i bordi, ci\u00f2 significa che i residui seguono una distribuzione di tipo rumore bianco. Non c&#8217;\u00e8 evidente autocorrelazione.<br>Al contrario, se i coefficienti sono sempre sopra o sotto il limite, ci\u00f2 significa che i residui sono autocorrelati.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un test di autocorrelazione <strong>Ljung-Box<\/strong> \u00e8 una forma particolare di test delle ipotesi, e fornisce un valore<em> p<\/em> come output, valore che ci consente di capire se rigettare l&#8217;ipotesi nulla o meno.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Applichiamo la funzione box.test sulla sequenza residua; troviamo il valore p. Se esso \u00e8 superiore al valore di \u03b1 non possiamo rifiutare l&#8217;ipotesi nulla. Cio\u00e8, i residui sono rumore bianco e ci\u00f2 dimostra che il nostro modello &#8220;funziona bene&#8221; nella previsione del valore.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vediamo il tutto in azione nel nostro esempio SEO relativo al traffico di un sito web, usando anche la libreria <em>highcharter<\/em> per una migliore visualizzazione dell&#8217;output:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Per prima cosa carico le librerie che mi servono\n\n<strong>library(googleAnalyticsR)<\/strong> \n# per leggere i dati di Google Analytics 4\n\n<strong>library(forecast)<\/strong> \n# per le previsioni su serie temporali\n\n<strong>library(highcharter) <\/strong>\n# per ottenere il grafico\n\n# ID numerico della propriet\u00e0 GA4\n# (Amministrazione &gt; Propriet\u00e0 &gt; Dettagli propriet\u00e0)\n<strong>property_id &lt;- 123456789<\/strong>\n\n# Autorizzo Google Analytics\n<strong>ga_auth()<\/strong>\n\n# e poi recupero i dati dalla Data API di GA4\n<strong>sitomese &lt;- ga_data(property_id, \n            metrics = \"sessions\", \n            dimensions = \"yearMonth\",\n            date_range = c(\"2023-01-01\", \"2025-12-31\"),\n            limit = -1)<\/strong>\n# nb: la dimensione dei miei dati \u00e8 annomese\n# e ordino le righe per mese\nsitomese &lt;- sitomese[order(sitomese$yearMonth), ]\n\n# Ora esprimo i dati come serie temporale\n<strong>sitomese_ts &lt;- ts(sitomese$sessions, start = c(2023,1), frequency = 12)<\/strong>\n \n# Calcolo il livellamento Holt-Winters\n<strong>previsione &lt;- HoltWinters(sitomese_ts)<\/strong>\n\n# Genero una previsione per i prossimi 12 mesi\n<strong>hchart(forecast(previsione, h = 12))<\/strong><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A chi legge il compito di testare la bont\u00e0 del modello previsionale.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"arima\">Indagare le serie storiche con i modelli ARIMA<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">L&#8217;uso del metodo di livellamento esponenziale richiede che i residui non siano correlati. Nei casi reali, questo \u00e8 abbastanza improbabile. Abbiamo per\u00f2 altri strumenti a disposizione per affrontare anche questi casi: R ci fornisce la funzione ARIMA per costruire modelli di serie temporale che prendano in considerazione l\u2019autocorrelazione.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Il rumore bianco (white noise)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019utilissima funzione arima.sim consente di simulare un processo ARIMA generando i dati di una serie temporale ad hoc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Attraverso questa funzione, dunque, possiamo iniziare a vedere due modelli di serie temporali basilari: il <strong>rumore bianco<\/strong> (<em><strong>white noise<\/strong><\/em>) e la <strong>passeggiata <\/strong><strong>aleatoria<\/strong> (<em><strong>random walk<\/strong><\/em>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un modello ARIMA consta di tre componenti: ARIMA(p,d,q).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>p \u00e8 l\u2019ordine di autoregressione<\/li>\n\n\n\n<li>d \u00e8 l\u2019ordine dell\u2019integrazione<\/li>\n\n\n\n<li>q \u00e8 l\u2019ordine della media mobile<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Il rumore bianco \u00e8 l\u2019esempio pi\u00f9 elementare di processo stazionario. Le caratteristiche salienti:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Presenta una media fissa, costante.<\/li>\n\n\n\n<li>Ha varianza costante.<\/li>\n\n\n\n<li>Non segue nessuna correlazione temporale.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Il modello white noise in termini ARIMA \u00e8 dunque ARIMA(0,0,0).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Andiamo allora a simulare una serie temporale di questo tipo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">wn &lt;- arima.sim(model = list(order = c(0,0,0)), n=100)\nts.plot(wn)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/rumore-bianco-ts.png\" alt=\"Esempio di serie temporale Rumore Bianco (White Noise)\" class=\"wp-image-1781\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/rumore-bianco-ts.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/rumore-bianco-ts-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">Un esempio di serie temporale di un processo White Noise<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">La passeggiata aleatoria (random walk)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Il Random Walk \u00e8 un semplice esempio di <strong>processo non-stazionario<\/strong>. Presenta queste caratteristiche salienti:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Non ha una media o una varianza specifici<\/li>\n\n\n\n<li>Mostra una forte dipendenza temporale<\/li>\n\n\n\n<li>I suoi cambiamenti o incrementi sono di tipo Rumore Bianco (White Noise)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Anche il modello della passeggiata aleatoria \u00e8 un modello di base di serie temporale, e pu\u00f2 essere facilmente simulato con la nostra funzione arima.sim.<br>Il modello Random Walk \u00e8 la somma cumulativa di serie Rumore Bianco aventi media zero.<br>Da questo discende che la prima serie differenziata di una serie Random Walk \u00e8 una serie White Noise!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il modello ARIMA per una serie Random Walk \u00e8 ARIMA(0,1,0).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Generiamo una serie di questo tipo e visualizziamola:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">RW &lt;- arima.sim(model = list(order = c(0,1,0)), n = 100)\nts.plot(RW)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RW-ts.png\" alt=\"Esempio di modello Passeggiata aleatoria (Random Walk)\" class=\"wp-image-1783\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RW-ts.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RW-ts-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption class=\"wp-element-caption\">Grafico di una serie storica di tipo Random Walk<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">vediamo la controprova di quanto affermato sopra:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">RWdiff &lt;- diff(RW)\nts.plot(RWdiff)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Otteniamo proprio una serie di tipo White Noise:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RWdiff.png\" alt=\"Diff serie Random Walk\" class=\"wp-image-1784\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RWdiff.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/RWdiff-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Il modello ARIMA in azione<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Il modello autoregressivo integrato a media mobile (ARIMA &#8211; <em>AutoRegressive Integrated Moving Average<\/em>) \u00e8 noto anche come <strong>modello Box-Jenkins<\/strong>, dal nome degli statistici George Box e Gwilym Jenkins.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lo scopo di ARIMA \u00e8 di trovare il modello che meglio rappresenti i valori di una serie storica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un modello ARIMA pu\u00f2 essere espresso come ARIMA (p, d, q), dove, come abbiamo gi\u00e0 visto, p \u00e8 l&#8217;ordine del modello autoregressivo, d indica il grado di differenziazione e q indica l&#8217;ordine della media mobile..<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Operativamente, possiamo definire cinque passaggi per adattare le serie storiche a un modello ARIMA<\/strong>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Visualizzare le serie temporali con un grafico.<\/li>\n\n\n\n<li>Differenziare le serie storiche non stazionarie per ottenere serie temporali stazionarie.<\/li>\n\n\n\n<li>Tracciare grafici ACF e PACF per trovare i valori ottimali di p e q, oppure ricavarli usando la funzione auto.arima.<\/li>\n\n\n\n<li>Costruire il modello ARIMA.<\/li>\n\n\n\n<li>Fare la previsione.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"arima-esempio\">Vediamo un esempio pratico di modello ARIMA<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">1. Simulo un processo ARIMA grazie alla funzione arima.sim() e disegno il grafico:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">simts &lt;- arima.sim(list(order = c(1,1,0), ar = 0.64), n = 100)\nplot(simts)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimasim.png\" alt=\"simulazione modello ARIMA\" class=\"wp-image-1788\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimasim.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimasim-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">2. Faccio la differenza per ottenere una serie storica stazionaria e traccio il grafico:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">simts.diff &lt;- diff(simts)\nplot(simts.diff)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/simts-diff.png\" alt=\"serie stazionaria\" class=\"wp-image-1789\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/simts-diff.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/simts-diff-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">3. Uso la funzione auto.arima per stimare i migliori valori di p,d, e q:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">auto.arima(simts, ic=\"bic\")\n\n\nSeries: simts \nARIMA(1,1,0) \nCoefficients: \nar1 0.6331 \ns.e. 0.0760 \nsigma^2 estimated as 0.9433: log likelihood=-138.73 \nAIC=281.46 AICc=281.58 BIC=286.67<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">4. Creo il modello ARIMA con i valori p,d e q indicati (nel nostro esempio 1,1,0):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fit &lt;- Arima(simts, order=c(1,1,0))\nsummary(fit)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">5. Basandoci ora sul nostro modello ARIMA possiamo passare alla previsione di valori futuri della serie e a tracciare il grafico:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">fit.prev &lt;- forecast(fit)\nsummary(fit.prev)\nplot(fit.prev)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimaprev.png\" alt=\"forecast arima\" class=\"wp-image-1790\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimaprev.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/arimaprev-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Le aree colorate mostrano gli intervalli di confidenza all\u201980% e al 95%.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Passiamo infine a valutare la bont\u00e0 del nostro modello con un grafico acf():<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"540\" src=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/prev-res.png\" alt=\"autocorrelologramma\" class=\"wp-image-1791\" style=\"width:641px;height:405px\" srcset=\"https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/prev-res.png 855w, https:\/\/www.gironi.it\/blog\/wp-content\/uploads\/2020\/08\/prev-res-300x189.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Come per il modello di livellamento esponenziale, possiamo usare la funzione acf per calcolare i residui e creare il diagramma di autocorrelazione. Poich\u00e9 il coefficiente di autocorrelazione diminuisce rapidamente, i residui sono rumore bianco.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Possiamo anche fare un test Box-Pierce:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Box.test(fit.prev$residuals)\n\nBox-Pierce test \ndata: fit.prev$residuals \nX-squared = 0.020633, df = 1, p-value = 0.8858<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">e otteniamo un valore p che indica la non rigettabilit\u00e0 dell\u2019ipotesi nulla.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"prova-tu\">Prova tu<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Per consolidare il tutto, ecco un esercizio completo che non richiede n\u00e9 un sito n\u00e9 un accesso a Google Analytics: i dati ce li generiamo da soli. Costruiamo in R tre anni di sessioni mensili realistiche \u2014 una crescita di fondo, un calo estivo marcato (come capita a molti siti B2B) e un po&#8217; di rumore casuale:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">set.seed(42)\n\n# 36 mesi: trend in crescita + stagionalit\u00e0 + rumore\ntrend &lt;- seq(8000, 14000, length.out = 36)\nstagionalita &lt;- rep(c(1.05, 1.08, 1.12, 1.04, 0.98, 0.88,\n                      0.72, 0.65, 1.02, 1.12, 1.16, 1.10), 3)\nrumore &lt;- rnorm(36, mean = 1, sd = 0.04)\nsessioni &lt;- round(trend * stagionalita * rumore)\n\n# la serie temporale: mensile, da gennaio 2023\ntraffico_ts &lt;- ts(sessioni, start = c(2023, 1), frequency = 12)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">L&#8217;esercizio ripercorre l&#8217;intero articolo, in cinque passi:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Disegniamo la serie con plot.ts(traffico_ts): trend e stagionalit\u00e0 si vedono gi\u00e0 a occhio nudo?<\/li>\n\n\n\n<li>Il seasonal plot con ggseasonplot(traffico_ts, year.labels = TRUE): \u00e8 proprio il grafico mostrato pi\u00f9 sopra \u2014 il crollo di agosto \u00e8 riconoscibile al primo sguardo?<\/li>\n\n\n\n<li>Decomponiamo con stl(traffico_ts, s.window = &#8220;periodic&#8221;), disegniamo le componenti con plot() e ricaviamo la serie destagionalizzata con seasadj().<\/li>\n\n\n\n<li>Stimiamo modello e previsione: futuro &lt;- forecast(HoltWinters(traffico_ts), h = 6), poi plot(futuro).<\/li>\n\n\n\n<li>Valutiamo i residui: acf(residuals(futuro), na.action = na.pass) e Box.test(residuals(futuro), type = &#8220;Ljung-Box&#8221;). Il modello regge?<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Se tutto fila liscio, la previsione per i primi sei mesi del 2026 dovrebbe proseguire la crescita rispettando il profilo stagionale (n.b.: con seed 42, il punto di previsione di gennaio si aggira sulle 15.300 sessioni), e il test di Ljung-Box sui residui dovrebbe restituire un p-value abbondantemente sopra 0,05: i residui sono rumore bianco, il modello ha catturato la struttura della serie.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un&#8217;ultima avvertenza, prima di chiudere, perch\u00e9 lo strumento \u00e8 potente ma insidioso: un modello di previsione \u2014 Holt-Winters o ARIMA che sia \u2014 <strong>proietta nel futuro le regolarit\u00e0 del passato<\/strong>. Funziona finch\u00e9 il mondo continua a comportarsi come si \u00e8 comportato: un core update di Google, una migrazione fatta male, un competitor aggressivo non sono nel modello, e nessuna banda di confidenza li pu\u00f2 prevedere. Per questo, nella pratica SEO, la previsione serve meno a indovinare il futuro e pi\u00f9 ad accorgersi in fretta che il presente se ne sta scostando: quando il traffico reale esce dalle bande della previsione, \u00e8 l\u00ec che dobbiamo andare a guardare. Di questo uso &#8220;in negativo&#8221; dei modelli abbiamo parlato nell&#8217;articolo sull&#8217;<a href=\"https:\/\/www.gironi.it\/blog\/anomaly-detection\/\">anomaly detection<\/a>, e torneremo presto sulla decomposizione del traffico organico con un caso di studio dedicato.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Per approfondire<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Per approfondire l&#8217;analisi delle serie storiche &mdash; stazionariet&agrave;, autocorrelazione, modelli previsivi &mdash; <a href=\"https:\/\/www.amazon.it\/dp\/8891906190?tag=consulenzeinf-21&#038;ascsubtag=analisi-delle-serie-storiche0-e-previsioni-di-serie-temporali-in-r-con-il-metodo-holt-winters\" rel=\"nofollow sponsored noopener\" target=\"_blank\"><em>Introduzione all&#8217;econometria<\/em><\/a> di Stock e Watson dedica all&#8217;argomento capitoli chiari e rigorosi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sul versante divulgativo, <a href=\"https:\/\/www.amazon.it\/dp\/8860443865?tag=consulenzeinf-21&#038;ascsubtag=analisi-delle-serie-storiche0-e-previsioni-di-serie-temporali-in-r-con-il-metodo-holt-winters\" rel=\"nofollow sponsored noopener\" target=\"_blank\"><em>Il segnale e il rumore<\/em><\/a> di Nate Silver racconta perch\u00e9 le previsioni falliscono cos\u00ec spesso \u2014 e come ragionano i bravi previsori: il complemento ideale, da leggere senza computer davanti.<\/p>\n\n\n<!-- internal-links-section -->\n<h3>Potrebbe interessarti anche<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.gironi.it\/blog\/anomaly-detection\/\">Anomaly detection: come identificare valori anomali nei dati<\/a><\/li>\n<li><a href=\"https:\/\/www.gironi.it\/blog\/il-paradosso-di-simpson-nella-seo-quando-i-dati-aggregati-possono-mentire\/\">Il Paradosso di Simpson nella SEO: quando i dati aggregati possono mentire<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Cosa si intende per serie storica, o serie temporale Una serie storica consta dei valori osservati in un insieme di periodi ordinati sequenzialmente. Questo, per chi fa SEO, \u00e8 gi\u00e0 un elemento del massimo interesse. I dati di traffico del nostro sito web, considerati lungo una sequenza temporale, sono infatti un esempio di serie storica. &hellip; <a href=\"https:\/\/www.gironi.it\/blog\/analisi-delle-serie-storiche0-e-previsioni-di-serie-temporali-in-r-con-il-metodo-holt-winters\/\" class=\"more-link\">Leggi tutto<span class=\"screen-reader-text\"> &#8220;Analisi delle serie storiche e previsioni di serie temporali in R&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","footnotes":""},"categories":[717,629],"tags":[731,733,735,737,739],"class_list":["post-1496","post","type-post","status-publish","format-standard","hentry","category-seo-it","category-statistica-it","tag-holt-winters-it","tag-lisciatori-it","tag-livellamento-it","tag-serie-storica-it","tag-trend-it"],"lang":"it","translations":{"it":1496,"en":3331},"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"post-thumbnail":false},"uagb_author_info":{"display_name":"paolo","author_link":"https:\/\/www.gironi.it\/blog\/author\/paolo\/"},"uagb_comment_info":172,"uagb_excerpt":"Cosa si intende per serie storica, o serie temporale Una serie storica consta dei valori osservati in un insieme di periodi ordinati sequenzialmente. Questo, per chi fa SEO, \u00e8 gi\u00e0 un elemento del massimo interesse. I dati di traffico del nostro sito web, considerati lungo una sequenza temporale, sono infatti un esempio di serie storica.&hellip;","_links":{"self":[{"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/posts\/1496","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/comments?post=1496"}],"version-history":[{"count":5,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/posts\/1496\/revisions"}],"predecessor-version":[{"id":3772,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/posts\/1496\/revisions\/3772"}],"wp:attachment":[{"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/media?parent=1496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/categories?post=1496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gironi.it\/blog\/wp-json\/wp\/v2\/tags?post=1496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}