機械学習で競馬予想 其の012 ~リファクタリング~
僕は、pythonの素人で、行き当たりばったりなコーディングをしているため、ソースが冗長で汚くなってきたので、このタイミングでリファクタリングしようと思います。機械学習で競馬予想という本筋から逸れてしまいますが、(筆者の)今後のためにも仕方ありません。pythonに詳しい方であれば本エントリは無視した方が良いでしょう。基本的には冗長な部分の排除とよりpythonらしいと思われる記述にしていきます。
手始めに、プロパティ的なものをハードコーディングしていたのでプロパティファイルへ外だし。
pythonではConfigParserを使うと良いらしいので以下のように実装。
- ConfigParser.SafeConfigParserでプロパティファイル読込用にインスタンスを生成
- readでプロパティファイルの読み込み
プロパティファイルの内容を取得するには、getを使う。
これだけ。
import ConfigParser # 環境設定ファイル読込処理 envFile = ConfigParser.SafeConfigParser() envFile.read(r'config.ini') horse_data_file_path = envFile.get('horse_data', 'file_path')
プロパティファイルにはカテゴリというのを設定できる。具体的な記述は以下のとおり。
[horse_data] file_path=.\horse
次に、元々、genfromtxtで馬のデータを取得したものに対して、dataShapingという関数で、不要データを削除や、データの形式を整形部分をgenfromtxtの呼び出し部分に記述。
実装は以下のような感じ。convertersで単にファイルから取得した値を返却するだけだったのを元々dataShaping関数で実装していた整形モジュール呼び出しと連動させただけ。
# 馬データの読み込み def loadHorseData(filename): horsedata = sp.genfromtxt(os.path.join(horse_data_file_path, filename), delimiter="\t", dtype=[ ('日付','S10'), # 0:日付 ('開催地','i3'), # 1:開催地 ('レース','i2'), # 2:レース ('レース名','U50'), # 3:レース名 ('距離','i4'), # 4:距離 ('天候','i3'), # 5:天候 ('馬番','i2'), # 6:馬番 ('人気','i3'), # 7:人気 ('着順','U10'), # 8:着順 ('タイム','f5'), # 9:タイム ('差/事故', 'i4'), # 10:差/事故 ('上3F','i4'), # 11:上3F ('通過順','U10'), # 12:通過順 ('体重','i4'), # 13:体重 ('騎手','U20'), # 14:騎手 ('負担重量','i4'), # 15:負担重量 ('調教師','U20'), # 16:調教師 ('獲得賞金(円)','U10') # 17:獲得賞金 ], converters={ 0 : lambda s: convertDate(s.decode('utf8')), # 開催日 1 : lambda s: createLocationDict(s.decode('utf8')), # 開催地 3 : lambda s: s.decode('utf8'), # レース名 5 : lambda s: createWeatherDict(s.decode('utf8')), # 天候 9 : lambda s: convertTime(s.decode('utf8')), # タイム 14 : lambda s: s.decode('utf8'), # 騎手 16: lambda s: s.decode('utf8'), # 調教師 }) return np.array(horsedata.tolist(), dtype = object)
それぞれのデータ整形に使っている処理は以下のとおり。以前は、大井競馬場のデータだけを使っていたけど、今回はすべての開催地のデータを使うようについでに修正。
def addZero(data): if len(data) == 2: return data else: return "0" + str(data) def convertDate(date): aryYmd = date.split("/") year = addZero(aryYmd[0]) month = addZero(aryYmd[1]) day = addZero(aryYmd[2]) return str(year) + str(month) + str(day) def convertTime(time): if len(time.split(":")) == 2: return np.float32(time.split(":")[0])*60+np.float32(time.split(":")[1]) else: return np.float32(time) def createWeatherDict(weather): global weatherDict global weatherIndex if weatherDict.has_key(weather) == False: weatherIndex += 1 weatherDict[weather] = weatherIndex return weatherIndex def createLocationDict(location): global locationDict global locationIndex if locationDict.has_key(location) == False: locationIndex += 1 locationDict[location] = locationIndex return locationDict[location]
そうすると、結果が微妙に変わった。この辺の評価は後日にするとして次回もリファクタリングを進めます。
8R 1200m | 新 | 旧 | 実績 |
---|---|---|---|
馬番 | タイム(秒) | タイム(秒) | タイム(秒) |
1 | 80.4909487166 | 74.2050783599 | 75.1 |
2 | 74.955080275 | 74.5661372198 | 76.6 |
3 | 73.6787991346 | 74.1367306308 | 74.1 |
4 | 76.1923007581 | 72.3405306744 | 75.0 |
5 | 77.984841449 | 81.7183619077 | 77.2 |
6 | 74.878874984 | 73.5652206548 | 76.2 |
7 | 76.8652917749 | 80.5876352042 | 78.0 |
8 | 76.739123412 | 73.8367610183 | 75.0 |
9 | 74.2465295977 | 75.2493784691 | 75.1 |
10 | 81.3600303209 | 81.3099440104 | 76.4 |
11 | 75.9533880198 | 76.1685987163 | 76.6 |
12 | 74.1004315609 | 73.9210259265 | 74.5 |
13 | 75.9515585476 | 76.2881028763 | 78.7 |
9R 1600m | 新 | 旧 | 実績 |
---|---|---|---|
馬番 | タイム(秒) | タイム(秒) | タイム(秒) |
1 | 104.009553751 | 105.449829127 | 106.3 |
2 | 105.285454948 | 104.446635423 | 105.1 |
3 | 104.170221199 | 103.544665086 | 104.8 |
4 | 103.561907896 | 102.832908331 | 104.8 |
5 | 105.803250689 | 106.681494384 | 107.0 |
6 | 104.753017942 | 104.852490486 | 105.5 |
7 | 103.855474193 | 104.096728343 | 104.1 |
8 | 103.621835287 | 101.063900125 | 104.9 |
9 | 105.521398972 | 105.44998775 | 106.9 |
10 | 105.96640969 | 106.27426342 | 106.2 |
11 | 102.40205078 | 102.557512398 | 106.3 |
12 | 104.211524406 | 104.923401093 | 105.8 |
13 | 104.522090684 | 103.621225058 | 107.0 |
14 | 106.726775191 | 103.160208763 | 104.3 |
10R 1200m | 新 | 旧 | 実績 |
---|---|---|---|
馬番 | タイム(秒) | タイム(秒) | タイム(秒) |
1 | 73.9448633203 | 74.053751696 | 74.7 |
2 | 74.4725932805 | 74.791709691 | 75.6 |
3 | 76.4310043125 | 74.9716748455 | 75.5 |
4 | 77.8331423393 | 91.0018906849 | 78.3 |
5 | 80.8977378491 | 79.8907980544 | 75.4 |
6 | 69.0830010014 | 68.6452500517 | 75.1 |
7 | 76.5005151764 | 75.2536390704 | 75.8 |
8 | 74.3322163529 | 74.4513043382 | 74.7 |
9 | 74.6606315693 | 53.7728385949 | 76.4 |
10 | 75.0673609574 | 74.9747204476 | 75.1 |
11 | 73.237177527 | 73.2287457443 | 76.5 |
12 | 82.8226314627 | 85.7890644837 | 75.7 |
13 | 73.5605822215 | 75.1488630555 | 74.5 |
11R 1600m | 新 | 旧 | 実績 |
---|---|---|---|
馬番 | タイム(秒) | タイム(秒) | タイム(秒) |
1 | 101.298091317 | 101.639022812 | 102.3 |
2 | 101.843065646 | 104.904044778 | 103.2 |
3 | 103.375501518 | 102.832548994 | 102.6 |
4 | 106.789608436 | 104.198294174 | 101.0 |
5 | 101.40716234 | 100.890777032 | 105.3 |
6 | 101.866305864 | 101.794480623 | 103.2 |
7 | 100.723857238 | 103.042734984 | 102.3 |
8 | 102.829131723 | 102.415056316 | 103.9 |
9 | 102.544875956 | 101.758714813 | 106.6 |
12R 1800m | 新 | 旧 | 実績 |
---|---|---|---|
馬番 | タイム(秒) | タイム(秒) | タイム(秒) |
1 | 114.444510794 | 117.24558277 | 117.1 |
2 | 118.470400983 | 119.808649496 | 118.5 |
3 | 117.646829198 | 115.77679082 | 116.3 |
4 | 115.078354065 | 114.421506359 | 117.1 |
5 | 116.195286215 | 91.7595650662 | 117.7 |
6 | 116.622796412 | 115.25449028 | 118.5 |
7 | 118.748983122 | 119.789764968 | 118.4 |
8 | 121.098679561 | 107.532586121 | 121.1 |
9 | 117.614868291 | 120.763363564 | 120.0 |
10 | 115.438044791 | 109.776689962 | 117.7 |
11 | 114.906238595 | 115.068710391 | 116.5 |
12 | 116.709747135 | 111.356021988 | 117.6 |
13 | 116.006504665 | 116.470179101 | 116.7 |