競馬レース結果の取得して色々見てみたい　前処理編



## 初めに
最近競馬にハマっており、データを見ながら予想や結果を語りたいなと思うようになりました。
なので、結果を可視化してみて色々見てみたいと思います。

当方開発経験がなく、今までほぼpythonを触ったこともない人間ですので拙いコードを書きますが、暖かい目で見て頂ければと思います。


## データの取得
netkeibaから、2010年~2013年のレース結果を用いたいと思います。
[netkeiba](https://www.netkeiba.com/)

また、今回はデータの可視化が目的なので、データを取得する部分に関しては下記サイト様を参考にさせていただきました。
[リラックスした生活を過ごすために](https://relaxing-living-life.com/676/)


取得したデータ
```python
import pandas as pd
df=pd.read_csv('レース結果.csv', encoding='cp932')
df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/92cd776c-cc02-97f1-742c-bcb6d668818c.png)

## データの加工

###### 欠損値の確認、除去
```python
df.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/d0991b62-c479-ea58-8fe1-ce084b0f29be.png)


```python
df=df.dropna()
df.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/d9890e2b-ce27-1a5f-0c4a-e08e56ae0db3.png)
###### データの全角、半角を除去

データ内に「ダート 」のように文字の後に半角があったので、除去します。
```python
df=df.map(lambda x : x.strip() if isinstance(x, str) else x)
```

###### データ型の確認

```python
df.dtypes
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/1d695b9c-1724-78bd-665e-527e9db47276.png)


###### タイムを秒に変換
機械学習を行うとなった場合、説明変数にしたいので、あらかじめ行っておきます。

```python
def object_to_seconds(object):
    minutes,seconds=map(float,object.split(':'))
    total_seconds=minutes*60+seconds
    return total_seconds
df.insert(loc=df.columns.get_loc('タイム') + 1, column='タイム_秒', value=df['タイム'].apply(object_to_seconds))

df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/513a3b31-bc01-a082-ec4e-a3718f777e30.png)


###### 開催日変換

開催日が20221023のようになっているデータは文字化けをしており、上手く取得できなかったので、手作業で保存し、その後型変換を行いました。

```python
df['開催日']=pd.to_datetime(df['開催日'], format='%Y年%m月%d日')
df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/557044ac-84cb-f5cd-21a5-5751a2962474.png)

###### 通過表記変換
m月d日のような表示であったり、
「1-1-1」の表記が、2001/1/1のような表示になっているので修正します

```python
import re
# 通過のフォーマットを変換する関数
def convert_pass(pass_str):
    pattern_1 =r'(\d{1,2})月(\d{1,2})日'
    pattern_2 =r'(\d{1,4})/(\d{1,2})/(\d{1,2})'
    # 'm月d日の場合はm-dの形にして返す
    if re.match(pattern_1, pass_str):
        return re.sub(pattern_1,r'\1-\2',pass_str)
    # 「1-1-1」の表記が、2001/1/1のような表示になっているので修正する
    elif re.match(pattern_2, pass_str):
        match=re.match(pattern_2, pass_str)
        t1=match.group(1)
        t2=match.group(2)
        t3=match.group(3)
        if t1[-2]=='0':
            t1=t1[-1]
        else:
            t1=t1[-2]
        return f'{t1}-{t2}-{t3}'
    # 上記以外の場合は元の文字列を返す
    else:
        return pass_str
# 通過カラムを変換
df['通過'] = df['通過'].apply(convert_pass)
```

###### 競馬場追加
競馬場カラムの追加を行います
```python

df['競馬場']=df['開催場所'].map(lambda x:re.sub(r'\d+回\s*|\s*\d+日目', '', x))
df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959043/89c8409a-9118-d0b6-d113-6b39dd984100.png)

###### 着順変換
着順カラムに失格や14(降)の表記があります。
失格は除外し、降着は(降)を取り除き、着順をint型に変換します。

```python
# 失格は除外、降着は（降）を取り除く処理
df = df[df['着順'] != '失']

def convert_rank(rank_str):
    pattern = r'(\d{1,2})(降)?' 
    match = re.match(pattern, rank_str)
    if match:
        return match.group(1)  
    else:
        return rank_str
df['着順'] = df['着順'].apply(convert_rank)

print(df['着順'].unique())
```
```python
#着順をint型に修正
df['着順'] = df['着順'].astype(int)
```

## ファイル出力

保存用に加工後ファイルを出力しておきます。
```python
#加工後データcsv出力

df.to_csv('レース結果加工後.csv',index=False,encoding='cp932')
print('出力完了しました')
```

取得したデータを競馬場毎に分割して出力します。


レース種別（芝、ダート）に分けた後、各競馬場に分割します。。
```python
#馬場,競馬場ごとにcsv出力

groundtype_list=['ダート','芝']
place_list=['札幌', '函館', '福島','新潟','東京','中山','中京','京都','阪神','小倉']

for ground in groundtype_list:
    df_ground = df[df['馬場'] == ground]
    
    for place in place_list:
        df_place = df_ground[df_ground['競馬場'] == place]
        
        # df_placeが空でない場合のみ処理を実行
        if not df_place.empty:
            title = 'レース結果_{}/レース結果_{}_{}.csv'.format(ground,ground,place)
            df_place.to_csv(title, index=False, encoding='cp932')
            print("処理完了しました:", title)
        else:
            print("データがありません:", title)
```




## あとがき
本当に初めてなので、未熟な部分や問題があるかと思います。
とりあえず分割したデータでグラフを出力できたので、前処理としてはこのあたりで止めておきます。
今後データをいじった際に必要になったとき追記します。

前処理が9割なんて話をよく聞いていましたが、本当にその通りで、ここまでするのにとんでもなく時間がかかりました。

今回作成したコードは以下のmaesyori.ipynbにのせてあります（少しごちゃついてて見にくいですが、、）ので、興味あればのぞいてみてください。

https://github.com/Kddikdi/Python.git

次回は本当に簡単な可視化作業から行っていきたいと思います。
以上ここまで読んで頂きありがとうございました。