0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AI投資システム構築】2.データの前処理方法

Last updated at Posted at 2025-03-01

データの前処理方法

前回の投稿「1. 学習用データの集め方」にて、為替レート(Open, Close, High, Low, Volume)の時系列データがCSVファイル等で入手できていることとします。

このデータに対して、前処理を行います。

学習データの前処理は、分析対象によっては「前処理」だけで専門書が出版されるぐらい、とても大事な作業です。前処理のやり方によって、学習モデルの成否が大きく変わります。演算の誤りがないように、注意して行いましょう。

大きく分けて、3つの処理を実施します。

  1. データクレンジング
  2. 変化量へ変換
  3. スケーリング

プログラミング言語はPython3を用います。
NumPyPandas等のライブラリを使用すると、楽にデータ処理を行えます。
例えばPandasの場合、CSVファイルの読み込みは下記ソースコードのように、簡単に行えます。

CSVファイル読み込み
import pandas as pd

# 時系列データ(CSVファイル読み込み)
trade_df = pd.read_csv(filePath, index_col=False, usecols=['Time','Open','Close','High','Low','Volume'], encoding='UTF-16')

index_col, usecols, encoding は、読み込むCSVファイルの形式を確認し、適宜変更が必要です。

1. データクレンジング

不正データ(外れ値)や欠損データを補う処理を行います。

1.1. 外れ値の除去・補正

不正データ(外れ値)は、「2.変化量へ変換」のように、時系列データを変化量に変換後、
ヒストグラムにすると視覚的にわかりやすいです。外れ値があれば、下記図のようにわかるはずです。
Pythonに慣れている方は、Matplotlibライブラリ等を用いてご確認ください。
Excel等の表計算ソフトに慣れている人は、CSVファイルを直接開いて確認してもいいと思います。

外れ値例.png

このような外れ値を含んでいる場合、
quantile(分位数)を用いて外れ値を含むレコード(同時刻レコード)を検知して、
レコードごと(同じ時刻のOpen, Close, High, Low, Volumeを全て)除去するか、
他の値で置換します。

1.1.1. レコード除去の場合

学習用データが十分にある場合は、レコード除去が有効です。
正確なデータだけ使うようにしましょう。
Pandasを用いたソースコードの例は以下の通りです

外れ値を含んだレコード除去の例
# Open値ついて、95%の分位数よりも値が小さいデータを抽出してそれ以上の値を除外する
q = trade_df['Open'].quantile(0.95)
trade_df = trade_df[trade_df['Open'] < q]

1.1.2. 外れ値を置換の場合

学習用データが少なくレコード除去したくない場合は、置換もできます。
時系列データの場合は、前後の時刻データからある程度予測ができるからです。

例えば 時刻 t の間隔が短い場合、下記数式が成り立つはずです。

Open(t) ≒ Close(t-1)

正確には違いますが、もし Open 値が外れ値の場合、1時刻前の Close 値を用いても問題ないでしょう。
また、 High 値が外れ値の場合、下記数式で置き換えてもいいと思います。

High(t) ≒ \frac{High(t-1) + High(t+1)}{2}

こちらも正確には違いますが、外れ値が同時刻付近で頻発していない場合は、有効な手段かと思います。
Pandasを用いたソースコードの例は以下の通りです

外れ値を置換の例
q = trade_df['Open'].quantile(0.95)
outlier_df = trade_df[trade_df['Open'] < q]
outlier_list = outlier_df.index.tolist()

for index in outlier_list:
    # 1列目:'Open', 2列目:'Close'の場合、Close(t-1)で置換する
    trade_df.iloc[index, 1] = trade_df.iloc[index-1, 2]

:coffee: Coffee Break
前回の投稿に記載した通り、一昔前(10年ほど前)は、外れ値を含む為替の時系列データがたくさんWeb上に公開されていました。昨今はこのようなデータは少なくなったと実感しています。この節の処理は今後、使うことはないでしょう。

1.2. 欠損データの除去・補正

不正データ(外れ値)は少なくなりましたが、欠損データはたびたびあります。
特に注意しないといけないのが、時間の欠損です。

次回の投稿で詳しく記述するつもりですが、
1つの通貨ペアの情報だけで予測を行うのは、情報量が少なすぎるため限界があります。
そのため複数の通貨ペアの情報や、相関のある市場データ(株価等)も組み合わせて学習データにします。

その際、時刻毎データを並べると、例えば下記の表のように、同一時刻で特定のデータが欠損していることが多々あります。特に週替わりにはたびたび発生します。
また、アメリカなどで行われているサマータイムにも注意してください。
市場の取引時間が変わるためです。

