頻馬主義

競馬のデータをいろいろ見ていきます

JRA公式データを用いたデータ分析マニュアル 正誤表

先日面白そうな本を見つけたので早速購入しました。

f:id:mare_ism:20210410182201p:plain:w217:h280

cutt.co.jp

Amazonなどでは品薄状態が続いているようですね。

書籍にざっと目を通し、サンプルコード*1を一通り動かしてみたところ、いくつか誤植が見つかりました。

現時点では公式の正誤表が出ていないようなので、気付いたものからこの記事に書いていきたいと思います。

書籍

第1章
  • P13 「A. 通常データ種別」のチェック項目

(DIFF-BR) 生産者マスタが2回書かれている

第3章
  • P75 プログラムソースのファイル名

誤 : sql_test.cpp

正 : sql_test.py

第4章
  • P174 サンプルコード1枠目

#馬体重差配列
BaTaijyuSas  = ["~-24", "-24~-16", "-16~-8", "-8~0", "0", "0~+8", "+8~+16", "+16~+24", "+24~"]

#馬体重差配列
BaTaijyuSas  = ["~-24", "-24", "-16", "-8", "0", "+8", "+16", "+24", "+24~"]
  • P174 サンプルコード2枠6行目

                    elif( -24 <= ZogenSa < -16 ):
                        BaTaijyuSa = "-24~-16"

                    elif( -24 <= ZogenSa < -16 ):
                        BaTaijyuSa = "-24"

サンプルコード

第3章
  • [3.1.2]sql_test.py 4行目
  • [3.1.3]sql_race_dictionary.py 4行目
  • [3.1.3]sql_table_info.py 4行目
  • [3.1.4]sql_race_GI.py 4行目
  • [3.2.1]sql_uma_race.py 4行目
  • [3.2.2]sql_uma_race2.py 4行目

connection = sqlite3.connect("../ecore_2019.db")

connection = sqlite3.connect("../ecore.db")
  • [3.5.7]utility_test_getZensoAgariJyunni.py 33行目

    zensoAgariJyunni = U.getZensoAgariJyunni( KettoNum, zensoRACE )

    zensoAgariJyunni = U.getZensoAgariJyuni( KettoNum, zensoRACE )
  • utility.py 269行目

    HaronTimeL3s = {}

    HaronTimeL3s = {}
    myHaronTimeL3 = 0
第4章
  • [4.5.5]All_BataijuSa_odds_courses.py 141行目

                        BaTaijyuSa = "~-8"

                        BaTaijyuSa = "-8"

*1:2021/04/01にダウンロードしたものを使用しています。

【馬王Z SQL講座】 2つの条件での抽出

1つの条件での抽出に関する記事はこちら

【馬王Z SQL講座】 条件抽出 - 頻馬主義

2つの条件

データを抽出するときに、複数の条件を使いたいことがあります。

ここで、2つの条件でデータを抽出することを考えてみましょう。

抽出対象としたいデータはどちらか片方の条件を満たしていればいいのか、それとも両方の条件を満たしていなければならないのかなどを区別する必要があります。

ここでは2つの条件として

  • 馬名がリジェネレーション
  • 競走コードが 21210070805

を使いたいと思います。

出走馬T テーブルからそれぞれの条件でデータ抽出したときのクエリと実行結果は以下のようになります。(出力対象のカラムは 年月日、競走コード、馬名 としています。)

馬名がリジェネレーション
クエリ
SELECT
    年月日,
    競走コード,
    馬名
FROM
    出走馬T
WHERE
    馬名 = "リジェネレーション"
;
実行結果

f:id:mare_ism:20210325033156p:plain

競走コードが 21210070805
クエリ
SELECT
    年月日,
    競走コード,
    馬名
FROM
    出走馬T
WHERE
    競走コード = 21210070805
;
実行結果

f:id:mare_ism:20210325033215p:plain

