移動平均フィルタの種類と比較:SMA・WMA・EMAのPython実装

単純移動平均(SMA)、加重移動平均(WMA)、指数移動平均(EMA)の数理的定義とPython実装を解説し、ノイズ除去性能・応答速度・周波数特性を比較します。

移動平均(Moving Average)は、時系列データの平滑化に最もよく使われるフィルタリング手法です。ノイズ除去、トレンド抽出、センサデータの前処理など幅広い場面で活用されます。

この記事では、代表的な3つの移動平均フィルタを数理的に定義し、Python実装と性能比較を行います。

単純移動平均 (Simple Moving Average, SMA)

定義

SMAは、直近 \(N\) 個のデータ点の算術平均です。

\[ y_t = \frac{1}{N} \sum_{i=0}^{N-1} x_{t-i} \tag{1} \]

すべてのデータ点に等しい重み \(1/N\) を与えます。\(N\) が**窓幅(ウィンドウサイズ)**で、大きいほど平滑化が強くなります。

特性

  • 長所: 実装が簡単。高周波ノイズの除去に効果的
  • 短所: 急激な変化への応答が遅い(遅延が \(\frac{N-1}{2}\) サンプル)。窓幅分のデータをバッファとして保持する必要がある

Python実装

import numpy as np

def sma(x, window):
    """単純移動平均フィルタ"""
    kernel = np.ones(window) / window
    # 'valid' モードで出力(端の不完全な窓を除外)
    return np.convolve(x, kernel, mode='same')

NumPyのconvolveを使うと、SMAは畳み込み演算として簡潔に書けます。

加重移動平均 (Weighted Moving Average, WMA)

定義

WMAは、新しいデータほど大きな重みを付ける移動平均です。重みは線形に減少します。

\[ y_t = \frac{\sum_{i=0}^{N-1} (N - i) \cdot x_{t-i}}{\sum_{i=0}^{N-1} (N - i)} = \frac{2}{N(N+1)} \sum_{i=0}^{N-1} (N - i) \cdot x_{t-i} \tag{2} \]

最新のデータ点に重み \(N\)、1ステップ前のデータ点に重み \(N-1\)、…、\(N-1\) ステップ前のデータ点に重み \(1\) を付け、重みの合計で正規化します。

特性

  • 長所: SMAよりも最新データへの追従が速い
  • 短所: SMAと同様に窓幅分のバッファが必要。重みが線形のため、古いデータの影響が急に0になる(窓の端での不連続)

Python実装

def wma(x, window):
    """加重移動平均フィルタ"""
    weights = np.arange(1, window + 1, dtype=float)
    weights /= weights.sum()
    return np.convolve(x, weights[::-1], mode='same')

指数移動平均 (Exponential Moving Average, EMA)

定義

EMAは再帰的に計算される移動平均で、過去のすべてのデータに指数関数的に減衰する重みを与えます。

\[ y_t = \alpha \cdot x_t + (1 - \alpha) \cdot y_{t-1} \tag{3} \]

\(\alpha\)(\(0 < \alpha \le 1\))は平滑化係数です。\(\alpha\) が小さいほど平滑化が強くなります。

SMAの窓幅 \(N\) と対応させる場合、\(\alpha = \frac{2}{N + 1}\) がよく使われます。

特性

  • 長所: 過去データのバッファが不要(1ステップ前の値だけ保持すればよい)。メモリ効率が良い。新旧データの重みが滑らかに減衰する
  • 短所: パラメータ \(\alpha\) の選択が直感的でない場合がある

Python実装

def ema(x, alpha):
    """指数移動平均フィルタ"""
    y = np.zeros_like(x, dtype=float)
    y[0] = x[0]
    for t in range(1, len(x)):
        y[t] = alpha * x[t] + (1 - alpha) * y[t - 1]
    return y

EMAの周波数特性(ゲイン・位相特性)の詳細な解析は指数移動平均(EMA)フィルタの周波数特性を参照してください。

