MATLABで競艇の解析を始めよう（大量の出走表ファイルからデータを読み込み）

# MATLABでボートレース解析をする２番目の記事です。

[最初の記事] (https://qiita.com/teruqii/items/11c21882613db088e339) の通りにやると C:\work\boat フォルダにファイルができましたよね。

とりあえず自分は試しに2005年から2019年まで15年分取ってみましたが、時間はかかるし、1.75GB（ファイル数 10000 超）のテキストファイルでフォルダーが埋まってしまうし、結局こんなに使わないし、、、ということで、こんなに取らなくてもいいね。（捨てよう。。。）

## ボートレース豆知識
　どの期間のデータを取ればよさそうかと言うと、2012年4月27日前後で持ちペラ制度っていう自前のプロペラを使うことがなくなって、2019年現在まで抽選ボート＋抽選プロペラでレースをやってるので、2012年の5月以降のデータを使うと統一されたルールのデータセットになります。むしろ、もう少し後の落ち着いた頃のデータでもいいかもね。

※ 前後って書いてるのは、「4/27以降に初日を迎えるレース場～」とかの理由。

# そもそもダウンロードしたのはどんなファイルなんだっけ。
試しに 2019/8/1 の B の名前の付いたファイル（出走表）を空けてみるとこんな感じ。


>STARTB
23BBGN
ボートレース唐　津   　８月　１日  ヴィーナスシリーズ第  第　４日
                            ＊＊＊　番組表　＊＊＊
          ヴィーナスシリーズ第７戦ＲＫＢラジオ杯　　　　　　
   第　４日          ２０１９年　８月　１日                  ボートレース唐　津
               －内容については主催者発行のものと照合して下さい－
１Ｒ  一　　般　　          Ｈ１８００ｍ  電話投票締切予定０８：５５ 
\-------------------------------------------------------------------------------
艇 選手 選手  年 支 体級    全国      当地     モーター   ボート   今節成績  早
番 登番  名   齢 部 重別 勝率  2率  勝率  2率  NO  2率  NO  2率  １２３４５６見
\-------------------------------------------------------------------------------
1 4627藤原菜希33東京46A1 6.47 47.50 5.28 32.00 63 36.60 76 41.46 2S221       12
2 5019柴田百恵19静岡45B1 2.13  1.33 0.00  0.00 17 41.78 45 22.50 S44 4        7
3 4758富樫麗加29東京51B1 5.08 26.61 6.06 41.94 65 34.25 35 30.86 4 3664       5
4 4947間庭菜摘26福岡51B1 2.66 10.39 1.69  2.86 18 33.33 72 25.00 5 636        6
5 4994山本梨菜21佐賀48B1 2.75  3.45 1.77  0.00 25 34.38 65 25.33 264 4        6
6 5057上田紗奈23大阪45B2 1.66  1.00 0.00  0.00 33 29.05 55 32.91 6 656        5
　２Ｒ  一　　般　　          Ｈ１８００ｍ  電話投票締切予定０９：２４ 
\-------------------------------------------------------------------------------
艇 選手 選手  年 支 体級    全国      当地     モーター   ボート   今節成績  早
番 登番  名   齢 部 重別 勝率  2率  勝率  2率  NO  2率  NO  2率  １２３４５６見
\-------------------------------------------------------------------------------
1 4885大山千広23福岡47A1 6.73 46.94 3.92 15.38 26 42.27 66 29.73 31432       12
2 4556竹井奈美29福岡47A1 6.44 45.80 7.05 53.85 46 26.00 75 40.48 3S453        6
3 4938小芦るり21佐賀51B1 4.62 31.00 3.25 15.38 23 31.31 34 31.65 432 55       8
4 4923末武里奈27山口47B1 3.29 12.70 1.33  0.00 16 37.44 50 31.08 5 642        7
5 4997濱崎寿里26埼玉52B2 1.38  3.85 0.00  0.00 11 38.53 47 26.92 6 666        7
6 5013山下夏鈴22三重44B1 2.47  6.38 2.00  5.88 53 30.92 79 39.74 366 6        6
...
...
この間に、まだまだたくさんある。
...
...
23BEND
22BBGN
ボートレース福　岡   　８月　１日  誰が勝っても福岡初優  第　１日
...
ここから別の会場の情報。
...
>

この 1R だと断然 1-3-4 の３連単を買いたくなるのはさておき、今回は試しに個人の単位でテーブルをまとめてみましょう。

# MATLABでデータを取り込む
ボートレースは同じ日に同じ人が２回出てくることもあって、時々同じ行が出てくるので、データをまとめる場合は要注意ポイントです。MATLAB だと unique 関数を使えば同じデータは１つにまとまりますね。（超便利！）

あとは、セル配列とか構造体とかあるけど、こういうフォーマットであればテーブルデータが解析に向いてるデータ形式です。とりあえず、こんなプログラムで 2019/8/1 の分だけでも取ってみよう。


```matlab
ix = datenum('20190801','YYYYmmDD');
fname = ['B',datestr(ix,'YYmmDD'),'.TXT'];

fid = fopen(fname);
S = textscan(fid,'%s','delimiter','\n');
B = S{1};
fclose(fid);
B = B(~cellfun(@isempty,(regexp(B,'^\d \d+'))));
Personal = cellfun(@scanB,B,'Unif',0);
Personal = unique(cell2mat(Personal),'rows');
T_Person = array2table(Personal,'VariableNames',{'NameNo','Age','Weight','Class','A_WinRate','A_DoubleWinRate','L_WinRate','L_DoubleWinRate','Motor','M_DoubleWinRate','Boat','B_DoubleWinRate'});


function sc = scanB(txt)

NAME = str2double(txt(3:6));
MOTOR = str2double(txt(41:43));
BOAT = str2double(txt(50:52));
AGE = str2double(txt(11:12));
WEIGHT = str2double(txt(15:16));
if strcmp(txt(17:18),'A1')
    CLASS = 1;
elseif strcmp(txt(17:18),'A2')
    CLASS = 2;
elseif strcmp(txt(17:18),'B1')
    CLASS = 3;
else
    CLASS = 4;
end
A_WINRATE = str2double(txt(19:23));
A_DOUBLEWINRATE = str2double(txt(24:29));
L_WINRATE = str2double(txt(30:34));
L_DOUBLEWINRATE = str2double(txt(35:40));
M_DOUBLEWINRATE = str2double(txt(44:49));
B_DOUBLEWINRATE = str2double(txt(53:58));
sc = [NAME,AGE,WEIGHT,CLASS,A_WINRATE,A_DOUBLEWINRATE,L_WINRATE,L_DOUBLEWINRATE,MOTOR,M_DOUBLEWINRATE,BOAT,B_DOUBLEWINRATE];
end

```

　サブ関数 scanB にまとめてしまったけど、３～６文字目に名前があるとか文字数が決まってる場合は char 型の配列で txt(3:6) とか取ったほうがよくて、文字数じゃない場合は textscan とかしたほうが融通が効きます。

このスクリプトを実行すると、T_Person っていうテーブル変数ができて、どんな感じかな。。


```matlab
>> T_Person

T_Person =

  586×12 table

    NameNo    Age    Weight    Class    A_WinRate    A_DoubleWinRate    L_WinRate    L_DoubleWinRate    Motor    M_DoubleWinRate    Boat    B_DoubleWinRate
    ______    ___    ______    _____    _________    _______________    _________    _______________    _____    _______________    ____    _______________

     2878     61       55        2        5.59            38.46           6.06            42.55          32           28.25          28          35.03     
     2903     60       50        3        4.84               25           4.88               25          68           27.94          42          26.15     
     3020     59       51        3        3.93            20.48           4.57            22.22          32            7.41          38          45.16     
     3036     61       56        3        4.59            20.41           4.11            21.05          10           31.25          32          30.23     
     3051     56       53        3        4.53               25           4.23            19.23          62           42.56          55           32.7     
...
...
```

8/1 に出場してる 586人分のデータが取れてる！よさそう！

名前は解析に使いやすそうな NameNo だけ取って（藤原菜希選手＝4627）、今節成績とか早見とかは解析に不要そう（＝別のデータで出てくる）なので取りませんでした。A1, A2, B1, B2 のクラスも解析しにくそうだったので、A1 → 1、B2 → 4 に変換しました。

# あとは For文 を書けばいいね。

8/1 から 8/3 だったらこんな感じ。

```matlab
for ix = datenum('20190801','YYYYmmDD'):datenum('20190803','YYYYmmDD')   % ここを修正
    fname = ['B',datestr(ix,'YYmmDD'),'.TXT'];
    
    fid = fopen(fname);
    S = textscan(fid,'%s','delimiter','\n');
    B = S{1};
    fclose(fid);
    B = B(~cellfun(@isempty,(regexp(B,'^\d \d+'))));
    Personal = cellfun(@scanB,B,'Unif',0);
    Personal = unique(cell2mat(Personal),'rows');
    T_Person = array2table(Personal,'VariableNames',{'NameNo','Age','Weight','Class','A_WinRate','A_DoubleWinRate','L_WinRate','L_DoubleWinRate','Motor','M_DoubleWinRate','Boat','B_DoubleWinRate'});
end                                                                       % ここもセットで追記

function sc = scanB(txt)

NAME = str2double(txt(3:6));
MOTOR = str2double(txt(41:43));
BOAT = str2double(txt(50:52));
AGE = str2double(txt(11:12));
WEIGHT = str2double(txt(15:16));
if strcmp(txt(17:18),'A1')
    CLASS = 1;
elseif strcmp(txt(17:18),'A2')
    CLASS = 2;
elseif strcmp(txt(17:18),'B1')
    CLASS = 3;
else
    CLASS = 4;
end
A_WINRATE = str2double(txt(19:23));
A_DOUBLEWINRATE = str2double(txt(24:29));
L_WINRATE = str2double(txt(30:34));
L_DOUBLEWINRATE = str2double(txt(35:40));
M_DOUBLEWINRATE = str2double(txt(44:49));
B_DOUBLEWINRATE = str2double(txt(53:58));
sc = [NAME,AGE,WEIGHT,CLASS,...
    A_WINRATE,A_DOUBLEWINRATE,...
    L_WINRATE,L_DOUBLEWINRATE,MOTOR,M_DOUBLEWINRATE,...
    BOAT,B_DOUBLEWINRATE];
end
```

3日分のファイルから、622人のデータが取れました！


# 出走表を取り込んで、選手ごとにデータを分別できました。
結果のデータも取り込んだりテーブルの操作もしなきゃダメですけど、長くなったのでとりあえずここまで。
続きが早く知りたい人は「いいね」で教えてね。（いいね至上主義）

→　[３番目の記事](https://qiita.com/teruqii/items/14bdffe71ef9ff061e55) 
→　[４番目の記事](https://qiita.com/teruqii/items/986d4fba96544960f367) を書いたよ。