Exponential Moving Average (EMA)

The Problem with SMA First

Remember SMA — it gives equal weight to all values in the window.

For a 3-day SMA on sales:

Day 1: 200, Day 2: 450, Day 3: 180

SMA = (200 + 450 + 180) / 3 = 276.6

Here, Day 1 (old data) and Day 3 (today) are treated equally. But think about it — should 2-day-old data matter as much as today's data?

In most real cases — No. Recent data is more important.

That's exactly what EMA fixes.


What is EMA?

EMA gives MORE weight to recent values and LESS weight to older values.

The further back a value is, the less it influences the average. Recent values dominate.


Weight Concept — Simple Visual

For a 3-period EMA, weights look like this:

Data Point

Weight

Today (most recent)

Highest ⬆️

Yesterday

Medium

Day before

Low

Even older

Very Low (almost ignored)

Compare this to SMA where every day gets exactly equal weight.


The Formula

EMA today = (Today's Value × α) + (Yesterday's EMA × (1 - α))

Where α (alpha) is the smoothing factor:

α = 2 / (N + 1)

For N = 3:

α = 2 / (3 + 1) = 0.5

That means — 50% weight to today, 50% to the past EMA.

For N = 10:

α = 2 / (10 + 1) = 0.18

Smaller alpha = smoother = older data still matters more.


Manual Walkthrough — Step by Step

Daily Sales data:

Day

Sales

1

200

2

450

3

180

4

500

5

220

Using N = 3, so α = 0.5

Step 1 — Day 1: No previous EMA exists, so EMA = first value itself

EMA(1) = 200

Step 2 — Day 2:

EMA(2) = (450 × 0.5) + (200 × 0.5)
       = 225 + 100
       = 325

Step 3 — Day 3:

EMA(3) = (180 × 0.5) + (325 × 0.5)
       = 90 + 162.5
       = 252.5

Step 4 — Day 4:

EMA(4) = (500 × 0.5) + (252.5 × 0.5)
       = 250 + 126.25
       = 376.25

Step 5 — Day 5:

EMA(5) = (220 × 0.5) + (376.25 × 0.5)
       = 110 + 188.12
       = 298.12

Final result:

Day

Sales

EMA (N=3)

1

200

200

2

450

325

3

180

252.5

4

500

376.25

5

220

298.12

Notice — EMA reacts faster to the spike on Day 4 (500) compared to SMA. That's the power.


SMA vs EMA — Side by Side

Feature

SMA

EMA

Weight to all values

Equal

More to recent

Reacts to sudden change

Slow

Fast

Smoother line

Yes

Slightly less smooth

NaN at start

Yes (first N rows)

No

Best for

Long-term trend

Short-term, fast signals


Python Program


    import pandas as pd
    import matplotlib.pyplot as plt

    # --- Data ---
    data = {
        'day': list(range(1, 16)),
        'sales': [200, 450, 180, 500, 220, 480, 210, 460, 190, 510, 230, 490, 200, 470, 215]
    }

    df = pd.DataFrame(data)

    # --- Calculate SMA and EMA ---
    df['SMA_3'] = df['sales'].rolling(window=3).mean()
    df['EMA_3'] = df['sales'].ewm(span=3, adjust=False).mean()  # EMA with N=3
    df['EMA_7'] = df['sales'].ewm(span=7, adjust=False).mean()  # EMA with N=7

    print(df.to_string(index=False))

    # --- Plot ---
    plt.figure(figsize=(12, 5))
    plt.plot(df['day'], df['sales'], label='Raw Sales', marker='o', linewidth=1.5, alpha=0.6)
    plt.plot(df['day'], df['SMA_3'], label='SMA (3-day)', linewidth=2, linestyle='--')
    plt.plot(df['day'], df['EMA_3'], label='EMA (3-day)', linewidth=2)
    plt.plot(df['day'], df['EMA_7'], label='EMA (7-day)', linewidth=2)

    plt.title('SMA vs EMA Comparison')
    plt.xlabel('Day')
    plt.ylabel('Sales')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('ema_vs_sma.png')
    plt.show()
    print("Plot saved!")


Output:

