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

第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 
ターゲットフロンティアからの出力もかなりの時間を要したし、この出力データは使わないこととした

```Python: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

```Python:build.ipynb
rd.info()
```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1024923 entries, 0 to 1024922
Columns: 274 entries, Ｍ to ←
dtypes: object(274)
memory usage: 2.1+ GB

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

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

```Python:build.ipynb
%%time
import pandas as pd

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

```text:Out
Wall time: 13.3 s
```

```Python:build.ipynb
rd.info()
```
```text: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 に変更した

```Python: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895631/3532e7f8-71b1-1c34-b090-5ac3db7d3298.png)