きっかけ
「日本のお正月の楽しみといえば、お茶の間で見る箱根駅伝!
このお正月も、みなさん盛り上がったんじゃないでしょうか?」
・・・というほどの箱根駅伝ファンでは、実はないです。
それでも、熱心に見る家族に交じってテレビを見ている最中、
「速い大学って毎年変わる。速い選手を一つの大学が同じ年に10人揃えるのって難しいよね」
という話があり、その点には少し興味をそそられました。
今年はたまたま○○大学(ネタバレ防止のため伏字)が速かったけど、
各大学の「山の神」とか「なんとかの神」呼ばれるような歴代最速メンバーが、
同じ年代に集って大学対抗の箱根駅伝を走ったとしたら、
いったいどの大学が1番になるんだろう。
という「たられば」を、過去のデータから探ってみようと思います。
環境
- Mac OS X 10.10.5
- Python 2.7.9 (virtualenv)
import sys
import os
import glob
import requests
from bs4 import BeautifulSoup
from collections import defaultdict
import numpy
import pandas
考え方
大学ごとに、各区間の歴代最速記録を時速で1計算して、
それを直近の第92回大会のコースに当てはめれば、最速の大学が分かる!?
対象
- 「第31回〜第91回の大会」
- 「区間距離」/「所要時間」で、大学ごと、区間ごとに最高の速度を計算する
↓ - 区間ごとに計算した速度で、第92回の大会を走らせる
手順
htmlの取得
「箱根駅伝公式Webサイト」より、
- 記録ページのhtmlを取得し、大会ごとの出場校を調べる
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import glob
import requests
from bs4 import BeautifulSoup
# User-Agent
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0'
#'From': 'youremail@domain.com' # This is another valid field
}
"""
# URL example
http://www.hakone-ekiden.jp/data/data_race.php?racenum=31
"""
def crawl_site(site_url):
# クロール対象URLを生成
tocrawl = [site_url+'?racenum='+str(i) for i in xrange(31, 92)]
return tocrawl
def prepare_html(tocrawl, html_path, identifier_prefix):
crawled = []
for i,site_url in enumerate(tocrawl):
print 'prepare_html:', site_url
r = requests.get(site_url, headers=headers)
filename = html_path + identifier_prefix + site_url.split('=')[1] + '.html'
f = open(filename, 'w')
f.write(r.content)
f.close()
if __name__ == '__main__':
# settings
site_url = 'http://www.hakone-ekiden.jp/data/data_race.php'
html_path = './html/'
identifier_prefix = 'hakone'
if not os.path.exists(html_path):
os.mkdir(html_path)
# prepare html files
num_html_files = len(glob.glob(html_path + identifier_prefix + '*.html'))
print 'num_html_files: ' + str(num_html_files)
if num_html_files == 0:
tocrawl = crawl_site(site_url)
prepare_html(tocrawl, html_path, identifier_prefix)
取得してローカルにダウンロードしたhtmlから、大会ごとの出場校を求めます。
続いて、「大学別選手一覧」のhtmlをダウンロードし、
http://www.hakone-ekiden.jp/data/data_univ.php?race=31&univ=50
そこから、ちょっとばかりBeautifulSoupに頼って、
- 出場校ごとに、歴代の区間記録を取得する
print universities
print len(universities)
print
print universities_each_year
print len(universities_each_year)
{4: u'\u6771\u4eac\u6559\u80b2\u5927\u5b66', 9: u'\u95a2\u6771\u5b66\u9023\u9078\u629c', 10: u'\u65e5\u672c\u5b66\u9023\u9078\u629c', 11: u'\u9752\u5c71\u5b66\u9662\u5927\u5b66', 12: u'\u4e9c\u7d30\u4e9c\u5927\u5b66', 13: u'\u795e\u5948\u5ddd\u5927\u5b66', 15: u'\u95a2\u6771\u5b66\u9662\u5927\u5b66', 16: u'\u6176\u5fdc\u7fa9\u587e\u5927\u5b66', 17: u'\u570b\u5b78\u9662\u5927\u5b66', 18: u'\u56fd\u58eb\u8218\u5927\u5b66', 19: u'\u99d2\u6fa4\u5927\u5b66', 20: u'\u57fc\u7389\u5927\u5b66', 21: u'\u9806\u5929\u5802\u5927\u5b66', 22: u'\u57ce\u897f\u5927\u5b66', 24: u'\u5c02\u4fee\u5927\u5b66', 25: u'\u5927\u6771\u6587\u5316\u5927\u5b66', 26: u'\u62d3\u6b96\u5927\u5b66', 27: u'\u4e2d\u592e\u5b66\u9662\u5927\u5b66', 28: u'\u4e2d\u592e\u5927\u5b66', 29: u'\u7b51\u6ce2\u5927\u5b66', 30: u'\u5e1d\u4eac\u5927\u5b66', 31: u'\u6771\u6d77\u5927\u5b66', 32: u'\u6771\u4eac\u5b66\u82b8\u5927\u5b66', 33: u'\u6771\u4eac\u5927\u5b66', 34: u'\u6771\u4eac\u8fb2\u696d\u5927\u5b66', 36: u'\u6771\u6d0b\u5927\u5b66', 38: u'\u65e5\u672c\u5927\u5b66', 39: u'\u65e5\u672c\u4f53\u80b2\u5927\u5b66', 40: u'\u798f\u5ca1\u5927\u5b66', 41: u'\u5e73\u6210\u56fd\u969b\u5927\u5b66', 42: u'\u9632\u885b\u5927\u5b66', 43: u'\u6cd5\u653f\u5927\u5b66', 44: u'\u660e\u6cbb\u5927\u5b66', 45: u'\u5c71\u68a8\u5b66\u9662\u5927\u5b66', 46: u'\u6a2a\u6d5c\u5e02\u7acb\u5927\u5b66', 47: u'\u6a2a\u6d5c\u56fd\u7acb\u5927\u5b66', 48: u'\u7acb\u6559\u5927\u5b66', 49: u'\u7acb\u547d\u9928\u5927\u5b66', 50: u'\u65e9\u7a32\u7530\u5927\u5b66', 78: u'\u4e0a\u6b66\u5927\u5b66', 94: u'\u5275\u4fa1\u5927\u5b66', 95: u'\u95a2\u6771\u5b66\u751f\u9023\u5408'}
42
defaultdict(<type 'list'>, {31: [28, 38, 50, 4, 43, 24, 36, 48, 34, 39, 13, 32, 46, 47, 26], 32: [28, 38, 4, 43, 39, 50, 48, 24, 36, 34, 32, 13, 46, 44, 47], 33: [38, 28, 48, 4, 50, 43, 39, 24, 34, 36, 32, 18, 46, 44, 13], 34: [38, 28, 4, 39, 43, 50, 48, 36, 24, 21, 34, 18, 32, 13, 46], 35: [28, 38, 4, 48, 43, 50, 39, 36, 24, 34, 18, 21, 32, 20, 13, 16], 36: [28, 38, 36, 4, 50, 24, 48, 43, 39, 44, 18, 34, 21, 32, 13], 37: [28, 38, 24, 39, 44, 36, 50, 43, 34, 21, 18, 4, 32, 48, 42], 38: [28, 44, 39, 24, 38, 48, 34, 43, 36, 18, 21, 50, 4, 16, 13], 39: [28, 44, 38, 39, 21, 18, 43, 4, 24, 50, 36, 34, 16, 48, 42], 40: [28, 38, 18, 36, 21, 39, 50, 43, 44, 24, 4, 48, 34, 16, 46, 49, 40], 41: [38, 28, 21, 18, 39, 50, 24, 44, 36, 4, 48, 43, 34, 11, 13], 42: [21, 38, 39, 28, 18, 36, 50, 24, 43, 44, 48, 4, 11, 13, 16], 43: [38, 21, 18, 28, 39, 36, 24, 43, 4, 50, 12, 13, 19, 11, 44], 44: [38, 39, 21, 36, 28, 18, 11, 12, 43, 50, 48, 4, 24, 19, 25], 45: [39, 38, 21, 18, 36, 24, 25, 43, 11, 12, 28, 4, 19, 50, 44], 46: [39, 21, 38, 18, 25, 24, 36, 12, 28, 19, 4, 11, 43, 13, 26], 47: [39, 21, 38, 18, 12, 36, 25, 28, 19, 24, 4, 11, 50, 43, 16], 48: [39, 38, 25, 21, 18, 28, 24, 36, 19, 12, 34, 4, 11, 26, 44], 49: [39, 25, 38, 21, 18, 28, 12, 34, 19, 24, 36, 4, 11, 31, 50], 50: [38, 25, 21, 34, 39, 18, 28, 36, 31, 12, 24, 19, 4, 11, 43, 50, 44, 26, 16, 13], 51: [25, 21, 39, 34, 38, 28, 18, 36, 19, 31, 29, 12, 24, 11, 50], 52: [25, 39, 34, 28, 21, 38, 19, 18, 12, 36, 29, 24, 31, 43, 11], 53: [39, 34, 25, 21, 38, 31, 19, 28, 36, 24, 12, 18, 50, 43, 26], 54: [39, 21, 25, 34, 38, 50, 28, 43, 36, 31, 24, 18, 19, 26, 29], 55: [21, 39, 25, 50, 38, 36, 34, 26, 24, 18, 31, 19, 28, 43, 12], 56: [39, 21, 50, 25, 38, 34, 36, 29, 24, 31, 19, 18, 26, 43, 28], 57: [21, 39, 25, 34, 50, 29, 38, 19, 24, 36, 28, 31, 18, 43, 26], 58: [21, 39, 38, 25, 50, 36, 29, 28, 24, 18, 31, 12, 19, 26, 34], 59: [39, 50, 21, 38, 31, 25, 36, 29, 34, 28, 18, 19, 12, 24, 43], 60: [50, 39, 21, 25, 38, 31, 34, 36, 29, 24, 28, 19, 18, 12, 26, 43, 33, 44, 32, 16], 61: [50, 21, 39, 38, 25, 28, 34, 29, 36, 24, 19, 18, 31, 12, 44], 62: [21, 50, 25, 19, 34, 39, 31, 28, 18, 24, 29, 38, 36, 12, 44], 63: [21, 39, 28, 38, 25, 31, 24, 50, 29, 36, 18, 19, 34, 44, 45], 64: [21, 25, 39, 38, 28, 34, 18, 31, 50, 44, 45, 19, 36, 24, 29], 65: [21, 39, 28, 25, 38, 19, 45, 31, 34, 50, 44, 18, 29, 36, 43], 66: [25, 38, 28, 45, 21, 39, 18, 31, 50, 43, 24, 34, 36, 19, 12], 67: [25, 45, 28, 38, 39, 21, 34, 31, 19, 43, 50, 24, 18, 44, 36], 68: [45, 38, 21, 28, 25, 50, 24, 19, 34, 31, 39, 43, 18, 13, 12], 69: [50, 45, 28, 24, 38, 19, 43, 13, 21, 39, 36, 34, 12, 31, 25], 70: [45, 50, 21, 28, 31, 24, 13, 39, 38, 43, 19, 12, 34, 18, 36, 27, 15, 25, 16, 29], 71: [45, 50, 28, 38, 39, 13, 24, 31, 34, 36, 12, 27, 19, 25, 21], 72: [28, 50, 21, 31, 25, 43, 12, 34, 39, 24, 36, 19, 38, 45, 13], 73: [13, 45, 25, 28, 50, 19, 36, 31, 21, 39, 24, 12, 26, 43, 34], 74: [13, 19, 45, 28, 21, 50, 38, 26, 25, 36, 39, 24, 15, 31, 30], 75: [21, 19, 13, 28, 31, 45, 25, 38, 36, 50, 26, 39, 27, 43, 30], 76: [19, 21, 28, 30, 38, 50, 31, 13, 45, 43, 39, 25, 15, 26, 36], 77: [21, 19, 28, 43, 13, 25, 30, 38, 45, 50, 39, 26, 41, 17, 31], 78: [19, 21, 50, 28, 25, 13, 12, 30, 45, 38, 39, 15, 24, 31, 43], 79: [19, 45, 38, 25, 28, 36, 31, 21, 39, 27, 13, 26, 30, 17, 50, 43, 12, 15, 24, 9], 80: [19, 31, 12, 43, 21, 36, 28, 13, 39, 38, 27, 45, 25, 30, 34, 50, 18, 15, 22, 10], 81: [19, 39, 38, 28, 21, 31, 12, 43, 27, 13, 50, 25, 36, 45, 22, 30, 24, 44, 26, 9], 82: [12, 45, 38, 21, 19, 31, 43, 28, 39, 36, 22, 25, 50, 17, 24, 13, 27, 44, 18, 9], 83: [21, 38, 31, 39, 36, 50, 19, 28, 24, 12, 22, 45, 27, 25, 43, 44, 13, 17, 18, 9], 84: [19, 50, 27, 9, 12, 45, 28, 30, 38, 36, 22, 39, 18, 24, 13, 43, 34, 31, 25, 21], 85: [36, 50, 39, 25, 27, 45, 38, 44, 9, 28, 18, 34, 19, 24, 13, 12, 26, 31, 21, 30, 78, 11, 22], 86: [36, 19, 45, 28, 34, 22, 50, 11, 39, 44, 30, 31, 27, 78, 38, 9, 24, 25, 43, 12], 87: [50, 36, 19, 31, 44, 28, 26, 39, 11, 17, 22, 45, 30, 34, 13, 27, 24, 9, 78, 38], 88: [36, 19, 44, 50, 11, 22, 21, 28, 45, 17, 18, 31, 30, 26, 13, 78, 9, 27, 39, 34], 89: [39, 36, 19, 30, 50, 21, 44, 11, 43, 27, 45, 25, 9, 17, 38, 13, 34, 78, 22, 28], 90: [36, 19, 39, 50, 11, 44, 38, 30, 26, 25, 43, 27, 31, 34, 28, 21, 17, 13, 22, 78, 24, 18, 45], 91: [11, 19, 36, 44, 50, 31, 22, 27, 45, 25, 30, 21, 38, 17, 39, 26, 13, 78, 28, 94, 95]})
61
歴代のユニークな出場校は42校のようです(※ただし、改称前後の大学は(公式ページで別のidが振られているようなので)別に数える)。
テーブルから読んだ「1時間06分49秒」のような文字列を変換したり。
(いいライブラリありそうだけども・・・)
def convert_hour(hour_in_ja):
minutes_per_hour = 60.0
seconds_per_minute = 60.0
try:
hour = int(hour_in_ja.split(u'時間')[0])
minute = int(hour_in_ja.split(u'時間')[1].split(u'分')[0])
second = int(hour_in_ja.split(u'時間')[1].split(u'分')[1].split(u'秒')[0])
except:
print 'inside except:', hour_in_ja
return float('NaN')
hour_in_num = hour + minute/minutes_per_hour + second/(minutes_per_hour*seconds_per_minute)
return hour_in_num
出場校ごとの歴代区間記録を、pandas.DataFrameのdictに格納する(単位:h)
- dict_of_dataframe
- キー:大学id、値:その大学のpandas.DataFrame
- pandas.DataFrame.
- 行:大会(第31-91回大会のうち出場回のみ)、列;10区間(1-10区)
dict_of_dataframe = {}
for a_univ_id in universities.keys():
# make data frame for each univ
df = pandas.DataFrame(df_array, index=df_index, columns=df_columns)
....
# assign df to a univ
dict_of_dataframe[a_univ_id] = df
例えば、
# 明治大学
print dict_of_dataframe[44]
1 2 3 4 5 6 7 \
32 1.280556 1.247500 1.321389 1.288056 1.772222 1.436111 1.356944
33 1.241389 1.172500 1.278889 1.241389 1.689167 1.406944 2.146944
36 1.190556 1.114167 1.371389 1.180278 1.515556 1.280833 1.136111
37 1.150556 1.313333 1.094444 1.145833 1.498611 1.265556 1.157778
38 1.139444 1.417778 1.135000 1.184444 1.479722 1.229444 1.154722
39 1.133056 1.362500 1.168889 1.096667 1.470000 1.188056 1.073889
40 1.117222 1.338611 1.129444 1.082222 1.419444 1.169167 1.142222
41 1.150278 1.333611 1.095556 1.122222 1.500278 1.178056 1.121389
42 1.109444 1.344444 1.132778 1.145556 1.453333 1.114167 1.174722
43 1.145833 1.365556 1.128333 1.648889 1.328889 1.017222 1.265278
45 1.256667 1.367778 1.303611 1.499167 1.517500 1.093889 1.183056
48 1.226667 1.473611 1.197500 1.200556 1.325556 1.087222 1.261667
50 1.160000 1.403889 1.173889 1.216111 1.417222 1.161944 1.229444
60 1.121667 1.316111 1.211667 1.204444 1.348889 1.084722 1.224444
61 1.145278 1.203889 1.190833 1.168611 1.346389 1.053611 1.207500
62 1.158056 1.244722 1.177222 1.150833 1.299444 1.135278 1.173889
63 1.094444 1.224444 1.125833 1.173333 1.296111 1.079444 1.155833
64 1.093611 1.221667 1.125556 1.152778 1.318611 1.052222 1.133889
65 1.124722 1.233056 1.129167 1.153333 1.304722 1.039167 1.150833
67 1.099722 1.148333 1.088889 1.135833 1.282778 1.134444 1.198889
81 1.070556 1.179167 1.093889 1.078611 1.267500 1.024444 1.133889
82 1.066667 1.206111 1.088611 0.952778 1.399444 1.030556 1.094167
83 1.097778 1.156667 1.095000 0.971111 1.344167 1.018056 1.120278
85 1.081389 1.163056 1.081389 0.924444 1.399167 0.993333 1.086111
86 1.040833 1.148889 1.052222 0.932500 1.454722 1.020000 1.108611
87 1.075278 1.126667 1.056389 0.946944 1.331111 1.028889 1.091111
88 1.046111 1.146389 1.068333 0.914722 1.326111 1.005278 1.069722
89 1.062778 1.195278 1.107500 0.972500 1.405556 0.971944 1.083611
90 1.033889 1.154167 1.057500 0.926667 1.428056 0.971111 1.078611
91 1.035278 1.132222 1.044722 0.916667 1.353611 0.998333 1.095833
8 9 10
32 1.347222 1.340278 1.350833
33 1.424444 1.257500 1.465556
36 1.361667 1.160833 1.299167
37 1.130833 1.319167 1.218056
38 1.139722 1.383333 1.173333
39 1.136667 1.332222 1.112500
40 1.136389 1.353889 1.141111
41 1.145556 1.322778 1.122778
42 1.156111 1.324167 1.155000
43 1.234167 1.436944 1.178889
45 1.140278 1.263889 1.221944
48 1.343056 1.547500 1.305833
50 1.321667 1.518611 1.300833
60 1.213889 1.373889 1.220556
61 1.168889 1.273611 1.151389
62 1.295833 1.277778 1.170556
63 1.155833 1.248611 1.167778
64 1.150556 1.270556 1.120833
65 1.191389 1.258889 1.137222
67 1.207778 1.233056 1.273889
81 1.129444 1.206111 1.289444
82 1.161389 1.216111 1.244722
83 1.165278 1.244722 1.252778
85 1.124167 1.231944 1.219444
86 1.139722 1.229722 1.238611
87 1.116944 1.186667 1.177500
88 1.090278 1.194167 1.186111
89 1.127222 1.258056 1.236111
90 1.089167 1.192778 1.237222
91 1.120556 1.149444 1.185833
歴代の区間距離を得る(単位:km)
- 「箱根駅伝 距離の変遷」より手動でpandas.DataFrameを作成
- pandas.DataFrame. 行:61大会(第31-91回大会)、列:10区間(1-10区)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy
import pandas
df_array = numpy.array([
[22.3, 21.2, 22.1, 21.0, 25.1, 25.1, 21.0, 22.1, 21.2, 22.3],
[22.3, 21.2, 22.1, 21.0, 25.1, 25.1, 21.0, 22.1, 21.2, 22.3],
[22.3, 21.2, 22.1, 21.0, 25.1, 25.1, 21.0, 22.1, 21.2, 22.3],
[22.3, 21.2, 22.1, 21.0, 25.1, 25.1, 21.0, 22.1, 21.2, 22.3],
[22.3, 21.2, 22.1, 21.0, 25.1, 25.1, 21.0, 22.1, 21.2, 22.3],
[22.3, 20.5, 24.7, 20.1, 25.1, 25.1, 20.1, 24.7, 20.5, 22.3],
[22.7, 23.7, 24.7, 20.1, 25.1, 25.1, 20.1, 24.7, 23.7, 22.7],
[22.7, 23.7, 19.9, 20.7, 25.1, 25.1, 20.7, 19.9, 23.7, 22.7],
[22.7, 23.7, 21.4, 19.4, 25.1, 25.1, 19.4, 21.4, 23.7, 22.7],
[22.7, 23.7, 21.4, 20.4, 24.7, 24.7, 20.2, 21.4, 23.7, 22.7],
[22.7, 23.7, 21.4, 20.4, 24.7, 24.7, 20.2, 21.4, 23.7, 22.7],
[22.7, 23.7, 21.4, 21.4, 23.7, 23.7, 21.2, 21.4, 23.7, 22.7],
[22.7, 23.7, 21.4, 21.4, 21.9, 21.9, 21.2, 21.4, 23.7, 22.7],
[22.7, 23.7, 21.4, 21.4, 21.9, 21.9, 21.2, 21.4, 23.7, 22.7],
[21.7, 24.7, 20.2, 23.2, 21.9, 21.9, 23.0, 20.2, 24.7, 21.7],
[21.6, 24.7, 21.5, 23.2, 22.0, 22.0, 21.7, 21.5, 24.7, 21.6],
[21.6, 24.7, 21.5, 23.2, 22.0, 22.0, 21.7, 21.5, 24.7, 21.6],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 25.2, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 25.2, 21.8],
[21.8, 24.4, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.9, 21.4, 21.4, 21.9, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.0, 20.5, 21.4, 21.9, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.0, 20.5, 20.5, 21.3, 22.2, 24.4, 21.8],
[21.8, 24.4, 22.2, 21.0, 20.5, 20.5, 21.3, 22.2, 24.4, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.8],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.8, 22.7, 22.2, 21.0, 20.6, 20.6, 21.3, 22.2, 22.7, 21.3],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 20.9, 20.7, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.3, 23.0, 21.3, 21.0, 20.9, 20.7, 21.2, 21.3, 23.0, 23.0],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.4, 23.2, 21.5, 21.0, 23.4, 20.7, 21.2, 21.5, 23.2, 23.1],
[21.3, 23.1, 21.4, 18.5, 23.2, 20.8, 21.3, 21.4, 23.1, 23.0]
])
#print df_array
def load_distance_df():
df_index = numpy.arange(31,92)
df_columns = numpy.arange(1,11)
df = pandas.DataFrame(df_array, index=df_index, columns=df_columns)
return df
要素ごとに区間距離/時速を計算し、max()関数を適用して、出場校ごとに各区間の歴代最高時速を得る(単位:km/h)
- pandas.Series. 行:10区間(1-10区)
- pandas.DataFrame同士の割り算が便利
- 記録が存在しない要素はNaN (Not a Number)として扱う
- 距離/時間の結果が無限大(inf)になる要素は、NaNに変換する
- 列(=区間)ごとの最大値を取る際に、NaNを無視できる
df_distance = load_distance.load_distance_df()
for univ in dict_of_dataframe:
# replace inf and -inf
dict_of_dataframe_velocity[univ] = (df_distance / dict_of_dataframe[univ] ).replace([numpy.inf, -numpy.inf], numpy.nan)
後処理はともかく、基本的には
df_distance / dict_of_dataframe[univ]
の1行で、大学ごとに全ての大会の区間距離/所要時間を計算できるのが便利ですね。
########
# 第92回
# km/(km/h) = h
########
# 第92回大会 区間ごとの距離(km)
distance_92th = numpy.array([21.3, 23.1, 21.4, 18.5, 23.2, 20.8, 21.3, 21.4, 23.1, 23.0])
series_dist = pandas.Series(distance_92th, index = numpy.arange(1,11))
########
# km/h
########
hour_ranking = {}
for univ in universities:
max_velocity_for_each_section = dict_of_dataframe_velocity[univ].max()
# 大学
print '大学名: ', universities[univ], 'id: ', univ
print '最高時速(km/h): ', max_velocity_for_each_section
print '区間ごとの最短所要時間(h): ', series_dist / max_velocity_for_each_section
print '総合所要時間(h): ', sum(series_dist / max_velocity_for_each_section)
print
# add data
hour_ranking[univ] = sum(series_dist / max_velocity_for_each_section)
printの結果を一部抜粋すると・・・
大学名: 関東学連選抜 id: 9
最高時速(km/h): 1 20.380952
2 20.222760
3 20.145757
4 22.540250
5 17.379823
6 20.891505
7 19.624582
8 19.383922
9 19.473071
10 19.562456
dtype: float64
区間ごとの最短所要時間(h): 1 1.045093
2 1.142277
3 1.062258
4 0.820754
5 1.334881
6 0.995620
7 1.085373
8 1.104008
9 1.186254
10 1.175722
dtype: float64
総合所要時間(h): 10.9522406546
総合所要時間で競う
出場校ごとに、各区間の歴代最高時速を用いて
第92回大会(2016年)のコースを走らせ、総合所要時間を比較する。
for k, v in sorted(hour_ranking.items(), key=lambda x:x[1]):
print '大学名: ', universities[k], '総合所要時間(h): ', v
結果
大学名: 日本大学 総合所要時間(h): 10.2453132331
大学名: 中央大学 総合所要時間(h): 10.3591586209
大学名: 日本体育大学 総合所要時間(h): 10.3759579539
大学名: 早稲田大学 総合所要時間(h): 10.3766071561
大学名: 順天堂大学 総合所要時間(h): 10.4208490227
大学名: 専修大学 総合所要時間(h): 10.4760277397
大学名: 東洋大学 総合所要時間(h): 10.4816180955
大学名: 国士舘大学 総合所要時間(h): 10.5138632405
大学名: 明治大学 総合所要時間(h): 10.5169890222
大学名: 法政大学 総合所要時間(h): 10.6055941866
大学名: 東京農業大学 総合所要時間(h): 10.6470086075
大学名: 大東文化大学 総合所要時間(h): 10.6603316782
大学名: 駒澤大学 総合所要時間(h): 10.6967026896
大学名: 山梨学院大学 総合所要時間(h): 10.7075345827
大学名: 東海大学 総合所要時間(h): 10.7491609299
大学名: 神奈川大学 総合所要時間(h): 10.8168044546
大学名: 中央学院大学 総合所要時間(h): 10.8412400185
大学名: 亜細亜大学 総合所要時間(h): 10.85684661
大学名: 城西大学 総合所要時間(h): 10.8746325761
大学名: 帝京大学 総合所要時間(h): 10.9042462208
大学名: 拓殖大学 総合所要時間(h): 10.9080803745
大学名: 國學院大学 総合所要時間(h): 10.90929883
大学名: 青山学院大学 総合所要時間(h): 10.9442540793
大学名: 関東学連選抜 総合所要時間(h): 10.9522406546
大学名: 筑波大学 総合所要時間(h): 10.9629683463
大学名: 上武大学 総合所要時間(h): 11.069379971
大学名: 東京教育大学 総合所要時間(h): 11.1392697521
大学名: 立教大学 総合所要時間(h): 11.2065269496
大学名: 関東学院大学 総合所要時間(h): 11.2972643755
大学名: 関東学生連合 総合所要時間(h): 11.32
大学名: 日本学連選抜 総合所要時間(h): 11.3482872531
大学名: 慶応義塾大学 総合所要時間(h): 11.5006612565
大学名: 創価大学 総合所要時間(h): 11.5277777778
大学名: 平成国際大学 総合所要時間(h): 11.6349612092
大学名: 立命館大学 総合所要時間(h): 11.7104078624
大学名: 福岡大学 総合所要時間(h): 11.7658274859
大学名: 東京学芸大学 総合所要時間(h): 11.8272461166
大学名: 東京大学 総合所要時間(h): 12.1214438077
大学名: 横浜市立大学 総合所要時間(h): 12.4901800886
大学名: 防衛大学 総合所要時間(h): 12.542251172
大学名: 埼玉大学 総合所要時間(h): 13.028733025
大学名: 横浜国立大学 総合所要時間(h): 13.1778038298
- 日大でしたか1位
- 青学が真ん中らへん?
もっとも、次に述べるような問題点もあるので、あまり積極的に考察する気になれないですが・・・。
TODOという名の言い訳ないしは問題点
- htmlの文字化けにより、pandasに読み込めなかったデータも一定数ある
- CP51932でエンコードされたhtmlが一部
- データ不足?
- 第83回大会、関東学連選抜の記録は、6区の川内(あの有名な市民ランナー!)のみ
注意
- この記事は、歴代出場校の名誉を操作する意図をもって書かれたものではありません。
- 【問題点】で指摘したような不具合が存在するので、得られた結果はあくまで参考とお考えください。
リンク
- 箱根駅伝公式Webサイト
- 箱根駅伝 距離の変遷
- 歴代の全区間距離が記録として残っている、第31回大会以降を対象とする
- 文字コード問題
脚注
-
大会ごとに区間距離が変わっているので、比較のため。 ↩