day sales SMA_3 EMA_3 EMA_7 1 200 NaN 200.000000 200.000000 2 450 NaN 325.000000 262.500000 3 180 276.666667 252.500000 241.875000 4 500 376.666667 376.250000 306.406250 5 220 300.000000 298.125000 284.804688 6 480 400.000000 389.062500 333.603516 7 210 303.333333 299.531250 302.702637 8 460 383.333333 379.765625 342.026978 9 190 286.666667 284.882812 304.020233 10 510 386.666667 397.441406 355.515175 11 230 310.000000 313.720703 324.136381 12 490 410.000000 401.860352 365.602286 13 200 306.666667 300.930176 324.201714 14 470 386.666667 385.465088 360.651286 15 215 295.000000 300.232544 324.238464 Plot saved!



Key Things to Remember

ewm(span=3)span is your N value, same as window in rolling

adjust=False — uses the recursive formula shown above (standard EMA). Always use this.

No NaN — EMA starts from Day 1 itself, unlike SMA which waits for N values


Where EMA is Used in ML


    # Feature Engineering with EMA
    df['ema_3']  = df['sales'].ewm(span=3,  adjust=False).mean()  # short trend
    df['ema_7']  = df['sales'].ewm(span=7,  adjust=False).mean()  # medium trend
    df['ema_21'] = df['sales'].ewm(span=21, adjust=False).mean()  # long trend

    # EMA reacts faster — great for detecting sudden changes (fraud, anomaly)
    df['deviation_from_ema'] = df['sales'] - df['ema_7']  # how far today is from trend

deviation_from_ema is a very powerful feature — if this value is very high or very low, it signals something unusual happening. Used heavily in anomaly detection and fraud detection models.


One Line Summary

EMA is a smarter Moving Average — it remembers the past but pays more attention to what just happened, making it faster to react to real changes in data.

Simple Moving Average - SMA (Rolling Mean)

Simple Moving Average (Rolling Mean)

The Problem First

Imagine you're tracking your daily steps for a week:

Mon: 3,000 | Tue: 12,000 | Wed: 2,500 | Thu: 11,000 | Fri: 4,000 | Sat: 13,000 | Sun: 3,500

The numbers jump up and down wildly. It's hard to answer: "Am I generally becoming more active or not?"

This is the core problem — raw data is noisy. Moving Average solves this.


What is Moving Average?

Moving Average = Average of the last N values, calculated at every step

Instead of looking at one day's value, you look at the average of the last few days. Then you "move" forward one step and calculate again.


Simple Example — Window Size = 3

Your daily steps:

Day

Steps

3-Day Moving Avg

Mon

3,000

Tue

12,000

Wed

2,500

(3000+12000+2500)/3 = 5,833

Thu

11,000

(12000+2500+11000)/3 = 8,500

Fri

4,000

(2500+11000+4000)/3 = 5,833

Sat

13,000

(11000+4000+13000)/3 = 9,333

Sun

3,500

(4000+13000+3500)/3 = 6,833

 See what happened? The moving average values — 5833 → 8500 → 5833 → 9333 → 6833 — are much smoother than the original jumpy numbers.


Why Do We Use It?

1. To remove noise Raw data has random spikes that don't mean anything. Moving average filters them out so you see the real trend.

2. To see the big picture Instead of asking "did I walk a lot today?", you ask "have I been walking more this week overall?" — much more meaningful.

3. Used everywhere in real life

  • 📈 Stock market — 50-day and 200-day moving averages tell traders the trend direction
  • 🌡️ Weather — "average temperature this month" smooths daily fluctuations
  • 🏪 Sales forecasting — businesses predict next month's sales using past months' averages
  • 🤖 ML / Time Series — it's a classic feature used in models to capture trends

The "Window" Concept

The window size (N) controls how smooth vs. sensitive the average is:

Window Size

Effect

Small (N=2 or 3)

Reacts quickly to changes, still a bit noisy

Large (N=7 or 30)

Very smooth, but slow to react to new changes

Think of it like sunglasses — darker glasses block more light (more smoothing), but you also miss some details.

Where Moving Average is Actually Used (ML/Data Science Context)

1. Time Series Forecasting

When you have data over time — stock prices, sales, temperature, website traffic — raw data is too noisy to feed directly into a model. Moving average smooths it first, making patterns clearer for the model to learn.

2. Feature Engineering

This is the biggest use case for you as an ML engineer.

Before training a model, you create new columns like:

  • price_7day_avg — average price of last 7 days
  • sales_30day_avg — average sales of last 30 days

These features help the model understand "what has been happening recently" — which a single day's value can't tell.

3. Anomaly Detection