両方の実行結果に、馬名がリジェネレーション かつ 競走コードが 21210070805 のレコードが1件含まれていますね。

論理演算

2つの条件(条件Aと条件B)を使った基本的な構文は下記の通りです。

SELECT
    [カラム名]
FROM
    [テーブル名]
WHERE
    [条件式A] [論理演算子]
    [条件式B]
;

このように2つの条件式の間に論理演算子を記述します。

では、論理演算子にはどんな種類があるんでしょうか?

AND:論理積

2つの条件の両方を満たしているレコードを抽出対象としたい場合には AND(論理積) を使います。

SELECT
    年月日,
    競走コード,
    馬名
FROM
    出走馬T
WHERE
    馬名 = "リジェネレーション" AND
    競走コード = 21210070805
;

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210325040021p:plain

OR:論理和

2つの条件の片方を満たしているレコードを抽出対象としたい場合には OR(論理和) を使います。

両方の条件を満たしているレコードも抽出対象となります。

SELECT
    年月日,
    競走コード,
    馬名
FROM
    出走馬T
WHERE
    馬名 = "リジェネレーション" OR
    競走コード = 21210070805
;

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210325040035p:plain

XOR:排他的論理和

2つの条件の片方だけを満たしているレコードを抽出対象としたい場合には XOR(排他的論理和) を使います。

両方の条件を満たしているレコードは抽出対象外となります。

SELECT
    年月日,
    競走コード,
    馬名
FROM
    出走馬T
WHERE
    馬名 = "リジェネレーション" XOR
    競走コード = 21210070805
;

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210325040045p:plain

OR を使った実行結果と違って 馬名がリジェネレーション かつ 競走コードが 21210070805 のレコードは抽出されていないことに注意して下さい。

【馬王Z SQL講座】 条件抽出

WHERE句:データの抽出条件を記述する

テーブルの中にあるデータから、何らかの条件に合致するレコードだけ抽出したいときには WHERE句を使います。

WHERE句を使った基本的な構文は下記の通りです。

SELECT
    [カラム名]
FROM
    [テーブル名]
WHERE
    [条件式]
;

数値で条件を指定

では、出走馬T テーブルから単勝配当が10,000円のデータを抽出するクエリを書いてみましょう。

SELECT
    *
FROM
    出走馬T
WHERE
    単勝配当 = 10000
;

このクエリのように、テーブルのデータを全件チェックするようなクエリは実行終了まで少し時間がかかります。*1

このクエリを実行すると、下図のような結果が得られます。*2

f:id:mare_ism:20210324071958p:plain

文字列で条件を指定

次に、出走馬T テーブルから馬名がアーモンドアイのデータを抽出するクエリを書いてみましょう。

SELECT
    *
FROM
    出走馬T
WHERE
    馬名 = "アーモンドアイ"
;

このように条件式に文字列を使う場合には「 " (ダブルクォート)」もしくは「 ' (シングルクォート)」で囲みます。

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210324072918p:plain

カラム同士の比較で抽出

抽出条件には上でやったように数値や文字列での指定もできますが、カラム同士の比較を用いることもできます。

出走馬T テーブルから 入線順位 と 確定着順 が等しくないデータを5件抽出するクエリを書いてみましょう。

出力対象のカラムは

  • 年月日
  • 馬名
  • 入線順位
  • 確定着順

とします。

SELECT TOP 5
    年月日,
    馬名,
    入線順位,
    確定着順
FROM
    出走馬T
WHERE
    入線順位 <> 確定着順
;

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210324073431p:plain

比較演算子

条件式を記述するときに使える比較演算子には以下のようなものがあります。

比較演算子 使い方 説明 備考
= A = B AとBは等しい
<> A <> B AとBは等しくない != は使えない
< A < B AはBより小さい
<= A <= B AはB以下
> A > B AはBより大きい
>= A >= B AはB以上

では、出走馬T テーブルから馬体重が630kg以上のデータを重い順に抽出するクエリを書いてみましょう。

