2014年9月4日木曜日

タイム差の連鎖で比較する方法の検証(5)

タイム差の連鎖で比較する方法の検証(4)で書いたように、今のところ、18番人気を予想するときがある。さすがにおかしいだろう、と調べてみる。2013年までの間で18番人気を予想してしまうのは、6レース。その最も最近のレースは、2012年4回阪神9日11レース。勝ったのは、17番オリービン(4番人気)で、予想した結果は10番アンノルーチェ(18番人気)である。見てみたところ、おかしな数値が出ているところはない。以下がタイム差を計算したもの。数が大きいほど、相手の馬に対して速いことを示す。なお、時間差を走破タイムで割るという調整をしているので、時間差そのままではない。そして、アンノルーチェのオリービンに対するタイム差は、-0.022085369だが、逆は、0.02186513と微妙に違う値になる。これは、その調整による差である。この値から直接のタイム差としては、オリービンのほうが速いということになる。平均値にはほとんど差がない。計算不能だった3頭を除くと、アンノルーチェより速いのは、1番クラレントと17番オリービンしかない。なぜに、これで18番人気なのか。うーん、何が問題なのか、もっと詳細を調べる必要があるな。


10 アンノルーチェ17 オリービン
1 クラレント-0.0220853690.0041351984
2 エックスダンス
3 フレールジャック-0.0015884668
4 モンストール0.0012626622-6.1875914E-4
5 ゼロス0.009481094
6 ブレイブファイト0.021263170.006194453
7 ゴールスキー0.0113776970.00542193
8 オートドラゴン0.0199577230.013366331
9 マイネルクラリティ0.018794650.012109033
10 アンノルーチェ0.02186513
11 タガノエルシコ0.0123999220.0058213435
12 ダイシンプラン0.0256952120.00988129
13 ダローネガ0.013413218-0.0023949028
14 ミキノバンジョー0.0176212840.0063157864
15 タムロスカイ0.0191193350.013514917
16 ガンダーラ0.021165427
17 オリービン-0.022085369
18 レッドデイヴィス0.0127679750.0038332231
平均0.0071950.007139

2014年9月2日火曜日

タイム差の連鎖で比較する方法の検証(4)

タイム差の連鎖で比較する方法の検証(3)で書いたバグをとった結果は、以下のようになった。今回も予想の範囲は、2001年から2013年の範囲で、80%以上データがあるレースに限っている。
的中率 23.2% 回収率 86.0%
バグってた時より、的中率も回収率もあがっている。以前にも書いたように一番人気は、以下。
的中率  32.3% 回収率 76.1%
さて、予想結果は、何番人気の馬を予想しただろうか。結果は以下。
1番人気 14545レース
2番人気 7838レース
3番人気 4752レース
4番人気 3166レース
5番人気 2231レース
6番人気 1607レース
7番人気 1047レース
8番人気 796レース
9番人気 597レース
10番人気 357レース
11番人気 252レース
12番人気 179レース
13番人気 130レース
14番人気 92レース
15番人気 66レース
16番人気 43レース
17番人気 14レース
18番人気 6レース
うーん、減ったものの、18番人気を予想するのはおかしいよなー。また、調べてみよう。

2014年9月1日月曜日

タイム差の連鎖で比較する方法の検証(3)

18番人気を勝つと予想してしまったデータがあると、タイム差の連鎖で比較する方法の検証(2)で書いた。どういうレースでそのような予想をしてしまうのか。まず、データ中で最も最近のデータを調べてみることにした。そのレースは、2013年5回京都7日目8レース。このレースで18番人気である6番マナウスを予想している。実際の結果は、17着であり、ほぼ人気どおり。詳細を調べてみると、おかしいタイム差になっているレースがあった。

6番マナウスと12番やマニンプードレとの時間差の計算のために、
まず、2013年4回京都8日目6レースで7番マナウスと8番アウトシャイン間のタイム差を計算している。このレースでは、
14着7番マナウス1.13.3
15着8番アウトシャイン1.13.3
で時間差なしである。次に、2013年2回小倉9日目12レースで2番アウトシャインと11番ノーザンソングのタイム差を比較している。
2着2番アウトシャイン1.08.4
13着11番ノーザンソング1.09.5
で時間差は-1.1である。次に、2013年4回阪神5日目7レースで6番ノーザンソングと3番ヤマニンプードレのタイム差を比較している。
あっ、ヤマニンプードレは出走取り消しになってる。

これはイレギュラーなので無視しないと駄目だ。バグであり、修正しないと行けない。

2014年8月31日日曜日

タイム差の連鎖で比較する方法の検証(2)

タイム差の連鎖で比較する方法の検証で書いたつづき。
予想がどれぐらいいいのかは、的中率と回収率で評価するしかない。しかし、オッズというのが非常によく出来ているというか、「みんなの意見」は案外正しい (角川文庫) というか、的中率が上がると回収率が下がり、的中率が下がると回収率が上がるみたいな結果になりがちだ。で、両方あげようとすると、フィルタリングをかけるのか、何らかの手段を講じないといけないだろう。

とりあえずは、この予想方法で、最も速いと予想された馬が何番人気だったのか、という結果を調べてみた。

1番人気 11856レース
2番人気  6681レース
3番人気  4298レース
4番人気  3082レース
5番人気  2290レース
6番人気  1813レース
7番人気  1384レース
8番人気  1255レース
9番人気  1032レース
10番人気  873レース
11番人気  735レース
12番人気  668レース
13番人気  561レース
14番人気  439レース
15番人気  358レース
16番人気  282レース
17番人気  67レース
18番人気  47レース

もっと、人気馬が選出されていると思っていた。いくらなんでも、この予想方法で18番人気の馬が選出されることがあるのは、少ないとはいえ、理解しがたい。もちろん、18番人気の馬が勝つ確率はある。上記のデータと同じ(2001年から2013年のレースでデータが80%以上そろっていたもの)レースで18番人気の馬は2回勝っているようだ。しかし、予想については、タイム差を使っているのだから、基本的にタイムが速い馬が選出されているはずである。人が予想する場合もタイムを見ているはずで、ある程度上位に来ないとおかしいのではないか。詳細を調べてみたい。

2014年8月30日土曜日

タイム差の連鎖で比較する方法の検証

タイム差の連鎖で比較するの考え方で書いた方法で計算をしてみた。馬の連鎖は3連鎖までとした。単純に言えば、AとBの馬の差を計算するときに、AとB直接対決した場合か、A-C(AとCが出たレースの差)-B(CとBが出たレースの差)のように、間に別の馬を1頭のみ挟んだ場合、同様にして2頭挟んだ場合を計算する。Aの強さは、A-Bのタイム差(複数ある場合は平均)、A-Cのタイム差、...、と計算したタイム差を平均したものとする。データがそろわないものは予想から外さないと行けないので、80%以上出走馬のタイム差が出た場合のみにした。予想は2001年から2013年の13年分。で、結果は、以下。

