機械学習のためのデータ前処理:時系列分析で役立つラグ特徴量と移動平均の作り方【Pandas入門】
はじめに
機械学習を用いて未来の出来事を予測する際、過去のデータが時間の流れに沿って並んでいる「時系列データ」を扱う機会は少なくありません。例えば、過去の売上データから将来の売上を予測したり、過去の株価データから将来の株価を予測したりといった分析は、時系列データ分析の典型的な例です。
時系列データを使った予測モデルを構築する際には、通常のテーブルデータとは異なる、特有の前処理が重要になります。中でも、時系列データの持つ時間的な依存性をモデルに学習させるために不可欠なのが、ラグ特徴量と移動平均といった特徴量の作成です。
この記事では、時系列データの前処理においてなぜこれらの特徴量が必要なのか、そしてPythonのデータ分析ライブラリであるPandasを使って、具体的にどのようにこれらの特徴量を作成するのかを、コード例を交えて分かりやすく解説します。プログラミング経験があまりない方でも理解できるよう、基本的な考え方から丁寧にご説明します。
時系列データとは
時系列データとは、ある事象の観測値を時間の経過とともに記録したデータ系列のことです。一つ一つのデータには、それが観測された「時刻」や「日付」といった時間情報が付随しています。
ビジネスにおいて時系列データは非常に身近に存在します。 * 日々の売上高 * 毎月の生産量 * 毎時間のウェブサイトアクセス数 * 株価の終値 * 気温や降水量
これらのデータは、過去の値が未来の値に影響を与える傾向(自己相関)や、特定の周期で変動する性質(季節性)、時間とともに増加または減少する傾向(トレンド)を持っていることがあります。機械学習モデルがこれらの時間的なパターンを捉え、より正確な予測を行うためには、データ前処理の段階でこれらのパターンを特徴量として explicit に(明示的に)与えてあげることが有効です。
サンプル時系列データの準備
解説のために、簡単なサンプル時系列データを作成します。ここでは、日付とそれに紐づく数値(例えば日々の売上など)のデータを持つPandasのDataFrameを作成します。
import pandas as pd
import numpy as np
# サンプルデータの作成
# 2023年1月1日から30日までの日付データを作成
dates = pd.date_range(start='2023-01-01', periods=30, freq='D')
# 日付に対応する数値データ(ランダムな変動に単純なトレンドと周期性を加えたもの)
# ここでは単純化のため、ランダムに生成
data = np.random.rand(30) * 10 + np.arange(30) * 0.5
# DataFrameの作成
df = pd.DataFrame({'Date': dates, 'Value': data})
# Date列をインデックスに設定
df = df.set_index('Date')
print(df.head())
Value
Date
2023-01-01 7.845102
2023-01-02 8.258111
2023-01-03 6.946456
2023-01-04 10.215612
2023-01-05 10.483185
上記のように、日付がインデックス(行のラベル)となったDataFrameが作成できました。これが時系列データの基本的な形です。
ラグ特徴量とは?
ラグ特徴量(Lagged Features)とは、過去の時点のデータ値を現在の時点の特徴量として利用する手法です。例えば、「昨日の売上」を「今日の売上予測」のための特徴量として使う場合、昨日の売上値は今日のデータに対する1日分のラグ特徴量となります。
なぜラグ特徴量が必要なのか
時系列データでは、直前の値や数日前の値が現在の値に強い影響を与えることがよくあります。例えば、昨日の売上が高ければ今日も高い傾向があるかもしれません。機械学習モデルは、与えられた特徴量からパターンを学習しますが、単に「今日のデータ値そのもの」だけでは、このような時間的な依存関係を直接的に学習することが難しい場合があります。
そこで、データ前処理の段階で「N日前の値」といったラグ特徴量を作成し、これを新しい列としてデータに追加します。これにより、モデルは現在のデータだけでなく、過去の値も参照しながら予測を行うことができるようになり、時系列データの持つ時間的な構造を効果的に捉えることが可能になります。
Pandasでのラグ特徴量作成方法
Pandasでは、shift()
メソッドを使うことで簡単にラグ特徴量を作成できます。shift(n)
は、シリーズやDataFrameの値を指定した数n
だけずらす操作を行います。時系列データでは、インデックス(日付)に基づいてデータをずらしてくれるため、ラグ特徴量の作成に非常に便利です。
例えば、1日前の値(ラグ1)を特徴量として追加するには、以下のようにします。
# ラグ1特徴量の作成 (1日前の値)
df['Value_Lag1'] = df['Value'].shift(1)
print(df.head())
Value Value_Lag1
Date
2023-01-01 7.845102 NaN # 1日前のデータは存在しないため欠損値(NaN)になる
2023-01-02 8.258111 7.845102
2023-01-03 6.946456 8.258111
2023-01-04 10.215612 6.946456
2023-01-05 10.483185 10.215612
新しい列Value_Lag1
が追加されました。2023-01-02
の行を見ると、Value_Lag1
の値は2023-01-01
のValue
の値と同じになっていることが分かります。データが1つ前の行にシフトされたイメージです。最初の行には1日前のデータが存在しないため、欠損値(NaN)が生成されます。
複数の期間のラグ特徴量を作成することも可能です。例えば、1日前、2日前、3日前の値を追加する場合。
# ラグ1, 2, 3特徴量の作成
df['Value_Lag2'] = df['Value'].shift(2)
df['Value_Lag3'] = df['Value'].shift(3)
print(df.head())
Value Value_Lag1 Value_Lag2 Value_Lag3
Date
2023-01-01 7.845102 NaN NaN NaN
2023-01-02 8.258111 7.845102 NaN NaN
2023-01-03 6.946456 8.258111 7.845102 NaN
2023-01-04 10.215612 6.946456 8.258111 7.845102
2023-01-05 10.483185 10.215612 6.946456 8.258111
ラグ特徴量は、どの期間のラグが予測に有効かを検討しながら、複数作成することが一般的です。例えば、週次の周期性があるデータなら、7日前のラグ特徴量が有効かもしれません。
移動平均とは?
移動平均(Moving Average)とは、時系列データを滑らかにするためや、トレンドを把握するために用いられる統計的な指標です。これは、特定の期間(ウィンドウサイズ)内のデータ値の平均値を計算し、そのウィンドウを時間とともに移動させながら計算を続けることで得られます。
なぜ移動平均が必要なのか
時系列データには、日々の細かい変動(ノイズ)が含まれていることが多いです。このノイズが多すぎると、 underlying な(潜在的な)トレンドや周期性が obscured(隠されて)しまい、機械学習モデルが重要なパターンを学習しにくくなることがあります。
移動平均を計算することで、一時的な変動が平準化され、より長期的なトレンドや季節性といったマクロな動きを捉えやすくなります。また、過去数日間の平均値が未来の値に影響を与えるという考え方に基づき、移動平均自体を強力な特徴量として利用することができます。
Pandasでの移動平均作成方法
Pandasでは、rolling()
メソッドとそれに続く集計メソッド(例えばmean()
)を組み合わせて移動平均を作成します。rolling(window=n)
は、指定したウィンドウサイズn
で移動する「窓」のようなオブジェクトを作成し、その窓内のデータに対して後続のメソッドを適用します。
例えば、3日間の移動平均を計算するには、以下のようにします。
# 3日間の移動平均特徴量の作成
df['Value_MA3'] = df['Value'].rolling(window=3).mean()
print(df.head())
Value Value_Lag1 Value_Lag2 Value_Lag3 Value_MA3
Date
2023-01-01 7.845102 NaN NaN NaN NaN # 3日分のデータがないためNaN
2023-01-02 8.258111 7.845102 NaN NaN NaN # 3日分のデータがないためNaN
2023-01-03 6.946456 8.258111 7.845102 NaN 7.683223 # (7.845 + 8.258 + 6.946) / 3
2023-01-04 10.215612 6.946456 8.258111 7.845102 8.473393 # (8.258 + 6.946 + 10.215) / 3
2023-01-05 10.483185 10.215612 6.946456 8.258111 9.215084 # (6.946 + 10.215 + 10.483) / 3
新しい列Value_MA3
が追加されました。2023-01-03
の行のValue_MA3
は、2023-01-01
から2023-01-03
までのValue
の平均値になっています。同様に、2023-01-04
のValue_MA3
は、2023-01-02
から2023-01-04
までのValue
の平均値です。
移動平均もラグ特徴量と同様に、ウィンドウサイズをいくつか試して、モデルの性能が最も高くなるサイズを選択することが一般的です。例えば、7日間の移動平均は週次のトレンドを捉えるのに役立つでしょう。
ラグ特徴量と移動平均の組み合わせ
ラグ特徴量と移動平均は、それぞれ異なる時間的な情報を捉えるため、両方を組み合わせて特徴量として利用することで、モデルの表現力を高めることができます。例えば、最新のラグ値と、比較的長期的な移動平均を組み合わせることで、短期的な変動と長期的なトレンドの両方を考慮した予測が可能になります。
先ほど作成したDataFrameには、すでにラグ特徴量と移動平均が含まれています。これらの列をすべて特徴量として機械学習モデルに与えることで、時系列データの特性をより深く学習させることができます。
生成された欠損値への対処
ラグ特徴量や移動平均を作成する際に、データの先頭部分には計算に必要な過去のデータが存在しないため、欠損値(NaN)が発生します。
Value Value_Lag1 Value_Lag2 Value_Lag3 Value_MA3
Date
2023-01-01 7.845102 NaN NaN NaN NaN
2023-01-02 8.258111 7.845102 NaN NaN NaN
2023-01-03 6.946456 8.258111 7.845102 NaN 7.683223
...
多くの機械学習モデルは欠損値をそのまま扱うことができません。これらの欠損値に対しては、適切な対処が必要です。一般的な方法としては、以下のようなものがあります。
- 欠損値を含む行を削除する: 特徴量作成によって発生した欠損値はデータの先頭部分に集中するため、該当する少数の行であれば削除することも有効です。
- 他の値で補完する: 平均値、中央値、あるいは直前の有効な値などで補完する方法です。ただし、時系列データの場合は、過去の値で補完することが自然である場合が多いです。
例えば、欠損値を含む行を削除する場合。
# 欠損値を含む行を削除
df_cleaned = df.dropna()
print(df_cleaned.head())
この例では、ラグ3と移動平均3日を同時に作成したため、最初の3行が欠損値を含んでおり、それらの行が削除されました。
欠損値への対処方法は、データの性質や分析の目的に応じて慎重に選択する必要があります。これまでの記事でも欠損値の対処法について詳しく解説していますので、そちらも合わせてご参照ください。
まとめ
この記事では、機械学習のための時系列データ前処理において非常に重要となる、ラグ特徴量と移動平均の作成方法について解説しました。
- ラグ特徴量は、過去のデータ値を現在の時点の特徴量として利用することで、時系列データの自己相関をモデルに学習させるために有効です。Pandasの
shift()
メソッドで簡単に作成できます。 - 移動平均は、一定期間内の平均値を計算することで、データのノイズを平準化し、トレンドや周期性を捉えやすくします。Pandasの
rolling().mean()
メソッドで作成できます。
これらの特徴量を適切にデータに追加することで、機械学習モデルは時系列データの時間的な構造をより効果的に学習し、予測精度を高めることが期待できます。
データ前処理は機械学習モデル構築の要です。特に時系列データのように時間的な依存性を持つデータでは、その性質を理解し、適切な特徴量を作成することが成功の鍵となります。この記事が、皆様の時系列データ分析にお役立てできれば幸いです。