システムトレードは、コンピュータが自動で取引を行い利益を目指す手法です。
機械学習を活用してシステムトレードを行う際には、大量のデータを正しく使うことが重要です。ですが、生のデータをそのまま使うと、うまく学習できなかったり、正確な予測ができなかったりすることがあります。
そのため「データの前処理」という工程が欠かせません。この記事では、機械学習に適したデータの前処理方法を、中学生でもわかるように解説します。
データの前処理とは何か
データの前処理とは、分析や学習に適した形にデータを整える作業のことです。生のデータには「欠けている値」や「極端な値」などの問題が含まれることがあります。そのまま使うと予測精度が下がったり、学習の妨げになるため、適切な処理が必要です。
データの前処理の目的は、データを「使いやすく」「正確に」することです。これにより、機械学習が正しく学習できるようになり、システムトレードの精度も向上します。
データの前処理の主な手法
システムトレードに使うデータを前処理する際には、いくつかの基本的な方法があります。それぞれの手法について詳しく見ていきましょう。
1. 欠損値の処理
データが部分的に欠けていることを「欠損」と呼びます。例えば、株価データの中に、特定の日だけ取引量のデータが抜けている場合があります。そのような欠損値をそのままにすると、学習の妨げになるため、何らかの方法で対処する必要があります。
欠損値処理の方法
- 平均値で埋める:欠けているデータを、他の日の平均値で補います。
- 前後のデータで埋める:直前や直後のデータを利用して欠損を埋めます。
- 欠損データを削除する:欠損が多い場合は、そのデータごと取り除くこともあります。
2. 異常値(外れ値)の処理
異常値は、他のデータから大きく離れた値のことです。例えば、ある日の株価だけ極端に高くなっている場合、それが異常値かどうかを確認する必要があります。異常値があると、分析結果が大きくずれてしまうことがあるため、適切に処理します。
異常値処理の方法
- 削除する:異常値が明らかに間違いであるとわかる場合、そのデータを削除します。
- 他の値に置き換える:平均値や中央値で異常値を置き換える方法もあります。
3. データのスケーリング(標準化と正規化)
データのスケーリングは、データの値を一定の範囲にそろえる処理です。株価や出来高など、数値の範囲が大きく異なるデータをそのまま使うと、機械学習が一部の特徴に偏りやすくなるため、範囲をそろえます。
- 標準化:データの平均を0、標準偏差を1にします。これにより、データが同じスケールで扱われるようになります。
- 正規化:データの最小値を0、最大値を1にそろえる方法です。データが0から1の範囲に収まるため、計算がしやすくなります。
4. カテゴリデータの変換
カテゴリデータとは、「値上がり」や「値下がり」のように、数値ではなく種類を表すデータです。このままでは機械学習で扱えないため、数値に変換する必要があります。
カテゴリデータの変換方法
- ワンホットエンコーディング:カテゴリごとに「0」か「1」を割り当てる方法です。例えば、「値上がり」を1、「値下がり」を0として扱います。
データの前処理の具体例
次に、これまで説明した前処理を使って、株価データの処理を行う例を紹介します。
データの前処理例
ここでは、Pythonを使って株価データを前処理するコードを紹介します。
# 必要なライブラリをインポート
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# ダミーデータの作成(実際のデータでは株価や出来高のデータを使用)
data = pd.DataFrame({
'price': [100, 102, np.nan, 105, 107, 108, 250, 110, 115, 120], # 一部に欠損値や異常値が含まれる
'volume': [2000, 2100, 2150, 2200, 2300, 2400, 2500, 2450, 2600, 2700]
})
# 欠損値を前後の値で補完
data['price'].fillna(method='ffill', inplace=True)
# 異常値を平均値に置き換え
mean_price = data['price'].mean()
data['price'] = np.where(data['price'] > 200, mean_price, data['price'])
# データのスケーリング(標準化)
scaler = StandardScaler()
data[['price', 'volume']] = scaler.fit_transform(data[['price', 'volume']])
# 結果を表示
print(data)
コードの解説
以下は、上記コードの各部分について解説したものです。
必要なライブラリをインポート
まず、このコードを動かすために、numpy
とtensorflow.keras
のライブラリをインポートしています。ライブラリとは、便利な関数やクラス(特定の機能を持つコードのまとまり)を集めたもので、これをインポートすることで、すぐに使えるようになります。
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN, Dense
ここで、numpy
はデータの配列(複数のデータを一まとめにして扱える形式)を操作するために使います。tensorflow.keras
は、機械学習用のライブラリで、この中のSequential
とSimpleRNN
、Dense
というクラスや関数を使って、データの学習と予測を行います。
ダミーデータの準備
data = np.array([100, 102, 101, 105, 107, 108, 110, 115, 120, 125, 130, 128, 129, 133, 135, 138, 140, 145, 150, 155])
ここでは、実際のデータの代わりにdata
という名前のダミーデータ(例となるデータ)を作成しています。このデータは、過去の株価終値が順番に並んでいると考えます。np.array
は、リストを「配列」として扱えるようにするためのものです。配列を使うと、たくさんのデータをまとめて処理できます。
データの変換
X = np.array([data[i:i+5] for i in range(len(data) - 6)])
y = data[6:]
機械学習で使うデータは、学習に適した形に変換する必要があります。X
は入力データ、y
は予測したい目標データです。
for i in range(len(data) - 6)
という部分は、i
を0からlen(data) - 6
まで動かすという意味です。data[i:i+5]
は、data
から連続した5つのデータを取り出す部分です。
モデルの作成
model = Sequential()
model.add(SimpleRNN(10, activation='relu', input_shape=(5, 1)))
model.add(Dense(1))
ここでは、Sequential
というクラスを使って、予測のためのモデルを作成しています。Sequential()
は、モデルの「入れ物」を作るためのクラスです。
SimpleRNN(10, activation='relu', input_shape=(5, 1))
は、RNN(リカレントニューラルネットワーク)というタイプの層を作成します。
10
は、この層の中にある「ニューロン」(情報を処理する部分)の数です。activation='relu'
は、活性化関数の種類を指定しています。活性化関数とは、次に送る値の範囲を調整するための関数で、relu
は一般的に使われる方法です。
※活性化関数についての詳細は下記の記事をご参照ください。
input_shape=(5, 1)
は、入力データの形を指定します。5つの値を1つの配列として扱う形になります。
model.add(Dense(1))は、最終的に1つの値を出力する層(出力層)を追加しています。Dense
とは、全てのニューロンが次の層のすべてのニューロンとつながっている「密結合層」のことです。
モデルのコンパイル
model.compile(optimizer='adam', loss='mse')
ここでは、model.compile
メソッドを使って、学習に使う方法を設定しています。
optimizer='adam'
は、最適化手法の指定です。adam
は学習を効率よく進めるための方法です。loss='mse'
は、損失関数を指定します。損失関数は、予測の結果がどれだけ正しいかを評価するためのもので、mse
は「平均二乗誤差」といって、予測値と正解の値の差が大きいほど損失が大きくなる方法です。
モデルの学習
model.fit(X.reshape(-1, 5, 1), y, epochs=100)
ここで、model.fit
メソッドを使って、モデルを学習させます。
X.reshape(-1, 5, 1)
は、入力データX
の形を変更して、RNNに適した形にしています。-1
はデータの個数に自動で合わせ、5, 1
は「5日分のデータを1つの配列として扱う」という意味です。y
は目標データで、予測したい次の日の株価のデータです。epochs=100
は、学習を100回繰り返すという設定です。学習回数を増やすほどモデルは多くのパターンを覚えますが、増やしすぎると逆に精度が下がることもあります。
次の日の株価を予測
next_day_prediction = model.predict(X[-1].reshape(1, 5, 1))
print("予測される次の日の株価:", next_day_prediction)
最後に、model.predict
メソッドを使って、次の日の株価を予測します。
X[-1].reshape(1, 5, 1)
は、最新の5日間のデータをRNNに適した形に変換しています。X[-1]
はX
の最後のデータを取り出す方法です。model.predict
は、入力データをもとにモデルが予測した結果を返します。print
関数を使って、予測された次の日の株価を表示します。
データの前処理を行う際の注意点
データの前処理は予測精度を高めるために重要ですが、いくつかの注意点があります。
- 過度な処理を避ける:データを処理しすぎると、逆に重要な特徴を失ってしまうことがあります。例えば、異常値でも相場の特徴を表している場合は、そのまま扱うこともあります。
- 目的に合った処理を行う:たとえば、価格のスケーリングは標準化が適している場合もあれば、正規化が適している場合もあります。目的に合わせた手法を選ぶことが重要です。
- データの順序を確認する:時系列データ(時間の流れに沿ったデータ)は、データの順序が重要です。前処理の際も順序を崩さないように気をつけます。
まとめ
機械学習を使ったシステムトレードでは、データの前処理が非常に重要な役割を果たします。前処理を正しく行うことで、データが「使いやすく」「正確」になり、予測精度が向上します。欠損値や異常値の処理、スケーリングやカテゴリデータの変換など、目的に応じた適切前処理を行い、機械学習がより正確に学習できるデータを整えましょう。システムトレードでのデータ分析をより効果的にするため、前処理の重要性を理解し、実践に役立ててください。