3つのフィルタの比較

比較実験

ノイズを含む信号に対して、3つのフィルタを適用して比較します。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
n = 200
t = np.linspace(0, 4 * np.pi, n)

# 元の信号 + ノイズ
signal = np.sin(t) + 0.5 * np.sin(5 * t)
noise = np.random.normal(0, 0.5, n)
observed = signal + noise

# フィルタ適用
window = 15
alpha = 2 / (window + 1)

y_sma = sma(observed, window)
y_wma = wma(observed, window)
y_ema = ema(observed, alpha)

# プロット
fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharex=True)

axes[0, 0].plot(t, observed, alpha=0.4, label='Observed')
axes[0, 0].plot(t, signal, 'k--', label='True signal')
axes[0, 0].set_title('Original')
axes[0, 0].legend()

axes[0, 1].plot(t, observed, alpha=0.3)
axes[0, 1].plot(t, y_sma, label=f'SMA (N={window})')
axes[0, 1].set_title('SMA')
axes[0, 1].legend()

axes[1, 0].plot(t, observed, alpha=0.3)
axes[1, 0].plot(t, y_wma, label=f'WMA (N={window})')
axes[1, 0].set_title('WMA')
axes[1, 0].legend()

axes[1, 1].plot(t, observed, alpha=0.3)
axes[1, 1].plot(t, y_ema, label=f'EMA (α={alpha:.3f})')
axes[1, 1].set_title('EMA')
axes[1, 1].legend()

for ax in axes.flat:
    ax.grid(True, alpha=0.3)
    ax.set_ylabel('Amplitude')

axes[1, 0].set_xlabel('Time')
axes[1, 1].set_xlabel('Time')
plt.tight_layout()
plt.show()

特性比較表

特性SMAWMAEMA
重みの分布均一線形減衰指数減衰
メモリ使用\(O(N)\)(窓幅分のバッファ)\(O(N)\)\(O(1)\)(前回値のみ)
計算量(1ステップ)\(O(N)\)(差分法で\(O(1)\))\(O(N)\)\(O(1)\)
過去データの影響窓外で完全に0窓外で完全に0指数的に減衰するが0にはならない
遅延\((N-1)/2\) サンプルSMAより小さい\(\alpha\)依存、最も小さい
ステップ応答直線的に上昇曲線的に上昇指数的に収束

周波数特性の比較

SMAの伝達関数は以下のとおりです。

\[ G_{SMA}(z) = \frac{1}{N} \sum_{i=0}^{N-1} z^{-i} = \frac{1}{N} \cdot \frac{1 - z^{-N}}{1 - z^{-1}} \tag{4} \]

SMAのゲイン特性にはゼロ点(特定周波数でゲインが0になる点)が存在するのに対し、EMAのゲインは単調に減少します。この違いにより、SMAは特定周波数の成分を完全に除去でき、EMAは全体的に滑らかな減衰特性を持ちます。

各フィルタの周波数特性の詳細な比較はローパスフィルタの設計と比較も参照してください。

用途別の選択ガイド

用途推奨フィルタ理由
センサデータの前処理EMAメモリ効率が良く、リアルタイム処理に適している
株価・金融データのトレンド分析SMA / EMASMAはテクニカル分析の標準指標、EMAは短期トレンドの追従に優れる
組み込みシステムEMA\(O(1)\)のメモリと計算量で実装可能
オフライン信号処理SMA / WMAバッチ処理なのでメモリ制約が緩く、窓幅ベースの制御が直感的
ノイズの周波数が既知の場合SMA窓幅を調整してゼロ点を目的周波数に合わせられる

関連記事

参考文献

  • Smith, S. W. (1997). The Scientist and Engineer’s Guide to Digital Signal Processing. California Technical Publishing.
  • Oppenheim, A. V., & Schafer, R. W. (2009). Discrete-Time Signal Processing (3rd ed.). Prentice Hall.