的中率 19.7% 回収率 83.1%

うーむ、なんと悪いことよ。ところで、同じレースの1番人気の的中率と回収率は、以下。

的中率 32.3% 回収率 76.1%

回収率は1番人気よりましだが、的中率はかなり悪い。だいたい予想アプリを作るとこういう傾向になる。

2014年8月28日木曜日

書評: カイジ「命より重い!」お金の話

経済学の基礎的な内容で、お金にまつわる話が書かれている。ところどころに漫画のカイジの1ページが差し込まれている。カイジの陥っている状況などを題材として、説明していく。

カイジが書かれていることで興味がひかれるような人を対象に書かれているわけで、そんなに難しい話をしてもしかたないからだろう。原則的な内容で、経済学の基礎はわかっている人なら知っているレベルのことのみで書かれている。たとえば、給料の決まり方は、資本論、つまり、必要経費で決まるという説明で書かれている。実際はさまざまな条件が絡むため、そのままというわけではないので、実感がうまくあてはまらず、逆に知らない人はこれだけ読んでも、わからないのではないだろうか。

最低賃金をあげたらどうなるか、という回答も、最低賃金で働いている人ような人が、まず、職を失う、という内容である。単純にはそう考えられるが、状況次第でそうではない。たとえば、少し前の日本のようにデフレーションで苦しんでいる時期であれば、インフレーションにうまくつながり、景気がよくなるなど、いいスパイラルにつながるかもしれない。そのような場合は、職を失うという結果にはならない。

この本はお金に対する考え方の本で、借金をしてしまうような人向けなのであるが、そういう人が読もうとするかどうかはよくわからないところだ。とりあえず、この本を読むと、カイジを読みたくなってくるのは確かだ。

2014年8月24日日曜日

タイム差の連鎖で比較するの考え方

タイム差の連鎖で比較するで、書いたようにタイム差を使った予想アプリを作成する。
考え方は単純だ。たとえば、2014年の宝塚記念を考えてみる。1着 ジャスタウェイはゴールドシップだが、メイショウマンボを除いて、他の馬とは過去に一緒のレースに出たことがある。なので、それから、タイム差が求められる。たとえば、2着 カレンミロティックとのタイム差は、
有馬記念(2013年)
3着 ゴールドシップ 2.33.8
6着 カレンミロティック2.34.3
をもとに、0.5秒差と算出できる。しかし、直接対決をしていない場合であっても、他の馬経由で算出できる。
ヴィクトリアマイル(2014年)
1着 ヴィルシーナ 1.32.3
2着 メイショウマンボ 1.32.4
ジャパンカップ(2013年)
7着 ヴィルシーナ 2.26.3
15着 ゴールドシップ 2.27.5
つまり、ゴールドシップとヴィルシーナのタイム差は-1.2秒差、ヴィルシーナとメイショウマンボのタイム差は0.1秒差、で合わせて、-1.1秒差というのが他の馬経由でのタイム差である。このタイム差は宝塚記念で実際には勝ったゴールドシップのほうが遅いということだが、たまたま大負けしたジャパンカップが算出用のレースになったのだからしかたない。このようにある馬経由で算出できるタイム差はたくさんあるはずで、それらを平均すれば、それなりに正しいタイム差が出せるのはないかというのが、考え方。
いくつも馬を連鎖すれば、誤差が蓄積されているだろうし、その組み合わせを算出するために計算量が大きくなる時間がかかるだろうから、ある程度連鎖の数はしぼるのがいいのだろう。そして、タイム差は距離によって重みが違うだろうから、単純に-1.2+0.1=-1.1ではなく、-1.2/(2.27.5秒) + 0.1/(1.32.3秒)ように走破タイムで重みを変えることにする。

2014年8月20日水曜日

高校野球

高校野球「大量リードで盗塁」、何が悪い 夏の甲子園に「大リーグ不文律」は意味なしにあるが、大量リードでの盗塁を問題する人がいるようだ。これは、高校野球の位置づけの微妙間がもたらす問題と言えるだろう。

メジャーやプロ野球にはそういう不文律があるわけだが、結局のところ、こういう不文律は「観客が見て面白くないから」、に尽きる。野球はピッチャーの不調などで最初のほうで一気に試合が決まってしまうことがある。でも、雨でも降らない限り、9回まで試合はやることになる。バラエティ番組と違い、差が開いたからといって、この回は何と得点は3倍とか、するわけにはいかないわけで、試合終了までやるしかない。プロである限りは、ショーである部分が大きいわけで、ある程度勝っている側を制限したりするのは、演出の範囲であろう。一方で、大差がついていても、勝ってる側のピッチャーが乱調になれば、一気に追いつくこともあり得るのが、野球とも言えるので、勝つことだけを考えれば、おかしいのだが、それこそショーとして面白くなるのでいいのだ。

高校野球は微妙だ。本来は高校の部活動のはずなのに、ショーの側面が大きい。もう大昔の話だが、思い出されるのは、松井秀喜の5打席連続敬遠だ。勝つためには、最善の策と考えてしたことのはずだが、批判も多かった。ショーと考えれば、これはありえない作戦だ。多くの人は松井のホームランを楽しみに見てるんだから。大量の客が入って、全試合テレビ中継があり、ニュースや新聞で取り上げられる。プロと同じ状態。だからこそ、いろんなチーム・選手の内実をドラマ仕立てにして、盛り上げたりする。おにぎり2万個の件が議論になるのも、ショーなのか、部活なのかの微妙さから来るのだろう。ショー化して、どんどん消費していく。連投して故障する投手もショーの中で消費されたと言えるのだろうな。

2014年8月19日火曜日

ラングリッチ(3)

最近、よくレッスンを受けていた先生が辞めたり、予約がいっぱいすぎてとれなかったりで、新しい先生の開拓が必要だ。選ぶにあたっては、写真と自己紹介文、発音練習みたいな動画、自己紹介のビデオがある。あとはお気に入りに登録されている人数。しゃべりを聞いたところで、あんまりわからないし、新しく入った先生はまだなかったりする。自己紹介文については、なぜか日本語でも紹介されている先生もいたりして謎だ。長い・短いで何か違いがあるわけでもない。結局、適当に選ぶしかないとも言える。

そして、多くの人は写真で選んでいるような気がする。理由は単純だ。お気に入りに登録されている人数順に先生一覧を見ることが出来る。それで見て行くと、写真写りのいい先生が上位のように見えるからだ。先生によって、午前だけだったり、土日だけだったり、といろいろなパターンがあるので、やっぱ多くの人が受けられる時間にレッスンをしている先生が上位にくるような気はするが。でも、現在トップのZee先生はAM5時から9時までのようだが、358もの登録がある。どうなってんだ。日に8コマしかレッスンがない。ということは1週間40コマなのに、358名の登録。平均すると2ヶ月に1コマぐらいしか受けられんぞ。受けたことない人もお気に入りにしてんじゃないのかとすら思える。
[修正]Zee先生のクラスは、午前に加えて20:30-25:00までの9コマもさらにあるようだ。長時間労働だな。とすると平均して1ヶ月に1コマぐらいか。それでも、やっぱり、めったにとれないよな。

