Media mobile ponderata esponenzialmente
Applichi lo smoothing esponenziale per assegnare più peso ai valori recenti con ewm(span=), una tecnica standard nell'analisi finanziaria.
Media mobile ponderata esponenzialmente è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
Il problema delle medie mobili semplici
Una media mobile semplice tratta tutte le n osservazioni della finestra allo stesso modo: un prezzo di 30 giorni fa contribuisce quanto il prezzo di ieri. Tuttavia, per prevedere i valori a breve termine, le osservazioni recenti sono più informative di quelle meno recenti. Una media mobile ponderata esponenzialmente (EWMA) risolve questo problema assegnando pesi che diminuiscono esponenzialmente alle osservazioni più vecchie: il valore di ieri conta di più, quello del giorno precedente conta leggermente meno, e così via fino all'inizio della serie.
import pandas as pd
import numpy as np
np.random.seed(42)
prices = pd.Series(
100 + np.cumsum(np.random.normal(0.5, 2, 30)),
index=pd.date_range('2024-01-01', periods=30)
)
df = pd.DataFrame({'price': prices})
df['SMA_7'] = df['price'].rolling(7).mean()
df['EWM_span7'] = df['price'].ewm(span=7).mean()
print(df.tail(5).round(2))Come funziona la ponderazione EWMA
EWMA calcola ogni valore come combinazione ponderata dell'osservazione corrente e della EWMA precedente: EWM_t = alpha * x_t + (1 - alpha) * EWM_{t-1}. Il valore di alpha (fattore di smoothing) determina la rapidità con cui i pesi diminuiscono: un alpha elevato (vicino a 1) reagisce rapidamente ai cambiamenti recenti (con meno smoothing), mentre un alpha basso (vicino a 0) reagisce lentamente (con più smoothing). I pesi formano una serie geometrica: il valore più recente ha peso alpha, quello precedente ha peso alpha*(1-alpha), e così via.
import numpy as np
# Manually show EWMA weights
alpha = 0.3
n_points = 8
weights = [alpha * (1 - alpha)**i for i in range(n_points)]
print(f'Alpha = {alpha}')
print(f'Weights (most recent first):')
for i, w in enumerate(weights):
print(f' t-{i}: {w:.4f}')
print(f'Sum of shown weights: {sum(weights):.4f} (converges to 1.0)')Il metodo ewm() e il parametro span
Pandas implementa EWMA tramite Series.ewm(). Il parametro più intuitivo è span, analogo alla finestra di una media mobile semplice: alpha = 2 / (span + 1). Uno span pari a 10 corrisponde approssimativamente a una SMA su 10 periodi, ma con pesi che diminuiscono esponenzialmente invece di pesi uniformi. Usi ewm(span=n).mean() per ottenere la EWMA e ewm(span=n).std() per la volatilità ponderata esponenzialmente.
import pandas as pd
import numpy as np
np.random.seed(0)
data = pd.Series(
np.random.normal(100, 10, 50),
index=pd.date_range('2024-01-01', periods=50)
)
df = pd.DataFrame({'value': data})
df['EWM_3'] = df['value'].ewm(span=3).mean()
df['EWM_10'] = df['value'].ewm(span=10).mean()
df['EWM_20'] = df['value'].ewm(span=20).mean()
print('Alpha values:')
for span in [3, 10, 20]:
alpha = 2 / (span + 1)
print(f' span={span} → alpha={alpha:.3f}')
print(df.tail(5).round(2))Il parametro halflife
Il parametro halflife definisce quanti periodi sono necessari affinché il peso si dimezzi. Se halflife=5, un valore di 5 periodi fa ha metà del peso del valore corrente. La relazione è: alpha = 1 - exp(log(0.5) / halflife). Halflife è spesso più intuitivo di span o alpha perché esprime direttamente la "memoria" della media in termini aziendali, ad esempio: "i prezzi di 2 settimane fa devono avere metà dell'influenza del prezzo odierno".
import pandas as pd
import numpy as np
np.random.seed(5)
prices = pd.Series(
100 + np.cumsum(np.random.normal(0, 2, 30)),
index=pd.date_range('2024-01-01', periods=30)
)
df = pd.DataFrame({'price': prices})
# halflife=5: weight halves every 5 days
df['EWM_hl5'] = df['price'].ewm(halflife=5).mean()
# halflife=14: weight halves every 14 days (longer memory)
df['EWM_hl14'] = df['price'].ewm(halflife=14).mean()
print(df.tail(5).round(2))Il parametro alpha direttamente
Può anche impostare direttamente il fattore di smoothing con ewm(alpha=). Alpha deve essere compreso tra 0 e 1 (esclusi). Un alpha elevato, come 0.8, produce pochissimo smoothing: la EWMA segue da vicino il segnale grezzo. Un alpha basso, come 0.1, produce uno smoothing intenso: la EWMA cambia lentamente e rimane indietro rispetto agli sbalzi improvvisi. La scelta dell'alpha corretto dipende dal compromesso tra reattività (rilevare rapidamente i cambiamenti reali della tendenza) e stabilità (ignorare il rumore casuale).
import pandas as pd
import numpy as np
np.random.seed(3)
data = pd.Series(
[100]*20 + [120]*20, # sudden level shift at row 20
dtype=float
) + np.random.normal(0, 2, 40)
df = pd.DataFrame({'signal': data})
df['alpha_0.1'] = df['signal'].ewm(alpha=0.1).mean() # slow
df['alpha_0.5'] = df['signal'].ewm(alpha=0.5).mean() # medium
df['alpha_0.9'] = df['signal'].ewm(alpha=0.9).mean() # fast
print('After the level shift (rows 20-25):')
print(df.iloc[18:26].round(2))EWMA per la volatilità: ewm().std()
ewm(span=).std() calcola una deviazione standard ponderata esponenzialmente. È alla base del modello di volatilità EWMA usato nella gestione del rischio finanziario (noto anche come modello RiskMetrics con fattore di decadimento lambda=0.94). La volatilità ponderata esponenzialmente reagisce ai picchi di volatilità più rapidamente di una deviazione standard mobile semplice, perché assegna un peso maggiore alle osservazioni recenti ad alta varianza.
import pandas as pd
import numpy as np
np.random.seed(42)
# Simulate returns: quiet period then volatile period
returns = pd.Series(
np.concatenate([
np.random.normal(0, 0.01, 60),
np.random.normal(0, 0.04, 60) # 4x more volatile
]),
index=pd.date_range('2024-01-01', periods=120)
)
df = pd.DataFrame({'returns': returns})
df['rolling_vol'] = df['returns'].rolling(20).std()
df['ewm_vol'] = df['returns'].ewm(span=20).std()
print('Volatility comparison (transition at row 60):')
print(df.iloc[58:65].round(5))MACD: combinare due EWMA
Il MACD (Moving Average Convergence Divergence) è un indicatore finanziario classico costruito a partire da due EWMA. È la differenza tra una EWMA rapida (con span breve) e una EWMA lenta (con span lungo) del prezzo. Quando il MACD attraversa lo zero dal basso verso l'alto, segnala un possibile slancio rialzista (un segnale di acquisto); l'attraversamento dall'alto verso il basso segnala uno slancio ribassista. Il MACD è un esempio perfetto di applicazione di due EWMA per derivare un indicatore.
import pandas as pd
import numpy as np
np.random.seed(7)
prices = pd.Series(
100 + np.cumsum(np.random.normal(0.3, 2, 100)),
index=pd.date_range('2024-01-01', periods=100)
)
df = pd.DataFrame({'price': prices})
df['EMA_12'] = df['price'].ewm(span=12).mean() # fast
df['EMA_26'] = df['price'].ewm(span=26).mean() # slow
df['MACD'] = df['EMA_12'] - df['EMA_26']
df['Signal'] = df['MACD'].ewm(span=9).mean() # signal line
print('MACD values (last 8 rows):')
print(df[['price', 'MACD', 'Signal']].tail(8).round(2))EWMA con halflife basato sul tempo
Pandas 1.1+ supporta la specifica di halflife, span e com come offset temporali (ad esempio halflife='7D') quando si lavora con un DatetimeIndex. Ciò consente di calcolare correttamente una EWMA su serie temporali non uniformi: ad esempio, se si hanno dati orari con interruzioni nei fine settimana, un halflife di '7D' significa che il peso si dimezza effettivamente ogni 7 giorni di calendario, indipendentemente dal numero di righe presenti in quel periodo.
import pandas as pd
import numpy as np
np.random.seed(0)
# Business-day data (no weekends)
biz_dates = pd.bdate_range('2024-01-01', periods=20)
prices = pd.Series(100 + np.cumsum(np.random.randn(20)), index=biz_dates)
# halflife as a time offset (7 calendar days)
ewm_7d = prices.ewm(halflife='7D', times=biz_dates).mean()
# halflife as row count (7 rows)
ewm_7rows = prices.ewm(halflife=7).mean()
df = pd.DataFrame({'price': prices, 'hl_7D': ewm_7d, 'hl_7rows': ewm_7rows})
print(df.round(2))Scegliere tra EWMA, rolling ed expanding
Riepilogo dei casi d'uso:
- Rolling(n).mean(): tutte le n osservazioni recenti hanno lo stesso peso; è indicato per semplici metriche retrospettive e quando tutti i periodi recenti sono ugualmente importanti.
- ewm(span=n).mean(): ponderazione esponenziale; è ideale quando si desidera uno smoothing che reagisca maggiormente ai cambiamenti recenti, ed è usato comunemente nella finanza e nell'elaborazione dei segnali.
- expanding().mean(): tutti i dati storici hanno lo stesso peso; è ideale per metriche YTD o storiche complessive, quando non è accettabile dimenticare i dati più vecchi.
Visualizzare il confronto tra EWMA e SMA
Rappresentare insieme EWMA e SMA in un grafico di serie temporali rende evidente la differenza nella loro reattività. EWMA reagisce più rapidamente ai cambiamenti improvvisi del livello perché non ha «dimenticato» tutte le osservazioni precedenti: un EWMA con periodo breve cambia direzione più velocemente di una SMA con la stessa finestra nominale. Per questo EWMA è preferibile nelle applicazioni di previsione in cui rilevare rapidamente la direzione del trend è più importante della massima riduzione del rumore.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
prices = pd.Series(
np.concatenate([
100 + np.cumsum(np.random.normal(0.3, 1.5, 50)),
130 + np.cumsum(np.random.normal(-0.3, 1.5, 50))
]),
index=pd.date_range('2024-01-01', periods=100)
)
df = pd.DataFrame({'price': prices})
df['SMA_10'] = df['price'].rolling(10).mean()
df['EWMA_10'] = df['price'].ewm(span=10).mean()
df.plot(figsize=(12, 5), title='SMA vs EWMA — EWMA reacts faster to trend reversals')
plt.ylabel('Price')
plt.axvline(x=df.index[50], color='red', linestyle='--', label='Trend change')
plt.legend()
plt.show()EWMA nelle applicazioni aziendali
Oltre che nella finanza, EWMA viene ampiamente utilizzato nell'analisi dei prodotti e nelle attività operative: per lo smoothing del customer lifetime value (il comportamento recente consente di prevedere meglio la spesa futura rispetto a quello passato), nel monitoraggio della latenza dei server (una metrica della latenza smussata esponenzialmente segnala più rapidamente i falsi allarmi rispetto a una media mobile) e nella previsione della domanda di inventario (le vendite delle settimane recenti dovrebbero avere più peso dei dati di sei mesi fa). Il principio generale è: ovunque la recenza sia importante, EWMA supera la semplice media.
Verifica rapida
Verifichi la Sua comprensione delle medie mobili ponderate esponenzialmente presentate in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che: ewm(span=) applica pesi con decadimento esponenziale, dando più importanza alle osservazioni recenti; alpha controlla la reattività (valore alto = risposta rapida, valore basso = maggiore uniformità); il parametro halflife esprime la memoria in termini significativi per il contesto aziendale. EWMA supera SMA quando è importante rilevare rapidamente le inversioni del trend. Ora esamineremo i calcoli di rango e percentile all'interno dei gruppi usando groupby().rank() e pd.qcut.
Domande Frequenti
La lezione «Media mobile ponderata esponenzialmente» è gratuita?
Sì — il testo completo di «Media mobile ponderata esponenzialmente» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
Cosa imparerò in «Media mobile ponderata esponenzialmente»?
Applichi lo smoothing esponenziale per assegnare più peso ai valori recenti con ewm(span=), una tecnica standard nell'analisi finanziaria. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?
Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Media mobile ponderata esponenzialmente»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?
Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Finestre mobili
- Finestre espandibili
- Media mobile ponderata esponenzialmente
- Ranghi e percentili all'interno dei gruppi