ブンデスリーガ勝敗予測 – LinearSVM

2022年2月12日

目的

ドイツ プロサッカーリーグのブンデスリーガの勝敗予測を行ってみる。

データはFootball-Data.co.ukのデータを利用する。
http://www.football-data.co.uk/germanym.php

各チームの勝敗予測を分類タスクととらえてSVMを利用して解く。

SVM(サポートベクターマシン)

Scikitlearnのチートシートに従って、LinearSVMを使ってみる。
https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html

LinearSVMはSVM(サポートベクターマシン)の一種である。
SVMについてはWikipediaからの引用させていただく。

サポートベクターマシンは、線形入力素子を利用して 2 クラスのパターン識別器を構成する手法である。

wikipedia

コードは次のとおり。

from sklearn.svm import LinearSVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# ブンデスリーガデータ読み込み
df = data_catalog.load('match_result')

# チーム名をダミー変数に変換
df_cat = None
for col in ['HomeTeam', 'AwayTeam']:
    tmp = pd.get_dummies(df[col], prefix=col)
    df_cat = pd.concat([df_cat, tmp], axis=1)
cat_col = df_cat.columns
df = pd.concat([df, df_cat], axis=1)

# 勝ち・負け・引き分けをコード値に変換
df['game_result'] = df['game_result'].astype('category')
df['game_result_cd'] = df['game_result'].cat.codes
display(dict(enumerate(df['game_result'].cat.categories)))

df_train, df_test = train_test_split(df, test_size=0.1, random_state=42)

X = df_train[cat_col]
y = df_train['game_result_cd']
X_test = df_test[cat_col]
y_test = df_test['game_result_cd']

clf = LinearSVC(random_state=0, tol=1e-5, max_iter=10000)
clf.fit(X, y)

print(f"accuracy: {accuracy_score( y_test, clf.predict(X_test))}")
"""accuracy: 0.4980392156862745"""

評価指標として、正解率 (Accuracy)を出してみたが、0.50であった。
これはランダムに勝敗予測するのと同じ結果になっている。

パラメタ最適化

LinearSVMには正則化パラメタ C がある。
これをグリッドサーチで最適化することで正解率が上がらないか試してみる。

from sklearn.model_selection import GridSearchCV

# ブンデスリーガデータ読み込み
df = data_catalog.load('match_result')

# チーム名をダミー変数に変換
df_cat = None
for col in ['HomeTeam', 'AwayTeam']:
    tmp = pd.get_dummies(df[col], prefix=col)
    df_cat = pd.concat([df_cat, tmp], axis=1)
cat_col = df_cat.columns
df = pd.concat([df, df_cat], axis=1)

# 勝ち・負け・引き分けをコード値に変換
df['game_result'] = df['game_result'].astype('category')
df['game_result_cd'] = df['game_result'].cat.codes
display(dict(enumerate(df['game_result'].cat.categories)))

df_train, df_test = train_test_split(df, test_size=0.1, random_state=42)

X = df_train[cat_col]
y = df_train['game_result_cd']
X_test = df_test[cat_col]
y_test = df_test['game_result_cd']

tuned_parameters = [{'C': [1e-2, 1e-1, 1, 10, 100, 1000]}]

clf = GridSearchCV(LinearSVC(random_state=0, tol=1e-5, max_iter=10000),
                   tuned_parameters,
                   cv=5,
                   scoring='accuracy')
clf.fit(X, y)

print(clf.best_params_)
"""{'C': 0.1}"""
print(clf.best_score_)
"""0.4951343500363108"""

print(f"accuracy: {accuracy_score(y_test, clf.predict(X_test))}")
"""accuracy: 0.5032679738562091"""

C を最適化してみたが、正解率は0.50より大きくならなかった。

考察

今回ブンデスリーガの試合結果予測をLinearSVMで試してみたが良い結果は得られなかった。

原因としては

  • 特徴量がホーム・アウェイチーム名だけと少なかったこと
  • LinearSVMが今回のタスクに適していなかった

が考えられる。

Scikitlearnのチートシートに従って、次はK近傍法を使っての分類を試してみる。