2014年8月18日月曜日

ラングリッチ(2)

ラングリッチは始めてから何ヶ月か経つと、4日分の予約を取ることが出来るようになる。そのため、明々後日の予約をとることになるのだが、先生によっては全然とれない。いつ予約してるんだ他の人たちは。朝の7時ぐらいに見ても、すでに全部の時間帯埋まっている先生もざらだ。よく話していた先生が、全然とれなくなってしまうのが残念なところだが、これはしかたない。その時間、他の人がすでに予約したというだけで他に先生はいるので、レッスンは受けることが出来る。先生を選ばなければ、全くとれないことはまずない。 また、結構先生が辞める。辞める前に教えてくれる先生もいる。フィリピンでは転職はよくあることのようなので、しかたない。まだ学生でバイトとして先生をしている人もいるので、就職したりもあるようだ。なので、いろいろな先生を試して行くしかない。 何ヶ月か前から、お気に入りの先生を登録できるようになった。そして、お気に入りに登録している人の人数を見ることが出来る。つまり、その先生の人気を見ることが出来る。じゃあ、人気の先生がいい先生なのか、というとこれがよくわからない。大人気の先生も誰かがキャンセルしたのか、とれることもある。で、とって試してみても、何が違うのかよくわからなかったりもする。なので、あまり人気に左右されてもしかたない。でも、先生は人気によって評価されたりするのだろうか、気になるところだな。

2014年8月17日日曜日

ラングリッチ

英会話の勉強に、オンライン英会話のラングリッチをやっている。Skypeで話すわけだが、毎日25分。今は6000円に値上がりしたが、入った時期の問題で1ヶ月あたり4980円。1日1回受けなければ損になってしまうので、基本的に毎日21時から受けるようにしているので、それに合わせて、会社を出て帰ってきている。始めた頃は、英会話をするということに対して、敷居が高く感じていたのだが、さすがに半年以上経つと何も気にならなくなった。 オンラインのテキストがいくつか用意されているので、それを使う。僕はVOAという英語のネイティブでない人向けの英語放送を文字にしたものを基本的に使っている。新しい記事が増えて行くので、毎日やっていても、ちょうどいい感じで進めて行ける。不得意な分野の記事だと会話するのも大変だが、得意な分野だと結構しゃべりやすい。が、逆に、言いたいことがどうしても英語で言い表せず歯がゆく感じたりもする。フリートークも可能だが、そもそも、知らない人との日本語会話がそれほど得意でないのに、25分しゃべるのはきつく感じる。先生がいろいろ質問してくるので、それに答えるだけで、25分ぐらいすぐすぎてしまうので、特に問題はないものの、テキストをやったほうが楽しめる気がする。 どちらにしろ、いきなりテキストに入るのではなく、今日何があった、みたいなトークから入るので、話をする。しかし、ウイークデイに聞かれたところで、毎日仕事に行ったぐらいしか言うことがない。仕事で何かしゃべりやすいイベントがあれば別だがいつも大したことないので、何を話すのが少し悩ましい。それでも、僕は家で仕事の話をしないので、先生に対してのほうが話していることになる。実質20分ぐらいなので、VOAの記事1つが終わらない。VOAの記事は長さがいろいろあるので、長いものだと4回ぐらいかかることもある。先生によっても、レッスンの進め方が変わるので、すぐ進んでしまうこともあれば、全然進まないのもある。いろいろ質問をしてくれる先生のほうが好きなので、進め方が遅い先生を選ぶようにしている。

2014年8月14日木曜日

いつ車を買い替えるか(2)

いつ車を買い替えるかの続き。

今は買い替える目的がない。特に今の車で満足しているからだ。何回か、ぶつけたり、ぶつけられたり、こすったりしたが、修理して問題なく走れている。

そして、ハイブリッド、電気自動車、燃料電池自動車、と技術の切り替わりが来ている。

ハイブリッドは好きではない。2系統あるのが、壊れやすさと価格の高さにつながるように思う。価格の高さについては、戦略と政治によりそれほどでもないが。しかし、嫌いは嫌いだ。2つ抱えている無駄は気に入らない。

電気自動車の時代はいつ来るのか。電気自動車はいい。車通りの多い道路の近くにたつ新築一戸建て、数年経つと結構黒くなる。こういうのが電気自動車になるとなくなるとするとすごいことだ。また、音も静か、ということは、大通りの近くであっても、騒音に悩まされなくなるということだ。そう考えると、土地の値段を変えてしまうかもしれないインパクトを持つ。しかし、走行距離と充電にかかる時間はいかんともしがたい。いつ、解決する技術が出るのか、その予測は難しい。どちらにしろ、研究レベルで技術が出来て、それから実用化するには、安全が重要な車では数年はかかるだろう。そう考えると、まだ、遥か先のような気もする。バッテリの進化にみなが期待するところであり、去年はバテナイスで一時期、一部の人たちが(というか投資家?)盛り上がっていた。しかし、日経エレクトロニクスの記事を見ると、
なぜなら、同電池の場合、電極当たりのエネルギー密度の点で高性能なリチウムイオン二次電池に劣っている上、技術的なブレークスルーがなければエネルギー密度を大幅に向上させることは難しそうだからだ。

とある。長所だけ見ると、期待させられるのだが、きっちり見ると、やはり簡単に置き換えられない問題がある。ブレークスルーはいつ起きるのか。田舎の海岸線を走っていると、気持ち良さそうなオープンカー。渋滞の首都高で見ると、何かの修行ですか、と思う。こういうのも、電気自動車になると、快適になるのだろうな。

2014年8月13日水曜日

書評: これがメンタリズムです

メンタリストDaiGoが書いた本。テレビ等でやっていたことの種明かしの本になるのだろう。

まずは、フォーク曲げの話。単に力で曲げているだけと言うことだ。なので、種も何もあったものではないが、3点押さえてテコの原理で曲げているので、曲げている流れをよく見ると、その瞬間があるらしい。何度も何度も練習して、非常に滑らかに見えるようにしている。こっちのほうは、なるほどね、と思える話ではある。それは最初のさわりであり、本論はメンタリズムの話。

結局のところ、いろいろな仕草で、ある物を印象に残るようにして、選ばせるようにする。さらに、目の動きや筋肉の動き等よく観察して人の考えていることを読む。そして、失敗したら、うまくごまかす。単純に言えば、そういうことのよう。選ばせるためのテクニックも紹介している。3を選ばせようと思ったら、