Index Time USDJPY EURUSD AUDJPY
1 2020/01/23 01:00 150.569 1.03749 NaN
2 2020/01/23 01:05 150.579 1.03584 93.472
3 2020/01/23 01:10 150.489 1.03798 93.480
4 2020/01/23 01:15 150.864 1.03445 93.570
5 2020/01/23 01:20 150.568 1.03545 93.611
: : : : :
x 2020/01/24 00:00 150.001 NaN NaN

このような欠損データを含んでいる場合、上記「1.1. 外れ値の除去・補正」同様、
同時刻のレコードごと除去するか、1つ前の時刻レコードで置換します。

複数の時系列データの統合と、
欠損データを含むレコードを削除するときのソースコードの例は以下の通りです

時系列データの統合と欠損データを含むレコード削除の例

USECOLS = ['Time','Open','Close','High','Low','Volume'] #CSVファイルの全要素

df_A = pd.read_csv(csv_file_A, usecols=USECOLS,
                                parse_dates= ['Time']) # 時刻タイプに変換
df_B = pd.read_csv(csv_file_B, usecols=USECOLS,
                                parse_dates= ['Time']) # 時刻タイプに変換

# 時系列データの統合(Time列を基準とする)
df_AB = pd.merge(df_A, df_B, on='Time', how='outer')

# 欠損データを1つでも含む場合、レコード削除
df_AB = df_AB.dropna(how='any')

この時間の欠損に対する処理は、細心の注意を払うことをオススメします。
過去に、ソースコードを誤って、欠損データを1時刻先の未来のデータで置換したことがあります。
その学習データを用いて学習モデルを生成したところ、未学習の(はずの)未来の為替の予測精度が80%以上と、爆発的に向上したことがありました。 当時は大いに喜んで「すごいものをつくってしまった」と興奮したのを覚えています。
また、間違いに気づくまでだいぶかかったため(数か月)、皆様は同じ間違いを起こさないよう、ご注意ください。

2. 変化量へ変換

入手した時系列データを、機械学習で学習させるため、定常化させます。
具体的には、差分をとります。
これもPandasを用いると、とても簡単に実行できます。

差分化
df_AB = df_AB.diff()

以上です。ただし、0レコード目はすべてNaNデータとなりますので、削除してください。

3. スケーリング

最後に、機械学習で学習しやすいようにするため、「2. 変化量への変換」後のデータに対して数値変換を行い、平均や分散、最小値・最大値を変更します。USDJPYの変動が大きく、EURUSDの変動が小さいような、要素ごとの偏りを無くす目的があります。

ここで、スケーリングに関する一般的な用語を定義します。

  • 標準化:平均0,分散1へ変換
  • 正規化:0~1へ変換
  • 白色化:要素間の相関を無くす変換

詳しくは専門書籍や他のWebサイトをご参照ください。
ちなみに私は下記の書籍で学びました。数学寄りの専門書です。

どの手法を用いるのか、ここは個人の判断が分かれるところかと思います。
私の経験上、「1. データクレンジング」と「2. 変化量へ変換」まで完了したデータであれば、そこまで偏ったデータとはならず、通貨毎の特徴をなくしたくないと思い、あえて標準化のみを行っています。
(もしかしたら専門家の先生からしたら、それはダメだと言われるかもしれません)

標準化の数式は下記のとおりです。

平均:\bar{x} = \frac{1}{N} \sum_{n=1}^N x(n)
標準偏差:\sigma_{x} = \sqrt{\frac{1}{N} \sum_{n=1}^N (x(n) - \bar{x})^2}
x(t) ← \frac{x(t) - \bar{x}}{\sigma_{x}}

Pandasを用いたソースコードは下記のとおりです。

標準化
mean_val = df_AB .mean(axis=0) # 平均
df_AB  = df_AB  - mean_val
std_val = df_AB .std(axis=0) # 標準偏差
df_AB  = df_AB  / std_val

この変換後の時系列差分データをCSVファイル、またはNumpyファイルへ出力し、
以降の処理で用いています。

まとめ

学習用データの前処理方法について記載しました。
何度も記載していますが、この処理は丁寧に行い、計算式に誤りがないか何度も確認しましょう。誤ったデータで学習させるのは本当に無駄です。

また、専門書があるように、私が記載した内容はすべてではありません。
データ前処理の方法について、少しでも参考にしていただけますと幸いです。

次は、「学習に用いるデータの選定方法」について、投稿する予定です。
よろしくお願いいたします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?