1.まとめ
- 競走馬のサイアーラインをネットワーク図で可視化してみた。
 - 知っている馬の名前が出てきてうれしかった。
 - もう少し昔まで(できれば祖先の3頭まで)さかのぼりたい
 
2. はじめに
- 
宮本輝の優駿や世界の名馬を小学校で読んで以来サイアーラインにあこがれていた。ダビスタにもはまり夜を徹してゲームしてたりした。
 - 
上記の「優駿」に書いてますが、世界中の競走馬の父系をたどると、たった3頭の馬につながる。現在の競馬(サラブレッド)は17世紀にはじまったので、その家系図をたどることができ、サイアーラインというものがあるとのこと。
 
3.サイアーラインとは
- 説明記事を参照。
 - どの馬にも、父をさかのぼると3頭の血のみが受け継がれているなんて、ロマンがある!ぜひこれをたどって可視化したい!
 
4. データ
- ネット上にもいろいろ情報が散らばっているけど、まとまってデータをとれたのが(JRDB)[http://www.jrdb.com/]の有料会員の競馬データ。
 - 血統以外にもオッズデータ、調教師データ、騎手データ、開催データなどこまかくひろく色々情報があるのでそれはそれで面白そうだが今回は割愛。
 - 血統データの項目は次のような感じ。
 
馬名
性別コード
毛色コード
馬記号コード
血統情報
  父馬名
  母馬名
  母父馬名
生年月日
父馬生年
母馬生年
母父馬生年
馬主名
馬主会コード
生産者名
産地名
登録抹消フラグ
データ年月日
父系統コード
母父系統コード   
このうち、馬名、父馬名、母馬名、母父馬名をとれればサイアーライン(+α)が可視化できるだろう、ということで抽出。可視化は例のようにpyvisを利用させてもらう。
まずは上記のデータをBigQueryに投入。
カラム名がひどくてすみません。

#_1=馬名、5_=父馬、6_=母馬、7_=母父馬
SELECT _1,_5,_6,_7 FROM `racehorse.racehorse.ukc`
WHERE _7 LIKE "%メジロマックイーン%" AND _5 LIKE "%ステイ%"
GROUP BY _1,_5,_6,_7
ORDER BY _1 ASC
ちゃんと、ゴールドシップとオルフェーブルが入ってますな。
さて、以下で
SELECT _1,_5 FROM `racehorse.racehorse.ukc`
GROUP BY _1,_5
UNION DISTINCT
SELECT _1,_6 FROM `racehorse.racehorse.ukc`
GROUP BY _1,_6
UNION DISTINCT
SELECT _6,_7 FROM `racehorse.racehorse.ukc`
GROUP BY _6,_7
4.1 edgeデータ作成
from google.cloud import bigquery
project_id = 'racehorse'
client = bigquery.Client(project=project_id)
def getlinedata():
    #search_term = query
    # 実行するクエリ
    query3 =  """
    SELECT _1,_5 FROM `racehorse.racehorse.ukc`
    GROUP BY _1,_5
    UNION DISTINCT
    SELECT _1,_6 FROM `racehorse.racehorse.ukc`
    GROUP BY _1,_6
    UNION DISTINCT
    SELECT _6,_7 FROM `racehorse.racehorse.ukc`
    GROUP BY _6,_7
         """
    # メソッドに`to_dataframe()`をつけるとpd.DataFrameで結果を受け取れる
    all_df = client.query(query3).to_dataframe()
    return all_df
frame = getlinedata()
frame.rename(columns={"_5":"source","_1":"target"},inplace=True)
4.2networkxに入れる。
import networkx as nx
G = nx.from_pandas_edgelist(frame,create_using=nx.DiGraph())
eigen_centrality = nx.eigenvector_centrality_numpy(G)
bet_centrality = nx.betweenness_centrality(G,k=10)
degree_centrality = nx.degree_centrality(G)
degree_coefficient = nx.clustering(G)
4.3 次数中心上位を見る
pd.DataFrame([degree_centrality]).T.sort_values(by=0,ascending=False).head(20)
4.4 絞りこみ後、pyvisに入れる
- 全員いれるとメモリが足りずクラッシュしたので、次数中心性上位のみを入れる。
 
degree_filter = pd.DataFrame.from_dict(degree_centrality.items()).pipe(lambda df:df[df[1]>0.01])[0].tolist()
frame2 = frame[frame['source'].isin(degree_filter)]
G2 = nx.from_pandas_edgelist(frame2,create_using=nx.DiGraph())
#!pip install pyvis #最初に実行
from pyvis.network import Network
pyvis_G = Network()
pyvis_G.from_nx(G)
pyvis_G.show("mygraph.html")
5.可視化結果
pyvisでやりたかったけど、重すぎてダメだっため、急遽gephiを使うことに。しかも2022年にソフトウェアが更新されていた。5年前の更新が最後だったので、これはこれで差分を要確認
1個のノード=1頭の馬。ノードの大きさ=次数(出次数=子供が多い)に比例して、馬の名前が大きく表示される。色の違い=グループの違い(modularity)。考察は別途。ちょっと見るだけでもなかなか面白い。フジキセキの位置がおかしい気がするけど、サンデーサイレンスのすごさが分かる。
主要馬のグルーピング(上記の色分け)
| グループ | 馬名 | 
|---|---|
| 0 | ハービンジャー、ダンカーク、ルーラーシップ、マジェスティックウォリアー、サンデーサイレンス、エルコンドルパサー、アグネスタキオン、クロフネ、ファルブラヴ、ジャングルポケット、チチカステナンゴ、シンボリクリスエス、ウォーエンブレム、ローエングリン、キングカメハメハ、カンパニー、トーセンジョーダン、エイシンフラッシュ、モーリス、ストロングリターン、エピファネイア、ノヴェリスト、タートルボウル | 
| 1 | キンシャサノキセキ、トニービン、フジキセキ | 
| 2 | オンファイア、ワークフォース、フレンチデピュティ | 
| 3 | ヘニーヒューズ、アルデバラン、ケイムホーム、ヨハネスブルグ、エンパイアメーカー、バゴ、ルールオブロー、バトルプラン、ケープブランコ | 
| 4 | ダノンシャンティ、ロックオヴジブラルタル、ブラックタイド | 
| 5 | アドマイヤムーン、パイロ、ファンタスティックライト、キングズベスト、ストーミングホーム、フリオーソ、モンテロッソ | 
| 6 | スクリーンヒーロー、マツリダゴッホ、ドリームジャーニー、コンデュイット、ナカヤマフェスタ、アイルハヴアナザー、ステイゴールド、ショウナンカンプ、タイムパラドックス、ロージズインメイ、ゴールドシップ | 
| 7 | ディープブリランテ、トーセンホマレボシ、リアルインパクト | 
| 14 | リアルシャダイ | 
| 15 | ホリスキー、タヤスツヨシ、エアジハード | 
| 16 | バブルガムフェロー | 
| 19 | カーリアン、シルヴァーチャーム | 
| 22 | モガミ、アスワン、シンボリルドルフ、シャーディー | 
| 23 | パークリージェント、タイトスポット、ロドリゴデトリアーノ | 
| 24 | ミスタープロスペクター、ブレイヴェストローマン、トウショウボーイ、ロイヤルスキー、ダイナガリバー、アジュディケーティング、リズム、ウイニングチケット、エイシンサンディ | 
| 25 | ダンスインザダーク | 
| 27 | デュラブ、ラストタイクーン、サクラチトセオー、タバスコキャット | 
| 30 | シアトルスルー、ヌレイエフ、ストームキャット | 
| 31 | オジジアン、グルームダンサー、デザートキング | 
| 33 | タマモクロス、ゴールデンフェザント、ディアブロ、スターオヴコジーン、スターオブコジーン、ペンタイア、サニーブライアン | 
| 34 | ゴーンウェスト、キングマンボ | 
| 35 | シーキングザゴールド、フォーティナイナー、デヒア、ボストンハーバー、コロナドズクエスト、カリズマティック | 
| 36 | ラッキーソヴリン、サッカーボーイ、ティッカネン、ロイヤルタッチ | 
| 37 | ダンジグ、アフリート、ウォーニング | 
| 39 | ニホンピロウイナー、アドマイヤベガ、アドマイヤボス | 
| 40 | ピルサドスキー | 
| 41 | ブライアンズタイム | 
| 43 | マルゼンスキー、サクラユタカオー、マイニング、サンシャインフォーエヴァー、カコイーシーズ、サクラローレル、サクラプレジデント | 
| 44 | キンググローリアス、チーフベアハート、スクワートルスクワート | 
| 45 | ジャイアンツコーズウェイ、ディープインパクト、ロードカナロア、ドゥラメンテ、オルフェーヴル | 
| 46 | ソヴィエトスター、メジロマックイーン、メジロライアン、ホワイトマズル | 
| 47 | ブラックタイアフェアー、ジョリーズヘイロー、アッミラーレ | 
| 48 | サンダーガルチ | 
| 50 | クリエイター、ジェイドロバリー、ナリタトップロード | 
| 51 | ウッドマン、ヘクタープロテクター、ナリタブライアン | 
| 52 | シアトルダンサー2、アンバーシャダイ、バンブーアトラス、クリスタルグリッターズ、ミスターシービー、ダンシングブレーヴ、エブロス、スキャン、リンドシェーバー、ハンセル、エルハーブ、サマーサスピション | 
| 53 | ジェネラス | 
| 54 | クリミナルタイプ、オペラハウス、トウカイテイオー、ゼンノエルシド | 
| 55 | スリルショー、ヤマニンゼファー、ミシル、ティンバーカントリー | 
| 56 | ノーザンテースト、ミルジョージ、アレミロード、ドクターデヴィアス、ジェニュイン、フサイチコンコルド、ゴールドヘイロー、フサイチソニック | 
| 58 | シャンハイ、ブラックタキシード | 
| 60 | アラジ | 
| 62 | コマンダーインチーフ、テンビー、マヤノトップガン、キングヘイロー、オース、アグネスフライト、グランデラ、ムーンバラッド、アドマイヤジャパン | 
| 64 | ビワハヤヒデ、タイキブリザード、マーベラスサンデー | 
| 65 | トワイニング、スウェプトオーヴァーボード | 
| 66 | サクラバクシンオー、エンドスウィープ | 
| 68 | ラムタラ、タイキシャトル、アルカセット | 
| 70 | スペシャルウィーク | 
| 72 | グラスワンダー | 
| 73 | パラダイスクリーク、リーチザクラウン | 
| 74 | ブラックホーク、ストラヴィンスキー | 
| 75 | エリシオ、クロコルージュ、キャプテンスティーヴ | 
| 76 | カーネギー | 
| 77 | カジノドライヴ、アグネスデジタル | 
| 78 | ソングオブウインド、メイショウオウドウ、ミラクルアドマイヤ、アドマイヤコジーン、ニューイングランド、アドマイヤマックス、オレハマッテルゼ、リンカーン、サムライハート | 
| 79 | タニノギムレット、ベルシャザール | 
| 80 | テイエムオペラオー | 
| 81 | ソウルオブザマター、グランプリボス | 
| 82 | マイネルラヴ | 
| 84 | ヴィクトワールピサ、エーピーインディ、フサイチペガサス、ゴールドアリュール、デュランダル、ネオユニヴァース、ゼンノロブロイ、ハーツクライ、ダイワメジャー、ジャスタウェイ | 
| 85 | シニスターミニスター、メイショウサムソン、メイショウドトウ、マリエンバード、プリサイスエンド、スタテューオブリバティ、メイショウボーラー、フォーティーナイナーズサン、トゥザグローリー | 
| 96 | サドラーズウェルズ、デインヒル | 
| 97 | ディープスカイ、マンハッタンカフェ、キズナ | 
| 98 | シアトリカル、アサティス、カリスタグローリ、ワイルドラッシュ、サウスヴィグラス、スキャターザゴールド、スズカマンボ、スズカフェニックス | 
| 99 | ファスリエフ、スターリングローズ、カネヒキリ、ヴァーミリアン、スマートファルコン、ベーカバド | 
6.次にやること
- 全部可視化するのが大変なので、純粋にサイアーラインまでとか、主要馬などに絞る機能が欲しい
 - 現状、ノードの大きさは子供の多さ(次数)でつけているけど、色やノードの大きさで何かを表したい(勝利数とか、父系名とか。余談ですがミスタープロスペクター系ってできたんですね。)
 - JRDBのデータが1999年までなので、それ以前の情報をネット上で探してとってきて追加したい。
 - 時系列に並べたい
 - ウェブアプリ化したい。少し作れた
 - データが一部おかしいのを発見。①同じ名前の馬が存在すると1かたまりになってしまう(ex:「キズナ」)。生年月日と性別との組み合わせで分ける必要あり。
 - 親がノード中にいるのに、リンクが張ってない馬がいる(ex:トウカイテイオー-シンボリルドルフ)。1999年より前のデータがないためのエラーのようなのでデータの蓄積を続ける。
 