出力対象のカラムは

  • 年月日
  • 馬名
  • 馬体重

とします。

SELECT
    年月日,
    馬名,
    馬体重
FROM
    出走馬T
WHERE
    馬体重 >= 630
ORDER BY
    馬体重 DESC
;

このクエリを実行すると、下図のような結果が得られます。

f:id:mare_ism:20210324083057p:plain

やっぱりショーグンは大きいですね!

*1:ブログ主の環境では30~40秒ほどかかりました。

*2:馬王Zのデータ取得状況によっては結果が一致しないことがあります。

【馬王Z SQL講座】 データの並び替え

SELECT文でデータの取得

まずは前回の復習として、競走馬マスタ テーブルから

  • 血統登録番号
  • 馬名

を5行取得してみましょう。

SELECT TOP 5
    血統登録番号,
    馬名
FROM
    競走馬マスタ
;

このクエリを実行すると、下図のような結果が得られます。*1

f:id:mare_ism:20210323060855p:plain

この結果はたまたま競走馬マスタ テーブルの先頭に格納されていたデータを取得しただけなので、あまり意味がありません。

ORDER BY 句:昇順に並び替え

SELECT文で取得した結果を並び替えるには ORDER BY 句を使います。

ORDER BY 句に並び替えに使いたいカラムを書きます。

SELECT TOP 5
    血統登録番号,
    馬名
FROM
    競走馬マスタ
ORDER BY
    血統登録番号
;

このクエリを実行すると、血統登録番号が昇順(小さい順)に5件データが出力されます。*2

f:id:mare_ism:20210323061050p:plain

DESC:降順に並び替え

降順(大きい順)に並び替えたい場合は ORDER BY 句で指定したカラムの後ろに DESC を付け加えます。

SELECT TOP 5
    血統登録番号,
    馬名
FROM
    競走馬マスタ
ORDER BY
    血統登録番号 DESC
;

このクエリを実行すると、血統登録番号が降順に5件データが出力されます。

f:id:mare_ism:20210323062259p:plain

同値のデータがあった場合

競走馬マスタ テーブルから、生年月日を降順に5件取得するクエリを書いてみましょう。

SELECT TOP 5
    血統登録番号,
    馬名,
    生年月日
FROM
    競走馬マスタ
ORDER BY
    生年月日 DESC
;

このクエリを実行すると、下図のデータが出力されました。

f:id:mare_ism:20210323064328p:plain

TOP 5 と指定したはずなのに6行ありますね。何故でしょう?

生年月日が大きい方から4番目のデータは 2019/06/09 で、同じ生年月日の馬は3頭います。

このように TOP と ORDER BY を併用すると、上位n番目(nは TOP で指定した数)に同値のデータがあった場合n件より多いデータが出力されるので注意が必要です。*3

上位n番目に同値のデータがない場合

挙動を理解するために、同様の条件で上位9件取得してみましょう。

SELECT TOP 9
    血統登録番号,
    馬名,
    生年月日
FROM
    競走馬マスタ
ORDER BY
    生年月日 DESC
;

このクエリを実行すると、下図のデータが出力されました。

f:id:mare_ism:20210323065945p:plain

生年月日が 2019/06/09 のデータが3件、2019/06/06 のデータが2件ありますが、9件目には同値のデータがないので指定したとおり9件出力されています。

*1:馬王Zのデータ取得状況によっては結果が一致しないことがあります。

*2:出力結果が並び替えられているだけで、テーブル内のデータに変化はありません。

*3:MySQLなどで使える LIMIT 句とは挙動が違います。

【馬王Z SQL講座】 SELECT文でデータを取得

SELECT文:テーブルのデータを取得する

SQLの初歩はテーブルからデータを取得するSELECT文です。

一番シンプルなSELECT文は

SELECT * FROM [任意のテーブル名];