If today's value is very far from the moving average, it's probably an anomaly — fraud, system failure, sudden spike. Moving average becomes your baseline to compare against.

4. Signal Smoothing (before EDA or Visualization)

Before you even plot data, applying moving average removes visual noise so you can actually see the trend in your EDA (Exploratory Data Analysis).

5. Stock/Finance Models

Classic use — 50-day MA crossing 200-day MA is a buy/sell signal. If you ever build a finance-related ML model, this will be a standard feature.


Python Program


    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt

    # --- Sample Data: Daily Sales for 15 days ---
    data = {
        'day': list(range(1, 16)),
        'sales': [200, 450, 180, 500, 220, 480, 210, 460, 190, 510, 230, 490, 200, 470, 215]
    }

    df = pd.DataFrame(data)

    # --- Calculate Moving Averages ---
    df['SMA_3'] = df['sales'].rolling(window=3).mean()   # 3-day simple moving avg
    df['SMA_7'] = df['sales'].rolling(window=7).mean()   # 7-day simple moving avg
    df['EMA_3'] = df['sales'].ewm(span=3, adjust=False).mean()  # 3-day exponential moving avg

    print(df.to_string(index=False))

    # --- Plot ---
    plt.figure(figsize=(12, 5))
    plt.plot(df['day'], df['sales'],  label='Raw Sales',  marker='o', linewidth=1.5)
    plt.plot(df['day'], df['SMA_3'],  label='SMA (3-day)', linewidth=2)
    plt.plot(df['day'], df['SMA_7'],  label='SMA (7-day)', linewidth=2)
    plt.plot(df['day'], df['EMA_3'],  label='EMA (3-day)', linewidth=2, linestyle='--')

    plt.title('Moving Average on Sales Data')
    plt.xlabel('Day')
    plt.ylabel('Sales')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('moving_average.png')
    plt.show()
    print("Plot saved!")


Output:

day sales SMA_3 SMA_7 EMA_3 1 200 NaN NaN 200.000000 2 450 NaN NaN 325.000000 3 180 276.666667 NaN 252.500000 4 500 376.666667 NaN 376.250000 5 220 300.000000 NaN 298.125000 6 480 400.000000 NaN 389.062500 7 210 303.333333 320.000000 299.531250 8 460 383.333333 357.142857 379.765625 9 190 286.666667 320.000000 284.882812 10 510 386.666667 367.142857 397.441406 11 230 310.000000 328.571429 313.720703 12 490 410.000000 367.142857 401.860352 13 200 306.666667 327.142857 300.930176 14 470 386.666667 364.285714 385.465088 15 215 295.000000 329.285714 300.232544 Plot saved!



What Each Line Does

Code

What it does

rolling(window=3).mean()

SMA — simple average of last 3 values

rolling(window=7).mean()

SMA — wider window, smoother line

ewm(span=3).mean()

EMA — gives more weight to recent values


Output You'll See

  • First 2 rows of SMA_3 will be NaN — that's normal, because you need at least 3 values to start calculating
  • First 6 rows of SMA_7 will be NaN — same reason
  • EMA has no NaN — it starts calculating from day 1

Real ML Usage (Feature Engineering snippet)


    # In a real ML project, you'd add these as features before training
    df['sales_lag1']  = df['sales'].shift(1)         # yesterday's sales
    df['sales_sma3']  = df['sales'].rolling(3).mean() # 3-day avg (trend feature)
    df['sales_sma7']  = df['sales'].rolling(7).mean() # 7-day avg (long trend)
    df['sales_ema3']  = df['sales'].ewm(span=3, adjust=False).mean()

    # Then drop NaN rows before training
    df.dropna(inplace=True)

    # Now df is ready to be fed into your ML model
    X = df[['sales_lag1', 'sales_sma3', 'sales_sma7', 'sales_ema3']]
    y = df['sales']

This is exactly how time series feature engineering is done in real projects — you create these rolling features and feed them to models like XGBoost, LSTM, or Linear Regression.


One Line Summary

Moving Average takes the average of the last N data points and slides that window forward — turning noisy, jumpy data into a smooth trend line.

That's it! Once you get this idea, SMA and EMA (which you've seen before) are just variations on top of this same concept.

Phase 4 — Data Binding & Directives

Chapter 1 — What is Data Binding? 1.1 — The Problem Data Binding Solves When you build a web application, you have two worlds that need to t...