“人工智能战胜足球专家”-这可能是本文有关足球比赛结果的标题。 可以,但是,可惜没有。
世界杯期间,我们的“
NORBIT ”公司举办了一场足球最佳预测比赛。 我对足球一无所知,但对参加比赛的渴望仍然赢得了我的懒惰。 删减了-一个有关如何借助机器学习使我在橄榄球队专家中取得良好成绩的故事。 没错,我没能中奖,但是我发现了一个崭新的数据科学世界。
我从一个假设开始,即除了国家队队员的个人技能外,还有不可估量但很重要的因素-团队精神+团队合作精神(例如,一支在比赛中拥有更强对手的球队,但在测试赛中和在自己的领域中更经常获胜)。 对于一个人而言,这项任务并不是那么简单,但是对于机器学习而言却是可以理解的。
我曾经对使用ML(使用BrainJS库)有一点经验,但是这次我决定检查一下Python更适合于此类任务的说法。
我从
Coursera的一门优秀课程开始了对Python的介绍,并且从
Habré上Open Data Science的一系列文章中学到了机器学习的基础知识。
从二十世纪初开始,很快就发现了一个出色的
数据集 ,其中包含国际队所有比赛的历史。 导入Pandas数据框后:
该数据库总共包含有关39 000场国际队比赛的信息。
熊猫使分析数据变得非常方便,例如,最有成效的比赛是2001年在澳大利亚和萨摩亚之间进行的,最终比分是
31:0 。
现在,您需要在比赛当年添加对团队水平的客观评估。 这些评估由FIFA处理。
但是,不幸的是,国际足联自1992年以来才进行评级。 而且,从时间表来看,球队的排名很容易发生变化,我真的不希望在今年之前对世界排名中球队的排名进行平均。
UEFA保留了更古老的统计数据,但是我找不到可用的数据集,因此该
站点进行了抢救。 在Node.js下,有一个功能强大且方便的
Cheerio可以执行这些任务,但是在Python下,一切都变得相当简单(请原谅该站点的管理员)。
网站抓取排名from requests import get from requests.exceptions import RequestException from contextlib import closing from bs4 import BeautifulSoup def query_url(url): try: with closing(get(url, stream=True)) as resp: if is_good_response(resp): return resp.content else: return None except RequestException as e: log_error('Error during requests to {0} : {1}'.format(url, str(e))) return None def is_good_response(resp): content_type = resp.headers['Content-Type'].lower() return (resp.status_code == 200 and content_type is not None and content_type.find('html') > -1) def log_error(e): print(e) def parse_ranks(raw_html, year): html = BeautifulSoup(raw_html, 'html.parser') ranks = [] for tr in html.select('tr'): tds = tr.select("td") if len(tds) == 10: rank = (year, tds[2].text, tds[7].text) ranks.append(rank) return ranks def get_url(year): if year in range(1960, 1999): method = 1 if year in range(1999, 2004): method = 2 if year in range(2004, 2009): method = 3 if year in range(2009, 2018): method = 4 if year in range(2018, 2019): method = 5 return f"https://kassiesa.home.xs4all.nl/bert/uefa/data/method{method}/crank{year}.html" ranks = [] for year in range(1960, 2019): url = get_url(year) print(url) raw_html = query_url(url) rank = parse_ranks(raw_html, year) ranks += rank with open('team_ranks.csv', 'w') as f: writer = csv.writer(f , lineterminator='\n') writer.writerow(['year', 'country', 'rank']) for rank in ranks: writer.writerow(rank)
添加UEFA评分后评分的波动(以及根据地缘政治cast测的结果对国家名称进行的小幅修改):
但即使在这里,也没有放弃一桶焦油-UEFA仅将欧洲球队排名(使用它们之前,您有时需要考虑一下常用缩写中隐藏的内容)。 幸运的是,季后赛几乎发展成了“欧洲人”。
将结果分成单独的游戏并向表中添加评分仍然更加方便。
最有趣的部分是模型训练。 Google立即提出了最简单,最快的选择-这是Python库Sklearn中的MLPClassifier。 让我们尝试以瑞典为例训练模型。
from sklearn.neural_network import MLPClassifier games = pd.read_csv('games.csv')
准确度:0.62没有比抛硬币更准确的信息,但可能已经比我潜在的“专家”预测更好。 尝试丰富数据,使用超参数是合理的,但我决定采用另一种方法,尝试使用
Boost的Yandex梯度
Catboost库。 一方面,这更加爱国,另一方面,他们承诺具有分类属性的高质量作品,如无数次
比较所证明的那样。
从
示例中获取设置:
准确度:0.73已经更好了,请尝试实践。
def get_prediction(country, against): y = SwdenGames['score'] y = y.astype('int') X = SwdenGames.drop(['score', 'againstTitle'], axis=1) train_pool = Pool(X, y, cat_features=[1, 2, 4]) query = [ get_team_rank(country, 2018), 0, 1 if country == 'Russia' else 0, get_team_rank(against, 2018), against] return cb_model.predict_proba([query])[0] team_1 = 'Belgium' team_2 = 'France' result = get_prediction(team_1, team_2) if result[0] > result[1]: print(f" {team_1} {team_2} {result[0]*100:.1f}%") else: print(f" {team_1} {team_2} {result[1]*100:.1f}%")
决赛“科蒂亚队以93.7%的概率输给法国队”的预测结果
尽管这次我没有赢得
NORBIT竞赛,但我确实希望本文能够降低实际使用机器学习的人的魔力,甚至可以激励我进行自己的实验。