ですが、これだと指定したテーブルの全レコードを取得しようとします。

馬王Z内のほとんどのテーブルは大量のレコードが入っているため、全レコードを取得するクエリを実行すると処理が終わるまでにかなりの時間がかかったり、場合によっては下図のようなメモリ不足の例外が発生してしまいます。

f:id:mare_ism:20210323050829p:plain

できる限り、そんなクエリは実行しないようにしましょう。

TOP:テーブルの先頭n行を取得する

テーブルの中にどんなデータが入っているか確認するときはTOPを使用します。

SELECTの後ろにTOP n(nは取得したい行数)を記述するとテーブルの先頭n行を取得することができます。

では、競走馬マスタ テーブルから先頭5行を取得してみましょう。

SELECT TOP 5 * FROM 競走馬マスタ;

このクエリを実行すると、下図のような結果が出力されます。*1

f:id:mare_ism:20210323051155p:plain

取得する列を指定する

テーブルにはたくさんの列があります。

先程書いたSELECT文の  *アスタリスク)は「全ての列」という意味になります。

取得したい列を指定するには、 * の代わりに列名を書きます。複数の列を指定したい場合はカンマで区切って列挙します。

では、競走馬マスタ テーブルから

  • 血統登録番号
  • 馬名
  • 生年月日

を5行分取得するクエリを書いてみましょう。

SELECT TOP 5 血統登録番号, 馬名, 生年月日 FROM 競走馬マスタ;

これでもいいのですが、クエリが少し長くなってきました。

横に長いクエリは読みづらいので、可読性を上げるため改行とインデント(文字下げ)を追加します。

SELECT TOP 5
    血統登録番号,
    馬名,
    生年月日
FROM
    競走馬マスタ
;

SQLでは改行やインデントは実行時に無視されるので、どちらのクエリでも同じ結果が得られます。

f:id:mare_ism:20210323052010p:plain

*1:馬王Zのデータ取得状況によっては結果が一致しないことがあります。

【馬王Z SQL講座】 データベース操作機能の呼び出し方

馬王Zのデータベース操作機能

競馬ソフトの馬王Zでは[ツール] > [データベース操作]からSQLによるデータ操作機能を呼び出すことができます。

f:id:mare_ism:20210323042758p:plain

すると、下図のようなデータベース操作の画面が開きます。

f:id:mare_ism:20210323042931p:plain

馬王Zにあるデータ

馬王Zのデータベースにはたくさんのテーブルがあり、その中に様々なデータが入っています。

どんなテーブルがあるかは、データベース操作画面右上のドロップダウンリストから確認することができます。

f:id:mare_ism:20210323043202p:plain

  • 競走馬T
  • レースT
  • 競走馬マスタ
  • 騎手マスタ
  • 調教師マスタ

などのテーブルがあることが分かります。

テーブルのカラム

各テーブルには1つ以上のカラム(列)があります。

ドロップダウンリストでテーブルを指定すると、そのテーブルに含まれるカラムの一覧が下の枠に表示されます。

f:id:mare_ism:20210323043901p:plain

出走馬T テーブルには

  • データ区分
  • データ作成年月日
  • 競走コード
  • 馬番
  • 枠番
  • 馬名
  • 血統登録番号

などのカラムがあることが分かります。

SQLのクエリを実行してみよう

SQLとは「Structured Query Language」の頭文字をとった略称で、データベースを操作するための言語です。

SQLで書かれた命令文のことをクエリと呼びます。

ではここで、とてもシンプルなクエリを書いて実行してみましょう。

SQLと書かれた枠の中に、

SELECT 1;

と書いて、右にある[実行]ボタンを押します。

f:id:mare_ism:20210323045254p:plain

画面の下側に1と表示されればOKです。

毛色別獲得賞金ランキング

サラブレッドの毛色は8種類に別れており、馬を見分けるのに役立ちます。

今回は毛色を中心に馬のデータを見てみました。

毛色別頭数