○○さん(3)ですね。これから参加型のメンタリズムを行います
って言うとか、選んでもらいたい、というときに、パッと3本指を出したり、頭の中で数字を描いてください、というときに、空中で3を書く、とか、で刷り込んでいくという。

うーん、納得しがたい。でも、この本は本当のことを書いているのだろう。テレビでは失敗したこともあることも書いてある。笑っていいとも、では悲惨な状態だったらしい。


2014年8月12日火曜日

いつ車を買い替えるか

7年の車検が終わり、車検証とシールが送られてきた。早速、シールをフロントガラスに貼った。次の車検はまた2年後。そろそろ車は買い替えるべきなのか。車検等のメンテナンスをしてもらっているトヨタカローラの人に聞くと、当然、いつも買い替え時期である。聞くと、そのときが買い替え時期。聞かなくても、あの手この手で買い替え時期。当たり前だ、売るのが仕事なのだから。ポジショントークをそのまま聞いてもしかたない。

前に買い替えたときは、わかりやすい時期だった。それは、子供が生まれたから。それまで乗っていた車ヴィッツには、後部座席のドアをつけていなかった。後ろに乗る人はいないので、無駄だと思い、つけなかった。しかし、チャイルドシートというのは、普通、後部座席に付けるものである。どちらにしろ、人数が増えれば、後部座席を使うしかない。そこで、買い替えた。すでに、8年間乗っていた車だったので、ちょうどいい機会でもあった。

ではどういう車を選ぶか、というのもそれほど悩まなかった。赤ん坊を抱きかかえて乗り込むことを考えると、スライドドア。少し大きくなってきて自分でドアを開けられるようになっても、ドアがバッと開いてしまうことを考えると、スライドドアが安全だろう。後は、荷台の大きさが欲しかった。ヴィッツの荷台では買い物のとき、せまく感じでいた。後部座席を使わない間は、後部座席にも荷物が十分におけたが、それがなくなると考えると、ある程度の広さが必要である。で、3列シートの車をいくつか車を見てみたが、どれもでかい。でかすぎて、狭い道が多い周辺を運転できそうな気がしない。まわりの人はそれでも運転しているんだけれども、自分には無理。そのバランスで、最終的にシエンタにした。

7年経ったということは、あと1年で前の車と同じ期間乗ったことになる。さて。

2014年8月11日月曜日

タイム差の連鎖で比較する

スピード指数は前の記事で書いたように難しい。そこで違う方法を考えてみる。

競馬新聞から競馬を予想するとき、過去のレース結果からその馬の強さを予想する。過去のレースの格や順位、タイムなどいろいろな情報を使う。スピード指数はその中でもタイムに注目して、そのタイムがレースごとの馬場の状態や展開によって差が出ることから、その調整を入れる。でも、その調整という部分が技術の必要な部分であり、予想ソフトなりの特徴になってくる。

しかし、調整というのは結局のところ、馬の強さに合わせることであり、遅いはずの馬のタイムは遅くして、速いはずの馬のタイムは速くするということになる。それにより、そのレースに出る馬の過去のタイムを比較しやすくする。しかし、そもそも過去のタイムを比較しやすくするためであれば、調整したタイムではなく、直接的に比較すればいいのではないか。

たとえば、Aという馬とBという馬があって、前走でも、AとBが直接対決していれば、そのままのタイム差(T(A)-T(B))を使えばいいし、直接対決していなくても、AとC、BとCが対決しているレースがあれば、AとBのタイム差は(T(A)-T(C))+(T(C)-T(B))を使えばいいのではないか。おそらくこのように他の馬を介して計算するタイム差はいくつもあるだろうが、それらを平均すればいい。このタイム差の計算方法は、いくつの馬を介せば、あるレースの全頭の時間差を出せるのかが気になるところではある。しかし、同じクラスの馬は、他の馬を1頭か2頭介せばつながるのではないか。一方で、クラスが上がったばかりの馬については、つながりにくくなる可能性はある。しかし、他にもよく似た時期に同じようにクラスを上がった馬もあるはずで、それほど気にする必要はないかもしれない。それに、クラスの壁と言われるタイムだけではわからない差をこの方法だと見ることができるかもしれない。また、芝もしくはダートが初挑戦のような馬もつながりにくいだろう。これは、そもそも予想が難しい部分でこの方法に限らない問題であり、それほど気にする必要はないだろう。

2014年8月10日日曜日

スピード指数の難しさ

スピード指数を出すには、場所と距離ごとの標準タイムが必要だ。しかし、距離による時間差距離による時間差(2)などで書いてきたが、500万以下、1000万以下クラスで同じ距離のレースが何度も行われているわけではないし、雨が降ると一気に走破タイムが変わる。それに、この記事に書いたようにオープンしかないようなレースもある。スピード指数系の予想ソフトを作る人は、ここをどのように適切にするのか、それがポイントになるだろう。逆に言えば、ここに恣意的な操作を施すことによって、それなりの結果を得られるようにすることもできると考えられる。また、開催日ごとの馬場の差を計算に入れるための馬場指数についても同じようなことが言える。馬場指数は、その日に行われたレースのタムから決めることになるだろうが、結局のところ、馬場の状態だけでなく、ペースなどいろいろな要因から変わってくるため、調整するしかない。ここも恣意的な操作が入る部分である。ここの目利きが、その予想ソフトの強さに影響する。

つまり、標準タイムと馬場指数は過去のレースからの計算のみで算出することはできない。過去のレース結果を参考にして、そこから経験等をもとに調整することが必要だ。だからこそ、この部分が売り物になるのだろう。西田式スピード指数のサイトでは、標準タイムと馬場指数が有料で手に入れられる。もう少し、自動的な計算のみで指数を出せないものか。

2014年8月9日土曜日

データベースを使う(4)

データを取り出すのは簡単だ。SQLのselectを使えばいいだけ。下のような形で、馬名で指定する馬の一定期間内のデータを取得することが出来る。

