Edited at

POG上達のためのデータ解析1 〜Pythonでwebスクレイピング〜

More than 3 years have passed since last update.


はじめに

競馬にはPOGという遊びがある。

これは架空の馬主となって所有馬の活躍度を競うものである。一般的にはデビューからダービーまでの期間の獲得賞金を活躍度の指標とすることが多い。

筆者はかれこれ5年ほどPOGを続けている。

これまでは、毎年4月頃になると発売される青本を頼りに、なんとなく良さ気な馬を選んできた。

しかしながら成績は燦々たるもので今年に至っては10頭中まだ2頭しか勝ち上がっていない。

このうだつのあがらない状況を打破すべく、データ解析に本腰を入れる事にした。ただし筆者には最近流行りの機械学習を自在に操るほどのスキルがない。そこで、ここでは馬の基本情報(厩舎、生産者、血統)とPOG期間中の獲得賞金との間にある因果関係を見出すことを当面の目標としたい。

ここで重要なのが「POG期間中の獲得賞金」である。筆者の知る限り、この情報を公開しているwebサイトは存在しない。もしかしたら有料で提供している機関はあるかもしれないが、費用に見合う効果があるか不明な状況では手を出したくない。

よって、ここではnetkeibaから馬の基本情報や出走歴のデータを取得し、出走歴データを使ってPOG期間中の賞金を計算する という手段を取ることとした。

また、使用した言語はPythonである。これは単に筆者が使い慣れているだけである。


ソースコード

2010年〜2013年までの4年間の間に生まれた馬のデータを収集する。

ここでは4コアの並列処理によって、4年分のデータを同時に取得するようにしている。

マシンスペックにもよるだろうが、筆者のMBAでは約1時間ほどでデータを取り終えた。

※2015/12/30編集

サーバアクセス処理の中に10秒間の時間待ち関数を挿入した。

これなら人力でサイトを閲覧する程度の頻度に抑えられるので過度なアクセスにはならないだろう。


MakeUmaDB_151229.py

#!/usr/bin/env python

# encoding: utf-8

import urllib2 as ul
import pandas as pd
import os
import time
import datetime
from lxml import html
import multiprocessing as mp

__PROC__ = 4

def MakeDir(dname):
if not os.path.exists(dname):
os.mkdir(dname)
print 'Make directory:%s' % dname
else:
print '%s is exist' % dname

return 0

def subMakeHorseDB(year):
# Set Directory
o_dname = 'horse_db'
MakeDir(o_dname)

# horse_prof
prof_keys = [
u'馬名',
u'生年月日',
u'調教師',
u'馬主',
u'生産者',
u'産地',
u'セリ取引価格',
u'父',
u'母',
u'母父',
u'POG期間賞金_半期',
u'POG期間賞金_通年'
]

# get Uma data from web site
base_url = 'http://db.netkeiba.com/horse/'
idx_from = 100000
idx_to = 111000

masta_d = {}
for idx in range(idx_from, idx_to + 1):
try:
# get html from web
time.sleep(10)
s_idx = str(year)+str(idx).zfill(6)
url = base_url + s_idx
src_html = ul.urlopen(url).read()# get html from url
root = html.fromstring(src_html)

# show progress
print 'idx: %s, (%d, %d/%d)' % (s_idx, year, idx, idx_to)

# not found db
if root.xpath('//title')[0].text.startswith(u'|'):
#print 'DB not found'
continue

# html parse
masta_d[s_idx] = {}

for prof in prof_keys:
if prof == u'馬名':
horse_name = root.xpath('//div[@class="horse_title"]')[0].text_content().split('\n')[1]
masta_d[s_idx][prof] = horse_name

elif prof == u'父':
masta_d[s_idx][prof] = root.xpath('//td[@rowspan="2"][@class="b_ml"]')[0].text_content().split('\n')[1]

elif prof == u'母':
masta_d[s_idx][prof] = root.xpath('//td[@rowspan="2"][@class="b_fml"]')[0].text_content().split('\n')[1]
elif prof == u'母父':
masta_d[s_idx][prof] = root.xpath('//td[@class="b_ml"]')[2].text_content().split('\n')[1]
elif prof == u'POG期間賞金_半期' or prof == u'POG期間賞金_通年':
continue
elif prof == u'生年月日':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[0].text_content()
elif prof == u'調教師':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[1].text_content()
elif prof == u'馬主':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[2].text_content()
elif prof == u'生産者':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[3].text_content()
elif prof == u'産地':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[4].text_content()
elif prof == u'セリ取引価格':
masta_d[s_idx][prof] = root.xpath('//table[@class="db_prof_table"]/tr/td')[5].text_content()

# calc POG prize
prize_all = 0.0
prize_half = 0.0
deadline_all = datetime.datetime.strptime('%d-07-01'%(year+3), '%Y-%m-%d')
deadline_half = datetime.datetime.strptime('%d-01-01'%(year+3), '%Y-%m-%d')

r_hist = root.xpath('//table[@class="db_h_race_results nk_tb_common"]')
if len(r_hist) == 0:
masta_d[s_idx][u'POG期間賞金_半期'] = '%d' % prize_half
masta_d[s_idx][u'POG期間賞金_通年'] = '%d' % prize_all
else:
r_hist_l = root.xpath('//table[@class="db_h_race_results nk_tb_common"]/tbody/tr')
for race in r_hist_l:
r_date = datetime.datetime.strptime(race.text_content().split('\n')[1],'%Y/%m/%d')
try:
prize = float(race.text_content().split('\n')[-2].replace(',',''))
except:
prize = 0.0

if r_date < deadline_all:
prize_all += prize
if r_date < deadline_half:
prize_half += prize

masta_d[s_idx][u'POG期間賞金_半期'] = '%.2f' % prize_half
masta_d[s_idx][u'POG期間賞金_通年'] = '%.2f' % prize_all
except:
pass

# make data frame
df = pd.DataFrame(masta_d).T
o_df = pd.DataFrame()

# sort columns
for prof in prof_keys:
o_df = pd.concat([o_df, df[prof]], axis=1)
o_df.index.name = 'Index'

o_fname = 'horse_prof_%d.csv' % year
o_fpath = os.path.join(o_dname, o_fname)
o_df.to_csv(o_fpath, encoding='utf-8')

def main():

year_l = [2010, 2011, 2012, 2013]
pool = mp.Pool(__PROC__)
pool.map(subMakeHorseDB, year_l)

if __name__ == '__main__':
main()
raw_input('Press Enter to Exit¥n')



今後

吐き出されたcsvファイルをこねくり回してPOG必勝の法則を見出したい。