2021年03月09日時点のJRA-VANデータには、186,161頭分*1の登録データがあります。 このデータから毛色別に頭数を集計したのが次のグラフと表になります。

f:id:mare_ism:20210309220448p:plain

毛色 頭数 比率
鹿毛 88,002 47.272%
栗毛 43,560 23.399%
黒鹿毛 31,450 16.894%
芦毛 11,348 6.096%
青鹿毛 8,252 4.433%
栃栗毛 1,783 0.958%
青毛 1,739 0.934%
白毛 27 0.015%
合計 186,161

全体の半数弱は鹿毛、1/4弱は栗毛ということが分かりました。 また、白毛は圧倒的に少なく、約1万頭に1頭程度の比率です。

毛色別獲得賞金ランキング

次に毛色別の獲得賞金*2上位5頭を見てみましょう。

鹿毛

馬名 生年月日 獲得賞金
キタサンブラック 2012-03-10 1,876,843,000円
アーモンドアイ 2015-03-10 1,519,563,000円
ディープインパクト 2002-03-25 1,454,551,000円
ジェンティルドンナ 2009-02-20 1,326,210,000円
ウオッカ 2004-04-04 1,304,876,000円

栗毛

馬名 生年月日 獲得賞金
テイエムオペラオー 1996-03-13 1,835,189,000円
オルフェーヴル 2008-05-14 1,344,084,000円
ダイワメジャー 2001-04-08 1,002,230,000円
シュヴァルグラン 2012-03-14 1,000,697,000円
ナリタトップロード 1996-04-04 990,112,000円

黒鹿毛

馬名 生年月日 獲得賞金
ブエナビスタ 2006-03-14 1,386,433,000円
ゼンノロブロイ 2000-03-27 1,115,608,000円
スペシャルウィーク 1995-05-02 1,092,623,000円
ナリタブライアン 1991-05-03 1,026,916,000円
シンボリクリスエス 1999-01-21 984,724,000円

芦毛

馬名 生年月日 獲得賞金
ゴールドシップ 2009-03-06 1,397,767,000円
メジロマックイーン 1987-04-03 1,014,657,700円
ビワハヤヒデ 1990-03-10 897,675,000円
オグリキャップ 1985-03-27 889,702,000円
クロノジェネシス 2016-03-06 873,420,000円

青鹿毛

馬名 生年月日 獲得賞金
コントレイル 2017-04-01 796,110,000円
ゴールドアクター 2011-05-18 743,244,000円
フェノーメノ 2009-04-20 629,108,000円
ダンスインザムード 2001-04-10 538,878,000円
ジェニュイン 1992-04-28 537,013,000円

栃栗毛

馬名 生年月日 獲得賞金
サクラローレル 1991-05-08 626,991,000円
マーベラスサンデー 1992-05-31 606,865,000円
ノンコノユメ 2012-03-28 351,611,000円
デアリングハート 2002-03-09 258,362,000円
コイウタ 2003-02-24 236,292,000円

青毛

馬名 生年月日 獲得賞金
ヴィルシーナ 2009-03-05 460,795,000円
ガルボ 2007-05-05 344,321,000円
ローズバド 1998-04-29 331,049,000円
ビートブラック 2007-05-23 320,217,000円
ドリームバレンチノ 2007-02-22 302,898,000円

白毛

馬名 生年月日 獲得賞金
ソダシ 2018-03-08 134,373,000円
ハヤヤッコ 2016-02-10 116,474,000円
シロニイ 2014-02-13 100,523,000円
ブチコ 2012-04-27 64,197,000円
ホワイトベッセル 2004-03-18 28,900,000円

上記の競走馬の中で中央競馬にて現役なのは

の5頭です。 なんと白毛の上位3頭が現役馬なんですね。

今年も白毛馬の活躍から目が離せません。

*1:引退済、未出走、デビューしなかった馬を含む

*2:中央競馬のみ