LoginSignup
2
2

More than 3 years have passed since last update.

【第2回】Python で競馬予想してみる ~ データの前処理(CSVデータの読み込み~各種処理) ~

Last updated at Posted at 2020-11-23

第1回目の記事は、環境設定とデータの取得まで終了
今回は、データの前処理(CSVデータの読み込みからデータの各種処理)をやってみるのだ

開発環境

Anaconda3 のインストール

データの取得

ターゲットフロンティアの出力データを使用

ターゲットフロンティアのレース検索で CVS 出力

※前回はここまで終了-------------------------------

データの前処理

CVS の読込みについて

20年分の全データを読み込んでみたら Wall time: 41.3 s

CSV ファイルの読み込みについては、pandas をインポートして簡単に成功
エンコードは、shift-jis でも大丈夫と書いてあるのだが、エラーが出るので encoding = 'cp932' に修正(cp932 ってなんだ💦)
データ型も指定しないとエラーがでるので、とりあえず全てオブジェクト型で取り込み
(指定しないとこの後のマージができなかったので応急処置。よい処理方法あれば教えて下さい)

rd_2000all.csv には 2000年からのレース検索で得られる全データを詰め込んで読み込んでみた
Wall time: 41.3 s
ターゲットフロンティアからの出力もかなりの時間を要したし、この出力データは使わないこととした

build.ipynb
%%time
import pandas as pd

# csvデータ読込み
rd = pd.read_csv('rd_2000all.csv'
 , encoding = 'cp932'
 , dtype = 'object'
 , skipinitialspace = True
 )

Wall time: 41.3 s

build.ipynb
rd.info()


RangeIndex: 1024923 entries, 0 to 1024922
Columns: 274 entries, M to ←
dtypes: object(274)
memory usage: 2.1+ GB

20年分の使うかもしれないデータだけを読込み

rd2000all.csv には 20000年からのレース検索で得られる全データを詰め込んで読み込んでみたが、やはり遅い
絶対に使わないデータだけを削除して rd2000.csv を読み込んでみた
私の能力低い PC で 13秒
とりあえず、このデータで進めてみる

build.ipynb
%%time
import pandas as pd

# csvデータ読込み
rd = pd.read_csv('rd2000.csv'
 , encoding = 'cp932'
 , dtype = 'object'
 , skipinitialspace = True
 )
Out
Wall time: 13.3 s
build.ipynb
rd.info()
Out
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1024923 entries, 0 to 1024922
Data columns (total 75 columns):
 #   Column          Non-Null Count    Dtype 
(省略)
dtypes: object(75)
memory usage: 586.5+ MB

n 走前までのデータを連結

CSV で取り込んだデータは、カラム数が 75個
今回は出走馬の実力を測る特徴量として、
予想するレースでは、斤量のみ
n 走前のレースでは 斤量・単勝オッズ・人気・補正(補正タイム:クラス内相対値)・補9(補正タイム:絶対値)、確定順位 を使用した
※予想するレースの人気やオッズを入れると人気馬ばかりの予想結果になるので、予想するレースの特徴量は 斤量 のみとした。今後は、馬特有データの血統などは特徴量として扱いたい

レースID 各データ 前走ID
ID01 *** ID10
ID02 *** ID11
ID10 *** ID20
ID11 *** ID21
ID20 *** ID30
ID21 *** ID31

とりあえず、今のデータフレーム(↑)は 1 レース分の各データが入っているので、それをレースID と前走ID をマージして n 走前までのデータが連結したデータフレーム(↓)に加工してみた。
この部分については参考になるコードが見つからなかったので python 初心者らしい!?力技で解決したのだ。
※もっとスマートなコードの書き方教えて下さい

レースID 予想レースデータ 前走ID 1走前データ 前々走ID 2走前データ 3走前ID
ID01 *** ID10 *** ID20 *** ID30
ID02 *** ID11 *** ID21 *** ID31
ID10 *** ID20 *** ID30
ID11 *** ID21 *** ID31
ID20 *** ID30
ID21 *** ID31

欠損地処理、データ型処理、目的変数の処理

その後、欠損値処理、データ型処理、目的変数の処理を行った
目的変数は、出走馬の着順を 3着以内なら 1、4着以下なら 0 に変更した

build.ipynb
# カラム抽出 使用するカラムを抽出
rd = rd[['レースID(新)', '斤量', '単勝オッズ', '人気', '補正', '補9', '確定着順', '前走レースID(新)']]

# 斤量のマークを外す
rd['斤量'] = rd['斤量'].str.extract('(\d+)', expand=False)

# 過去レース用 rd_pr にコピー
rd_pr = rd.copy() 

# rdは、直近レースデータ用+目的変数 ID、斤量、確定着順
rd = rd.drop(['単勝オッズ', '人気', '補正', '補9'], axis=1)

# n走前まで連結(もっとスマートなコードの書き方教えてください)
n = 1
rd_pr_cn = rd_pr.columns

for i in range(n): # もっとスマートなコードの書き方教えてください
    rd_pr.columns = rd_pr_cn
    rd_pr = rd_pr.rename(columns=lambda s: str(i+1) + '_' + s)
    rd_pr = rd_pr.rename(columns={str(i+1)+'_レースID(新)': '前走レースID(新)'})
    rd = pd.merge(rd, rd_pr, on = '前走レースID(新)', how='left')
    rd.drop([ '前走レースID(新)'], axis=1, inplace=True)
    rd = rd.rename(columns={str(i+1)+'_前走レースID(新)': '前走レースID(新)'})

rd.drop(['レースID(新)', '前走レースID(新)'], axis=1, inplace=True)

# 欠損値があるレコードは除去
rd.dropna(how='any', inplace=True)

# データフレーム全体の型を変更
rd = rd.astype(float)

# 着順が3着以内かどうかのカラムを追加する
f_ranking = lambda x: 1 if x in [1, 2, 3] else 0
rd['3着以内'] = rd['確定着順'].map(f_ranking)
rd.drop(['確定着順'], axis=1, inplace=True)

とりあえず、これでデータの前処理は完了
データフレームの内容を確認するとこうなります
スクリーンショット 2020-11-23 14.19.38.png

2
2
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
2
2