public List<HorseData> select(String horsename, Date mindate, Date maxdate) {
try {
PreparedStatement ps = conn.prepareStatement("select * from Horse where name = ? and date < ? and date >= ? order by date DESC");
ps.setString(1, horsename);
ps.setDate(2, new java.sql.Date(maxdate.getTime()));
ps.setDate(3, new java.sql.Date(mindate.getTime()));
ResultSet rs = ps.executeQuery();
return readResultSet(rs);
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return null;

}
private List<HorseData> readResultSet(ResultSet rs) {
List<HorseData> list = new ArrayList<HorseData>();
try {
while (rs.next()) {
HorseData hd = new HorseData();
hd.name = rs.getString("name");
hd.term = rs.getInt("term");
hd.place = rs.getInt("place");
hd.day = rs.getInt("day");
hd.rnum = rs.getInt("rnum");
hd.date = new Date(rs.getDate("date").getTime());
hd.frame = rs.getInt("frame");
hd.number = rs.getInt("number");
hd.order = rs.getInt("ordernumber");
hd.time = rs.getInt("time");
hd.popularity = rs.getInt("popularity");
hd.weight = rs.getInt("weight");
hd.loadweight = rs.getFloat("loadweight");
hd.threefurlong = rs.getFloat("threefurlong");
hd.odds = rs.getFloat("odds");
hd.setPassorder(rs.getString("passorder"));
list.add(hd);
}
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return list;
}

2014年8月8日金曜日

書評: ある奴隷少女に起こった出来事

奴隷だった著者による自伝。著者のハリエットは1813年生まれ。リンカーンが奴隷解放宣言をしたのが1862年なので、49歳の頃ということになる。アメリカの南部で奴隷があったことは知識として知っていても、具体的にどういうものなのか知らない人は多いだろう。僕もそうだった。

著者が、奴隷として使えていた家から抜け出し、自由を得るまでの話であるが、それまでの紆余曲折が書かれている。その時々に最善を考えて行動しているのだろうが、論理的にそう思えないところが数々あるため、小説として読んでしまうと少し辛いかもしれない。著者の実質的な所有者であるドクターフリントがストーカー気質で精神的な嫌がらせはしつくすのに、力尽くでということはしないという不思議な性格。また、著者が、祖母の家の屋根裏で7年間過ごすというのはすさまじい。実際にあったことということに驚くしかない。

奴隷の売買や相続による所有者の変更や、母が奴隷の場合は子供も奴隷になるという法律、自由州に逃げたとしても連れ戻される法律、いろいろな形で絡まり合い、読みどころの多い本である。

2014年8月6日水曜日

データベースを使う(3)

データベースを使う(1)で作ったテーブルに、馬のデータを差し込んで行く。普通にSQLのinsertを使えばいいだけ。executeUpdate()を使えば、Primary Keyが同じ場合はエラーでなく、上書きされる。これをYahoo競馬から取得したデータをすべてデータベースに登録し直し。これで、使いやすくなったはず。

public boolean insert(Horse horse, int term, int place, int day, int rnum, Date date) {
try {
final String sql = "insert into Horse values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
final PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, horse.name);
ps.setInt(2, term);
ps.setInt(3, place);
ps.setInt(4, day);
ps.setInt(5, rnum);
ps.setDate(6, new java.sql.Date(date.getTime()));
ps.setInt(7, horse.frame);
ps.setInt(8, horse.number);
ps.setInt(9, horse.order);
ps.setInt(10, horse.time);
ps.setInt(11, horse.popularity);
ps.setInt(12, horse.weight);
ps.setFloat(13, horse.loadweight);
ps.setFloat(14, horse.threefurlong);
ps.setFloat(15, horse.odds);
ps.setString(16, horse.getPassorder());
ps.executeUpdate();
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return true;

}

2014年8月4日月曜日

データベースを使う(2)

テーブルを作るかどうかを判定するには、データを取ってみたらいいようだ。
ResultSet rs = null;
try {
final Statement s = conn.createStatement();
rs = s.executeQuery("select count(1) from Horse");
} catch (SQLException se) {
final String state = se.getSQLState();
if (state.equals("42X05")) {
makeTable(conn);
} else {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
} finally {
if (rs != null) try {rs.close();} catch (Exception e) {};

}

makeTableの先は、データベースを使うで書いたcreate tableを呼び出している。

2014年8月3日日曜日

データベースを使う

すべてオンメモリで動かせば、データベースを使う必要はないだろう。と、思ったが、結構でかい。全部読み込んだらエラーが出る。ヒープ領域を大きくすればいいのかもしれないが、すべてをメモリに読み込むのは止めることにした。それにあたり、Json形式でファイルを保存することにしていたが、読み込み時にデータをしぼることを考えれば、やはりデータベースを使うほうがいいだろう。なお、PCではなく、Google Appを使うことを考えたら、BigTableに置き換えることを想定したほうがいいのだが、普通にSQLを使う。JavaではDerbyを使うのがいいようだ。で、ライブラリに、ダウンロードしたderby.jarを追加した。
String CREATEHORSETABLE
"create table Horse "
"(name varchar(20) NOT NULL, term smallint NOT NULL, "
"place smallint NOT NULL, day smallint NOT NULL, "
"rnum smallint NOT NULL, date date NOT NULL, frame smallint, "
"number smallint, ordernumber smallint, time smallint, "
"popularity smallint, weight smallint, loadweight real, "
"threefurlong real, odds real, passorder char(20), "
"PRIMARY KEY(name, date))";
Connection conn = DriverManager.getConnection("jdbc:derby:/Users/tkydevelop/Documents/workspace/HorseRaceAnalyzer/db;create=true");
Statement s = conn.createStatement();
s.execute(CREATEHORSETABLE);
のようにしてテーブルを作成した。

2014年8月2日土曜日

Jsonで書き込みと読み出し

Yahoo競馬から取得したデータをjson形式でファイルに保存することにした。jsonのライブラリとして、jacksonを使った。Annotations, Streaming API, DataBindのライブラリを追加した。
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
.setVisibility(PropertyAccessor.CREATOR, Visibility.NONE)
.setVisibility(PropertyAccessor.SETTER, Visibility.NONE)
.setVisibility(PropertyAccessor.GETTER, Visibility.NONE)
.setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE);
om.writeValue(file, list);
writeValueを使うとオブジェクトの属性値がそのまま書き出される。加えて、たとえば、getXXXX的な名前の関数の値も書き出されてしまう。そのため、setVisibilityを使って、それらを書き出さないように変更した。
一方で読み込みをしようとしても、うまくオブジェクトに読み込むことができなかった。仕方ないので、
JsonNode rootNode;
rootNode = om.readTree(new File(filename));
for (JsonNode node: rootNode) {
Race race = new Race();
race.date = new Date(node.get("date").longValue());
のような形で、リストを繰り返しながら読み込んだ。

2014年7月31日木曜日

距離による時間差(2)

距離による時間差の記事で、2013年の京都の芝1200mと2400mの上位3頭平均タイムを示したが、クラスが上なのに遅いタイムの部分があった。これは、馬場が不良のときのデータも含んでいたのが理由のように思われるので、良馬場だけのデータにする。

2013年の京都の芝1200mの上位3頭の平均タイムは、以下である。
新馬(1レース) 1:10:1
未勝利(5レース) 1:09:4
500万下(4レース) 1:08:7
1000万下(7レース) 1:08:5
1600万下(2レース) 1:08:7
オープン(4レース) 1:07:8
GIII (2レース) 1:08:0
で、2400mは以下である。
未勝利(1レース) 2:26:2
500万下(4レース) 2:27:4
1000万下(4レース) 2:27:2
1600万下(3レース) 2:25:1
GII(2レース) 2:24:0

未勝利と500万下の差は、0.7秒と-1.2秒、
500万下と1000万下の差は、0.2秒と0.2秒、
1000万下と1600万下の差は、-0.2秒と2.1秒
である。少しはましになったが、やっぱり、きれいな差にはなっていない。スピード指数で比較するのは、難しいのではないか。

2014年7月30日水曜日

距離による時間差

同じ秒差でも、距離によって異なる価値がある。ということで、スピード指数では、以下のように距離指数というのを使って、距離による時間差を吸収している。
この指数は 1秒÷基準タイム×1000 の計算式から求められたものです。
実際のところ、どれぐらい差があるのだろうか。2013年の京都の芝1200mの上位3頭の平均タイムは、以下である。
新馬(2レース) 1:10:2
未勝利(5レース) 1:09:4
500万下(5レース) 1:08:9
1000万下(7レース) 1:08:5
1600万下(4レース) 1:09:1
オープン(5レース) 1:08:3
GIII (2レース) 1:08:0
で、2400mは以下である。
未勝利(1レース) 2:26:2
500万下(4レース) 2:27:4
1000万下(5レース) 2:27:6
1600万下(3レース) 2:25:1
GII(2レース) 2:24:0

未勝利と500万下の差は、0.5秒と-1.2秒、
500万下と1000万下の差は、0.4秒と-0.2秒、
1000万下と1600万下の差は、-0.6秒と2.5秒
である。きれいな差にはなっていない。2400mは未勝利のほうが500万下、1000万下より速いやんか。結局、データ数がそれほどないため、ほとんど誤差と言えるのだろう。

2014年7月29日火曜日

オープンにしかない距離

基準タイムを計算しようとしたとき、500万下、1000万下にない距離はどうすればいいのか。とりあえず、オープン以上しかないレースというのがどれだけあるのだろうか。2013年で見てみると(障害はのぞく)、

京都 芝3000m オープン平場と、GIのみ
京都 芝3200m GIのみ
阪神 芝3000m GIIのみ
中山 芝3600m GIIのみ
東京 芝2500m GIIのみ
東京 芝3400m GIIIのみ

これだけあるようだ。これらの距離は、オープンのタイムをもとに基準タイムを作るしかない。逆に言えば、これらのレースタイムは誤差が大きくなるだろうな。

2014年7月28日月曜日

例外的なデータ(2)

どんな距離のレースがあるんだろうとデータを見ていて気付いた。23600になっているデータがある。何じゃこりゃと思うと、これはダイヤモンドステークス(3600m)から取得したデータのよう。Yahooのページで確認してみると

芝・右・内2周 3600m [コースガイド

うーん、やられた。距離の部分を抜き出すために、このデータを、


Integer.parseInt(course.replaceAll("[^0-9]", ""));

として、数字の部分以外を削除していた。その結果、内2周の2も抜き出されてしまった。さて、どうやって切り出そうかな。[スペース]とmの間で抜き出すか。

String[] distances = course.split(" ");
for (String distance: distances) {
if (distance.endsWith("m")) {
return Integer.parseInt(distance.replaceAll("[^0-9]", ""));
}

}

上記のように、抜き出す部分を限定してみる。

2014年7月27日日曜日

基準タイムに何を使えばいいのか(2)

基準タイムに500万下、1000万下の平均タイムを使うとしても、そのクラスにはない距離というのがある。長距離、たとえば3200mなんてオープンにしかないし。ということは、その基準タイムは、オープンをもとに決めるしかない。したがって、オープンのタイムがこれぐらいだから、500万下もしくは1000万下だとこれぐらいと出すことになるのだろう。ということで、クラスごとにどれぐらいの差があるのかを調査中。たとえば、2013年の阪神競馬場芝1600mの平均(上位3頭)は以下。

新馬(8レース) 1:37:5
未勝利(13レース) 1:35:7
500万下(8レース) 1:34:8
1000万下(7レース) 1:34:5
1600万下(2レース) 1:33:8
オープン(4レース) 1:33:5
GIII(2レース) 1:35:1
GI(2レース) 1:34:5

これを見ると、何となく妥当なタイムが出ているように思うが、GIなどはレース数が少ない分、馬場の状態などで大きな違いが出る気がする。

2014年7月26日土曜日

基準タイムに何を使えばいいのか

500万下と1000万下の距離ごとの平均をとり、基準タイムとすることを書いた。しかし、実際に平均を取ってみると、不思議なデータもある。

2013年函館の芝2000mのデータ
500万下 8レース上位3頭の平均 2:03:8
1000万下 4レース上位3頭の平均 2:05:8

500万下のほうが2秒も速い。本来は、1000万下のほうがクラスが上なのだから速いはずである。しかし、たった4レースの平均だとすると、これぐらい差が出てもしかたないのかもしれない。もう少し調べてみよう。で、上記の対象になっているレースは、以下。
1回函館1日12レース 500万下 (混合)(特指) 定量 馬場:良 タイム: 2.00.6

1回函館3日8レース 500万下 [指定] 定量 馬場:良 タイム: 2.01.1
1回函館5日12レース 1000万下 (混合)(特指) 定量 馬場:良 タイム: 2.03.4
2回函館2日10レース 500万下 (混合)(特指) 定量 馬場:良 タイム: 2.02.1
2回函館3日10レース 500万下 (混合)(特指) 定量 馬場:良 タイム: 2.01.6
2回函館6日10レース 1000万下 (混合)(特指) 定量 馬場:良 タイム: 2.01.7
3回函館1日10レース 500万下 (混合)(特指) 定量 馬場:良 タイム: 2.02.0
3回函館3日10レース 500万下 (混合)(特指) 定量 馬場:良 タイム: 2.01.8
3回函館6日10レース 1000万下 (混合) 定量 馬場:良 タイム: 2.02.5
4回函館2日9レース 500万下 (混合)(特指) 定量 馬場:重 タイム: 2.06.9
4回函館5日12レース 1000万下 (混合)[指定] ハンデ  馬場:不良 タイム: 2.15.2
4回函館6日8レース 500万下 (混合)(特指) 定量 馬場:重 タイム: 2.12.5
これを見ると、500万下は、開催の最初のほうで行われていて、1000万下は後半だ。芝が荒れていたせいかもしれない。また、馬場不良で行われた4回函館5日12レースの非常に遅いタイムが効いているとも言える。

過去のデータはというと、
2012年
500万下 3レース上位3頭の平均 2:02:3
1000万下 2レース上位3頭の平均 2:02:4
2011年
500万下 3レース上位3頭の平均 2:02:4
1000万下 2レース上位3頭の平均 2:01:7

で安定しているように見える。馬場が悪いときのデータは外すべきか。

2014年7月25日金曜日

基準タイム

競馬でどの馬が勝つかはいろんな要因があるものの、速く走ったほうが勝ち、ということから考えると、やはり走破タイムが重要と言える。そして、競馬場によって走りやすさに差があることから、異なる競馬場での走破タイムをそのまま比較することは出来ないだろう。で、競馬場ごとの距離ごとに基準タイムを作って、比較しやすいようにするのが、第一ステップである。西田式スピード指数では、


各競馬場ごとに500万条件と1000万条件で行われたレースの1~3着に入着した馬のタイムの平均を求めてさらに平均したものです。
つまり各競馬場の各距離ごとに500万条件と1000万条件の中間に位置するモデル馬を想定して、これらが出すであろうタイムが基準タイムなのです。

になっている。同条件のレースは多くあることや、実力の拮抗ぐらいから考えて、この値を使うぐらいしかいい手はないかな、やっぱり。各距離と書かれているが、内回りと外回りは分けるべきかもしれない。分けようと思った場合、Yahoo競馬のページでは、
芝・右・外 1600m
のように外の場合のみ記述されているようだ。なので、このコース情報に"外"が含まれているかどうかを判定すればいいのだろう。また、500万、1000万条件を抜き出すには、
1000万下 (混合)[指定] 定量
のように書かれている条件に1000万下と書かれているかどうかで抜き出す。なお、2001年に900万下だったのが1000万下に変更になっている。Yahoo競馬のデータから見ると、変更になったのは、1回函館1日(2001/6/9)が最初のように見えるが、同時開催の東京・中京は900万のままだ。よくわからないな。とりあえず、900万下も1000万下も同じとしてマッチングすれば抜き出せるだろう。また、2歳の500万下と3歳以上の500万下には差がありそうな気がするが、平均だし、まずは気にせず同じものと取り扱うことにする。

この基準タイムは、予想するレースより、過去のレースのデータから求めないといけない。予想ソフトを作るのだから、当たり前だが、予想するレースが実施される前に手に入れられるデータのみを使うように制限する必要がある。ということで、基準タイムは、予想するレースの前年度のデータを使うことにするか。つまり、今(2014年)なら、2013年のデータを使うことになる。しかし、競馬場の改装工事があった場合、前年度データがないことも考えられるので、2年分の平均をとることにする。これで、データがないことを防げるだろう。

2014年7月24日木曜日

データからのタイムの抜き出し方

基準タイムを算出するため、500万下や1000万下の平均タイムを出してみると、1000mのタイムが変な値に。なぜか調べてみると、多くの場合、1分を切るからだ。Yahoo競馬では、タイムは、x.xx.xの形式で書かれる。そのため、"."でsplitして、それぞれを計算していたのだが、xx.xになるケースを考えていなかった。

String[] times = time.split("\\.");
if (times.length == 2) {
return Integer.parseInt(times[0]) * 10 + Integer.parseInt(times[1]);
} else if (times.length == 3) {
return Integer.parseInt(times[0]) * 600 + Integer.parseInt(times[1]) * 10 + Integer.parseInt(times[2]);
} else {
return -1;

}

のように場合分けすることで、おかしなデータはなくなった。

2014年7月23日水曜日

一つのレースだけが中止になることもある

Yahoo競馬からデータの取得を続けていると、なぜか、解析できないレースがあった。それにアクセスしてみると、出馬表にリダイレクトされる。転送先の出馬表を見てみると、「強風のため中止」とある。で、このレースは、「第126回中山大障害(J・GI)」。他のレースはできるが、このレースは障害レースであり、他の平地のレースは強風でもできたということだ。

HttpGet hg = new HttpGet(url);
List<Header> headers = new ArrayList<Header>();
headers.add(new BasicHeader("Accept-Charset","utf-8"));
headers.add(new BasicHeader("User-Agent", "HorseRaceAnalyzer"));
RequestConfig config = RequestConfig.custom().setRedirectsEnabled(false).build();
HttpClient hc = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setDefaultHeaders(headers).build();

HttpResponse hr = hc.execute(hg);
int status = hr.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
return null;
}
return EntityUtils.toString(hr.getEntity(), "UTF-8");

Webページをhttp-getする際に、リダイレクトを止めることにした。そして、このレースのデータはエラーとして取り扱い、データとして取得しないことにする。その部分を含めて、http-getの部分のソースは上記。

2014年7月22日火曜日

例外的なデータ

Webページを解析するで、書いたように、Yahoo競馬のWebページをもとに競馬のデータを取得しようとしていて、前後の文字列を使用した。これで、データを取れるのだが、レースによってエラーが出る。すべてのデータを確認して、仕様を予測したのではないので、例外的なデータの場合があるからだ。まずややこしいのは払戻金の情報。昔は、三連単は2004年から三連複は2002年から始まったので、それより昔は当然ない。馬連は8頭立て以下では存在しないとか、競馬をわかっている人には当たり前のことではあるが、ややこしい。同着も存在する。それらを考慮してデータ構造を作った上で、取り出さなければならない。リスト型を使い、ない場合を含めていくつになることもありうるようにした。

他、競争中止になったときには、着順やタイム、上がり3ハロンなどの情報もなくなる。着順には数字が書かれるかわりに中止書かれている。競争除外になれば、それに加えて、オッズや馬体重、人気、通過順位もなくなることになる。値が空欄になったり、"-"になったりする。エラーが出るごと、これらを受け入れられるように修正した。

降着があるのも注意点。"5(3)"のように書かれている。こう書かれている場合は、もともとは3着だったのが5着に変更されたということのようだ。降着の取り扱いをデータ上どうするか悩んだが、そのレースの他の馬については降着で訂正される前の着順は書かれていない。なので、降着を反映した後のデータを取り扱うのがいいのだろう。なので、上記の例では、(3)の部分は捨てることになる。

 String[] strorders = strorder.split("\\(");
 horse.order = Integer.parseInt(strorders[0].replaceAll("[^0-9]", ""));

上記のようにして、括弧の前の部分だけを取り出し。"("でsplitするときは、"\\"を前につける必要がある。このことを最初知らずに少しだけはまった。

2014年7月21日月曜日

Webページを解析する(2)

Webページからデータを取得するということは、表示上の値を取り扱わないと行けないということである。払戻金は、たとえば、1,020円のように、3桁ごとに","が打たれている。これらは取り除かないと行けない。

 Integer.parseInt(money.replaceAll("[^0-9]", ""));

上記のようにString#replaceAllを使うことで、数字だけにした上で、intに変換できる。

また、タイムは1.09.6のような形で記述されている。最小の単位が0.1秒であるため、これをベースとした整数値として取り扱うことにし、以下のように変換した。

 String[] times = time.split("\\.");
 horse.time = Integer.parseInt(times[0]) * 600 + Integer.parseInt(times[1]) * 10 + Integer.parseInt(times[2]);

"."でsplitするときは、"\\"でエスケープする必要がある。ところで、Macでは、¥と\は区別される。"\"は[option]+[¥]で入力できる。

2014年7月20日日曜日

Webページを解析する

Yahoo競馬からデータを取得すると決めた。APIが用意されているわけではないので、HTMLを解析し、必要な部分を抜き出さなくてはならない。

public HtmlAnalyzer(String html) {
buf = new StringBuffer(html); 

}
public String getData(String begin, String end) {
int ibegin = buf.indexOf(begin);
if (ibegin == -1) return null;
ibegin += begin.length();
buf.delete(0, ibegin);
int iend = buf.indexOf(end);
if (iend == -1) return null;
String ret = buf.substring(0, iend);
buf.delete(0, iend + 1);
return ret;

}

上記のように、HTMLをStringBufferに入れて、解析した部分から消していくことにした。解析として、ある文字列とある文字列の間の文字列を取り出す関数を作った。そして、HTMLのソースファイルを見ながら、必要な部分の前後の文字列を切り出し、上記関数getDataの引数として与えるようにした。
<p id="raceTitDay" class="fntSS">2000年1月5日(水) <span>|</span> 1回中山1日 <span>|</span> 10:00発走</p> 
HTMLのソースファイルで、日付と開催日と場所の情報は上記のように書かれている。そこで、以下のようにgetDataを呼び出してデータを取得するようにした。

HtmlAnalyzer ha = new HtmlAnalyzer(html);
Race race = new Race();
race.horses = new ArrayList<Horse>();
String date = ha.getData("<p id=\"raceTitDay\" class=\"fntSS\">", "<span>");
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
race.date = format.parse(date);
race.termplaceday = ha.getData("</span>", "<span>").trim();

多くのデータがあるため、かなり面倒だが、基本的には同じように書いて行けばよい。難しいのは、どこまで可変でどこまで固定なのかということだ。HTML自体は、データを埋め込んで自動生成しているのだろうから、基本的には同じ枠組みで作られているはずだ。しかし、どこが埋め込み部分なのか判断が難しい場合もあるので、試行錯誤が必要だろう。

2014年7月19日土曜日

どのプログラミング言語で作るか

久しぶりに、競馬予想ソフトを作ると決めたものの、どのプログラミングで作るのがいいのか。それを決めるための最も大きな要件は、どのデバイスで使うのか、ということになるだろう。後は、自分の得意・不得意もあるし、開発工数が少なくてすむというのもある。昔作ったときは、確か、C#で作ったのだが、そのときはWindowsで動かすことしか考えていなかったし、サーバー側で処理することも考えていなかった。今回の要件は以下のようになるだろうか。


  • 開発環境 MacBook Air + 無料の開発環境
  • Androidから見られるようにしたい
  • 最初はMac上でいろいろ試したい
  • 完成したもののロジックはクラウドで(Google App Engine?)
Macで使うことを考えると、Objective CもしくはSwiftという選択肢がある。速度的にはこれが一番早いだろう。他のデバイスで動かすことには適さない。マルチプラットフォームという話では、HTML/JavaScriptがいいのだろうな。無料で開発できるし。node.jsを動かしたようなクラウドサービスを使えば、これをクラウド側に展開することも可能だ。しかし、Google App Engineは対応していない。これからはHTML5だ、とか、口では言うのだが、あまり優秀な開発環境がないからか、書きにくくて好きではない。UI部分はまだしもロジックを書くのには向かないように思う。結局、Javaを使うか。これなら、Google App Engineも対応しているので最終的にロジック部分を全部移行することが可能だろうし、Eclipseで開発ができる。データベースをどうするかだが、めんどくさいので、最初のうちは、計算時は全部メモリ上において動作させるか、富豪プログラミング的に。最近はoracleとかのデータベースもインメモリが使われているしな。毎回、Yahooのページからデータを取るわけに行かないから、取ってきたデータをメモリ展開したものをファイルに保存することにする。

2014年7月18日金曜日

競馬のデータ

競馬の予想アプリを作ろうで書いたように、JRA-VANから生データは手に入れられないし、MAC用のSDKは現在はないようである。でも、データがないことには、どうもならん。ということで、何らか方法を考える。APIを提供してくれているところないかなー、と思ったが、さすがにそれはないようだ。しかし、競馬の結果を見ることができるWebサイトはいくつかある。そのデータを利用することにする。どこのサイトにしようかと思ったが、Yahooの競馬にすることに決めた。どこでも、大差ないと思うが、大手の安心感というやつか。で、当たり前だが、仕様書があるわけではない。したがって、仕様を推測しながら作ることになる。まずはURL。
結果のサイトは、

http://keiba.yahoo.co.jp/race/result/1402020101/

のようなURLになっている。どうもこれは、

http://keiba.yahoo.co.jp/race/result/[year - 2000][競馬場ID][x回][x日][xレース]/

という形式らしい。競馬場IDは、

01:札幌, 02:函館, 03:福島, 04:新潟, 05:東京, 06:中山, 07:中京, 08:京都, 09:阪神, 10:小倉

のようだ。昔、JRA-VANのデータを使ったときも同じだった気がするな。0はなくて10まで。ということで、この形式でURLを生成すれば、結果のページを取得できる。対応するレースが存在しない場合は、404エラーが帰ってくるので、404エラーが帰ってくるまで繰り返せば、すべてのデータを取ることが可能だ。

2014年7月17日木曜日

競馬の予想アプリを作ろう

完全にほったらかしになっていたのだが、少しずつ書いていきたい。

GWに友人に連れられてひさしぶりに競馬に行った。天皇賞含め、いくつかのレースを買ったのだが、惨敗。ひとつも取れず。昔は、自身で予想ソフトを作って、それをもとに予想していたが、新聞だけを読んで予想も楽しいものだった。

その後、競馬はしてないのだが、今、予想ソフトを作ってみると当時と違うことが出来るだろうか、と思い出した。で、作ってみることにした。

まず、データをどこからか取らなければ行けない。昔は、たしかnifty経由でJRA-VANからデータが取れたんだったっけ。しかし、今は違う。JRA-VANのサイトを見ると、JRA-VANデータラボの会員になる必要があるらしい。これは、月額2,052円(こっちのページには1,995円になっている、消費税が5%->8%であがってこちらは修正漏れか)。高いと言えば高いが、まあ、それで楽しめるのであればいいと思ったのだが、このサービスはデータをくれるのではなく、SDKベースでデータにアクセスできるようになるものらしい。

しかし、このSDKはMacで使えなさそうである。Q&Aでは、



Macintosh版のSDK(JV-Link)はありますか?
JRA-VAN SDKの中にMacintosh版も含まれております。
Macintosh版のJV-Linkは、Carbonインターフェースとして作成されており CodeWarriorやOS標準でバンドルされているXcodeで開発可能です。
と書かれているのだが、JV-Link質問箱では、

申し訳ございませんが、Mac版のJV-Link、SDKの更新は
現在行っておらず、Cocoaによる開発にも対応しておりません。


になっている。ということで、現在は使えないのだろう。どちらにしろ、Android版はなさそうだ。SDKベースではなくデータそのものを配布してくれればいいのに。