MATLABでボートレースの解析をする10個目くらいの記事です。
8回目と9回目の続きです!あまり予想するにあたって参考にならないと評判の「ピットレポート」を解析してみます。
COTOHAが面白そうだったので、COTOHA でやってみましょう。COTOHA は、自然言語処理の使いやすい API を提供してくれるサービスです!
https://api.ce-cotoha.com/
ピットレポートって何なのさ。
大きいレースがあるときだけ公式サイトに載ってる情報なんですけど、走る前のインタビューです。例えばこういうやつ。
https://www.boatrace.jp/owpc/pc/race/pitreport?rno=12&jcd=22&hd=20191114
このレースだと、結果は 124653 の順なんですけど、この言葉から情報は取れるかな。
さっそくピットレポートの読み込みからはじめよう!
と張り切ると、大体詰まる。。
ダウンロードできるデータがないので、力技で取ろう。
ここを探してもないよね。。。
https://www.boatrace.jp/owpc/pc/extra/data/download.html
とりあえずウェブページにはあるので、レースがある日の URL を総当りで取ってみましょう。
前回のプログラムの続きで、2019年のデータでやってみます!
MATLAB と Text Analytics Toolbox があればいいね。
%% 前回までの結果を読む。
load TR_all
load fanbook
%% ピットレポートを取ってくる。
PlaceList = {'桐生','戸田','江戸川','平和島','多摩川',...
'浜名湖','蒲郡','常滑','津',...
'三国','琵琶湖','住之江','尼崎',...
'鳴門','丸亀','児島','宮島','徳山','下関',...
'若松','芦屋','福岡','唐津','大村'};
Place = categorical(PlaceList,PlaceList);
TR_comment = table;
f = uifigure;
d = uiprogressdlg(f,'Title','読込中','Message','ちょっと待ちなさいね。');
for ix = 1:height(TR_2019)
% URLはこんな感じで、レース番号 rno, 開催場所 jcd, 日付 hd を入れれるようにプログラムを書こう。
% https://www.boatrace.jp/owpc/pc/race/pitreport?rno=01&jcd=07&hd=20200214
jcd = num2str(find(ismember(PlaceList,TR_2019.Place{ix})),'%02d');
rno = num2str(TR_2019.R(ix),'%02d');
hd = TR_2019.YYYYMMDD{ix};
url = ['https://www.boatrace.jp/owpc/pc/race/pitreport?rno=',rno,'&jcd=',jcd,'&hd=',hd];
code = webread(url);
if contains(code,'is-alignL')
T = htmlTree(code);
td = findElement(T,'td[class="is-alignL is-p0-10"]');
comment = extractHTMLText(td);
comment = comment(TR_2019.frame(ix,:)); % 着順で並び替え
TR_comment = [TR_comment;[TR_2019(ix,:),table(comment','VariableNames',{'Comment'})]];
end
d.Value = ix/height(TR_2019);
end
save TR_comment TR_comment
超時間がかかるので、実行したら一旦帰る。
2019年の54493レースの総当りなので、適当に書いたウェイトバーが全然進まない。。
しばらくしたら TR_comment.mat ができてるはず。
できてたら読み込んで、続きをやりましょう。
load TR_comment % 2054レース x 6人分 = 12324個のデータがありました。
試しに適当なレースのコメントを見てみる。
>> TR_comment.Comment(end,:)'
ans =
6×1 の string 配列
"今日が一番いい感じでした。全体にいいですね。だいぶ上積みが出来てきました。スタートは早いと思ったら早いし勘はズレていないです。3コースは好きですね。(コメント自信度・・★★☆)"
"昨日は調整をして出足も伸びも、だいぶ良くなっていますね。でも、昨日とは感触が違うので一から調整をします。スタートは決まっているけど、自分の勘とはズレているので修正をしたい。いいスタートを決めたいです。(コメント自信度・・★★★)"
"しっかりした足はありますね。起こしでちょっと気になるところがあるので修正をしたいです。出たとこ勝負になりそうだけど、スタートはしっかりコンマ10の全速を行きたいですね。(コメント自信度・・★★☆)"
"足はいい方だと思います。合えば伸びも回り足も、ちょっとずついいですね。試したいペラの調整をしています。波を越えられる足になっているし、どこか開いたところを捲り差したいですね。(コメント自信度・・★★☆)"
"乗れるとは思っていませんでした。エンジンは普通くらいになったけど、ペラは叩き変えます。展開を突ける足にしたいですね。6コースは嫌いじゃないです。昨日はいいスタートを行けたので今日も行けるようにしたい。(コメント自信度・・★★☆)"
"バランスが取れて全体にいい足をしていますね。満足をしています。気象条件にしっかり合わせたい。昨日はスタートで遅れてしまったし、3日間の反省をふまえて、しっかりレースをしたいです。(コメント自信度・・★★☆)"
大丈夫そう!
COTOHA API を使ってみよう!
と思ったんですが、データが多い!
COTOHAの無料版は1日に1000件までなのに、どうやら12324個もデータがあるので間引きましょう。
データを間引こう。
場所で分ければいいか。。
どの会場に何個くらいデータがあるかな。
histogram(categorical(TR_comment.Place))
ピッタリ 100レース x 6人 = 600データで区切りがいいから福岡にしよう。
TR_Fukuoka = TR_comment(TR_comment.Place == "福岡",:);
MATLAB x COTOHA の設定をしよう。
登録は aoimidori さんの設定を見て、
https://qiita.com/aoimidori/items/644ac0e726d60a99cc4a
プログラムは eigs さんの記事を丸パクリすればいいね。
https://qiita.com/eigs/items/39196afdb5f28bf3ba0f
%% COTOHA設定
clientid = 'input_your_Client_ID';
clientsecret = 'input_your_Client_secret';
url = 'https://api.ce-cotoha.com/v1/oauth/accesstokens';
options = weboptions('RequestMethod','post', 'MediaType','application/json');
Body = struct('grantType', 'client_credentials', ...
'clientId', clientid, ...
'clientSecret', clientsecret);
tokens = webwrite(url, Body, options);
超ラク。
センチメント解析をしよう。
MATLAB の Text Analytics Toolbox にも、vaderSentimentScores とか、いくつか関数があるんですけど、今のところ日本語に対応してなさそうなので COTOHA でやりましょう。
こんな感じでAPIを600回 ( =レース数 x 6人) コールします。
%% センチメント解析
clear response
for n = 1:height(TR_Fukuoka)
for ix = 1:6
baseurl = 'https://api.ce-cotoha.com/api/dev/';
Header = {'Content-Type', 'application/json;charset=UTF-8';
'Authorization', ['Bearer ' tokens.access_token]};
Body = struct('sentence', TR_comment.Comment(n,ix), ...
'sent_len', '1');
options = weboptions('RequestMethod','post', ...
'MediaType','application/json','HeaderFields', Header);
response(n,ix) = webwrite([baseurl 'nlp/v1/sentiment'], Body, options);
end
end
各順位の人はどのような感情か。
COTOHA から Positive/Negative とか感情分析の結果が出るので、着順ごとに集計してみよう。
%% 順位ごとの感情
T1 = struct2table(response(:,1));
T2 = struct2table(response(:,2));
T3 = struct2table(response(:,3));
T4 = struct2table(response(:,4));
T5 = struct2table(response(:,5));
T6 = struct2table(response(:,6));
figure(1)
subplot(2,3,1),histogram(categorical({T1.result.sentiment})),title('1着')
subplot(2,3,2),histogram(categorical({T2.result.sentiment})),title('2着')
subplot(2,3,3),histogram(categorical({T3.result.sentiment})),title('3着')
subplot(2,3,4),histogram(categorical({T4.result.sentiment})),title('4着')
subplot(2,3,5),histogram(categorical({T5.result.sentiment})),title('5着')
subplot(2,3,6),histogram(categorical({T6.result.sentiment})),title('6着')
↓↓結果。
みんな大体ポジティブ!(=ポジティブでも負ける)
1着と6着との傾向がほぼ同じだから、感情ではあんまり分からんね。
スコアで傾向が見えるかな。
どのくらいポジティブかっていうスコアがあるので、その平均を並べてみよう。
ポジティブだけ集めてスコアを平均します。
score = [...
mean([T1(ismember({T1.result.sentiment},'Positive'),:).result.score]),...
mean([T2(ismember({T2.result.sentiment},'Positive'),:).result.score]),...
mean([T3(ismember({T3.result.sentiment},'Positive'),:).result.score]),...
mean([T4(ismember({T4.result.sentiment},'Positive'),:).result.score]),...
mean([T5(ismember({T5.result.sentiment},'Positive'),:).result.score]),...
mean([T6(ismember({T6.result.sentiment},'Positive'),:).result.score])];
bar(score)
差はあるけど、1着と6着が同じなんだよな・・・
(なぜポジティブが6着なんだ。)
分散はあんまり差が出ませんでした。
1着しか言わない言葉はあるだろうか。
COTOHAの結果の中に、emotional_phrase っていうのがあったので、1着しか言わない言葉を集めよう。
せっかくなので、関数にして6回コールして、setdiff で差分を取りましょう。
emo1 = emo_phr(T1);
emo2 = emo_phr(T2);
emo3 = emo_phr(T3);
emo4 = emo_phr(T4);
emo5 = emo_phr(T5);
emo6 = emo_phr(T6);
ph1 = setdiff(emo1,[emo2,emo3,emo4,emo5,emo6])'; % 1位しか言ってないこと。
function emo = emo_phr(T) % エモい言葉あつめ
emo = [];
for n = 1:height(T)
for m = 1:length(T.result(n).emotional_phrase)
emo{end+1} = T.result(n).emotional_phrase(m).form;
end
end
end
↓↓1着しか言わない言葉の結果。
>> ph1
ph1 =
91×1 の cell 配列
{'あまり乗り心地はいい' }
{'あまり良くなかったですね' }
{'いいとか悪い' }
{'いい感じです' }
{'このままいけそうです' }
{'こぼれた' }
{'しんどい' }
{'そんなにいい' }
{'ちょっと足りない' }
{'どうか分からない' }
{'どうもうまく合わせられない'}
{'どこかいい' }
{'なさそうですよ' }
{'はっきり分かっていない' }
{'まだいい' }
{'まだいい感じはないですね' }
{'まだ重たい' }
{'もう変わらない' }
{'もう少し良くしたい' }
{'もったいなかったです' }
{'よくなっている' }
{'よくなってきていて' }
{'よくなる' }
{'ギリギリ' }
{'バランスがとれていい' }
{'バランスがとれています' }
{'バランスがとれているね' }
{'不安定ですね' }
{'中堅よりちょっといい' }
{'乗りづらいです' }
{'乗りづらかったです' }
{'乗りやすかったです' }
{'乗りやすくしてしまうと' }
{'乗りやすくなった' }
{'乗りやすくなっています' }
{'何とかいい' }
{'信用し切れていないです' }
{'信頼して' }
{'入念な' }
{'全然ダメでした' }
{'全然足らなくて' }
{'冷えたので' }
{'冷静さ' }
{'劣勢で' }
{'劣勢でした' }
{'可能性もある' }
{'問題はないですよ' }
{'回りづらかったですね' }
{'変わらないです' }
{'失敗した' }
{'失敗しています' }
{'失敗してしまって' }
{'失敗しない' }
{'失敗です' }
{'好感触だった' }
{'嫌いじゃなかった' }
{'少しいい' }
{'差がありそうだし' }
{'差がありましたね' }
{'引き続きバランス良く' }
{'弱いな' }
{'弱いね' }
{'影響はありますね' }
{'必要ですね' }
{'怪しさ' }
{'悔しいですね' }
{'悪くないですね' }
{'悪くはないかな' }
{'悪くはないですよ' }
{'慌てて' }
{'懸命な' }
{'文句ない' }
{'普通でしょう' }
{'普通なので' }
{'根本的' }
{'波があると分からないです' }
{'渾身' }
{'痛いですね' }
{'笑顔' }
{'自信があった' }
{'良くして' }
{'良くなかったな' }
{'良くなってくれていればいい'}
{'謙遜した' }
{'負けてなかった' }
{'軽くて' }
{'達成' }
{'違和感がありました' }
{'重視して' }
{'重視ですね' }
{'間違えてしまったよ' }
反対の言葉があったりするけど、「自信があった」「文句ない」「バランスがとれて」とかがあればいいのかな。逆に6着はどうだろう。
>> ph6 = setdiff(emo6,[emo1,emo2,emo3,emo4,emo5])'
ph6 =
74×1 の cell 配列
{'あまりいい' }
{'あまり良くなってる' }
{'いいかも' }
{'いまひとつ' }
{'このまま行ってみて' }
{'ごまかせる' }
{'そんなに変わらない' }
{'ただ乗りやすい' }
{'どこか気になる' }
{'はっきりとは分からない' }
{'まだ分からない' }
{'もう少し欲しい' }
{'もう少し欲しいですね' }
{'よく分からなかったです' }
{'よさそう' }
{'スムーズさ' }
{'ズレていました' }
{'トップクラス' }
{'パワーがある' }
{'丁寧な' }
{'中堅くらいですね' }
{'乗りやすさ重視' }
{'人並' }
{'全く分からなかった' }
{'全然ダメだね' }
{'分からなくなりました' }
{'力強い' }
{'劣勢だった' }
{'効果はない' }
{'同じくらいであれば' }
{'失敗して' }
{'安心しました' }
{'少しだけ気になる' }
{'平行線' }
{'弱すぎて' }
{'弱すぎる' }
{'強めだった' }
{'強気' }
{'影響もありましたね' }
{'微妙に' }
{'必要なので' }
{'思惑通り' }
{'悪くはないです' }
{'持っていけた' }
{'普通くらいかな' }
{'普通よりちょっといい' }
{'楽しみはありますよ' }
{'残れた' }
{'波があったら乗れないです'}
{'波があると乗りづらい' }
{'深くなっても大丈夫です' }
{'滑る' }
{'無理' }
{'物足りないですね' }
{'特殊で乗りづらかったです'}
{'相当高い' }
{'素直なので' }
{'良かったかな' }
{'良くなった' }
{'良くなっていない' }
{'良くなっている' }
{'良くなってます' }
{'良くなれば' }
{'著しくない' }
{'行き過ぎてしまいました' }
{'見劣りする' }
{'見劣りすると' }
{'負けない' }
{'追いつかれた' }
{'速いですね' }
{'違和感がなければ' }
{'違和感もない' }
{'遠かったです' }
{'限界' }
「ズレていました」「劣勢だった」「滑る」「無理」「著しくない」「限界」とか言ってる人がいたら6着候補だな。こっちは分かりやすい。
ついでに、4,5,6着しか言わないこと。
>> ph456 = setdiff([emo4,emo5,emo6],[emo1,emo2,emo3])'
ph456 =
257×1 の cell 配列
{'あおられてしまった' }
{'あまりいい' }
{'あまりいい感じ' }
{'あまり分かっていない' }
{'あまり深くなる' }
{'あまり良くない' }
{'あまり良くなってる' }
{'あまり速い' }
{'あんまりいい' }
{'いいかも' }
{'いいのかな' }
{'いまひとつ' }
{'うまくいかなかった' }
{'このまま行く' }
{'このまま行ってみて' }
{'ごまかせる' }
{'さっぱり' }
{'すぐにズレてしまう' }
{'ずっとおかしかった' }
{'ずっと変わらない' }
{'そんなに変わらない' }
{'そんなに嫌いな' }
{'ただ乗りやすい' }
{'だいぶ良くなっていると' }
{'ちょっといいかな' }
{'ちょっと分かっていない' }
{'どうしていい' }
{'どこか気になる' }
{'なにかおかしい' }
{'なんとか残せた' }
{'はっきりとは分からない' }
{'ひどい' }
{'まだマシ' }
{'まだ分からない' }
{'まだ微妙ですね' }
{'まだ持て余している' }
{'まだ普通なので' }
{'もう少し欲しい' }
{'もう少し欲しいですね' }
{'もう少し良く' }
{'もう少し良くなる' }
{'もっと乗りやすくして行きたい'}
{'ものすごく' }
{'よかったです' }
{'よくて' }
{'よくなれば' }
{'よく分からないです' }
{'よく分からなかったです' }
{'よさそう' }
{'イマイチでしたね' }
{'キツイです' }
{'グッとくる' }
{'スムーズさ' }
{'スローで' }
{'ズレていました' }
{'トップクラス' }
{'バランスがとれて普通ですかね'}
{'バランスはとれている' }
{'バランスもとれて' }
{'バランス良く' }
{'パワーがある' }
{'パワーはあります' }
{'パワーアップ' }
{'ヤバい' }
{'ラッキーだった' }
{'ワースト機' }
{'一番良い' }
{'丁寧な' }
{'上位級' }
{'上向き' }
{'上手く' }
{'下手でしたね' }
{'不可もない' }
{'不安はない' }
{'不完全燃焼' }
{'中堅くらい' }
{'中堅くらいですね' }
{'乗りづらい' }
{'乗りづらいですね' }
{'乗りやすいのかな' }
{'乗りやすくて' }
{'乗りやすくなっていますね' }
{'乗りやすさ重視' }
{'乗り心地がいいですね' }
{'人並' }
{'何とかしのげる' }
{'余計' }
{'偏っている' }
{'全く分からなかった' }
{'全然ダメだね' }
{'冷えたし' }
{'分かった' }
{'分からないですね' }
{'分からないね' }
{'分からなくなりました' }
{'力強い' }
{'劣る' }
{'劣勢' }
{'劣勢かもしれない' }
{'劣勢だった' }
{'劣勢です' }
{'劣勢な' }
{'効果はない' }
{'十分いい' }
{'可もなく不可もなく' }
{'同じ' }
{'同じくらいであれば' }
{'向上している' }
{'問題はなかったですね' }
{'変化はある' }
{'多い' }
{'大丈夫そうだった' }
{'大丈夫だ' }
{'失敗して' }
{'失敗してしまいました' }
{'好きなので' }
{'好成績' }
{'威張れない' }
{'威張れるほどでもない' }
{'威張れるほどよくないです' }
{'嫌いじゃない' }
{'嫌いです' }
{'嬉しかったです' }
{'安定' }
{'安心しました' }
{'少しだけ気になる' }
{'少しでも良くなる' }
{'少しズレていた' }
{'少しマシ' }
{'差がありますね' }
{'平行線' }
{'引きずっていた' }
{'弱いかな' }
{'弱いです' }
{'弱すぎて' }
{'弱すぎる' }
{'強い' }
{'強かったですね' }
{'強めだった' }
{'強気' }
{'強烈' }
{'影響があって' }
{'影響もあって' }
{'影響もあり' }
{'影響もありましたね' }
{'徐々に良くなってきています' }
{'微妙に' }
{'必要か' }
{'必要がありますね' }
{'必要だ' }
{'必要なので' }
{'思い切り' }
{'思惑通り' }
{'怪しかった' }
{'悪いのかな' }
{'悪かったり' }
{'悪かったりする' }
{'悪くなさそうですよ' }
{'悪くはない' }
{'悪くはないです' }
{'悪くもない' }
{'情けない' }
{'慌しく' }
{'手ごたえがあった' }
{'持ちこたえる' }
{'持っていけた' }
{'持っていける' }
{'持て余している' }
{'早かった' }
{'映えないですね' }
{'普通くらいかな' }
{'普通だね' }
{'普通で' }
{'普通よりちょっといい' }
{'最低限' }
{'望んでいない' }
{'本当に寒くて' }
{'楽しみたいです' }
{'楽しみはあります' }
{'楽しみはありますよ' }
{'欲しいですね' }
{'残れた' }
{'気づかなかった' }
{'気になっていた' }
{'気になりました' }
{'気になります' }
{'気になりますね' }
{'波があったら乗れないです' }
{'波があると乗りづらい' }
{'深くなっても大丈夫です' }
{'滑っている' }
{'滑る' }
{'無念' }
{'無理' }
{'物足りないですね' }
{'特に悪い' }
{'特殊で乗りづらかったです' }
{'特殊な' }
{'特筆出来る' }
{'狙えていた' }
{'猛烈な' }
{'甘いですね' }
{'甘くて' }
{'甘くて不安ですね' }
{'目立つ' }
{'相当高い' }
{'納得できる' }
{'素晴らしかったですね' }
{'素直で' }
{'素直なので' }
{'細かい' }
{'結構いいですよ' }
{'緊張' }
{'自信がある' }
{'良い状態であれば' }
{'良かったかな' }
{'良かったね' }
{'良かったり' }
{'良くしていきたい' }
{'良くしていきたいです' }
{'良くないですね' }
{'良くなった' }
{'良くなっていない' }
{'良くなっていますよ' }
{'良くなっている' }
{'良くなってます' }
{'良くなりそう' }
{'良くなりました' }
{'良くなれば' }
{'良さそうでした' }
{'良さそうな' }
{'著しくない' }
{'行き過ぎてしまいました' }
{'見劣りする' }
{'見劣りすると' }
{'負けない' }
{'足りない' }
{'足りなかったです' }
{'迷' }
{'追いつかれた' }
{'追い付く' }
{'速いですね' }
{'違和感があります' }
{'違和感がある' }
{'違和感がない' }
{'違和感がなければ' }
{'違和感もある' }
{'違和感もない' }
{'遠かったです' }
{'重たいですね' }
{'重たかったね' }
{'重たくなった' }
{'限界' }
{'難しくて' }
{'頑張って' }
{'骨っぽい' }
{'高い' }
「劣勢」はたくさん出てくる。「見劣り」「滑る」「無念」「全然ダメ」「情けない」とかあれば4着以下だな。
「骨っぽい」ってなんだ。。
今日のアクセス数の上限になったのでここまで。
ということで、「何だこの滑るボートは!全然ダメじゃないか!情けない!骨っぽい!限界だ!無理!」くらい言ってたら舟券から外してもいいと思います。(そんな人いない。)
あとはもう少しデータを増やしたり、同じ人の良い時との類似度算出をしてもいいかもしれないですね。いずれにせよ 1日1000アクセスまでなので、また明日にしましょう。