التنبؤ بنتائج كرة القدم

نموذج للتعلم الآلي في بيثون يستخدم مكتبة Scikit-learn للتنبؤ بنتائج مباريات كرة القدم في الدوري الروسي الممتاز (RPL).

دخول


استلهمت من كتابة هذا المقال من خلال مقالة " التعلم الآلي": التنبؤ برياضيات اللغة الإنجليزية لعام 2018 . سيتدرب نموذج التعلم الآلي لدينا على إحصائيات مباريات الدوري الروسي الممتاز (RPL) بدءًا من موسم 2015/2016 للتنبؤ بنتائج الألعاب القادمة. البيانات مأخوذة من موقع wyscout.com لإحصائيات كرة القدم.
رمز والبيانات المتاحة على جيثب .

معطيات


نحن نربط المكتبات الضرورية:

import pandas as pd import numpy as np import collections 

بيانات المطابقة على جيثب .

 data = pd.read_csv("RPL.csv", encoding = 'cp1251', delimiter=';') data.head() 

صورة
ماذا يعني xG و PPDA؟
xG (الأهداف المتوقعة) هي نموذج للأهداف المتوقعة. يعتمد ذلك على مؤشر الطلقات على الهدف ، والتي يمكننا على أساسها تقدير عدد الأهداف التي كان على الفريق تسجيلها إذا أخذنا في الاعتبار جميع اللقطات التي قدمها. تعلم المزيد عن xG.
PPDA (التمريرات المسموح بها لكل عمل دفاعي) هو مؤشر إحصائيات كرة القدم الذي يسمح لك بتحديد شدة الضغط في المباراة. كلما انخفضت قيمة PPDA ، زادت كثافة اللعبة في الدفاع. تعرف على المزيد حول PPDA
PPDA = عدد التصاريح التي قام بها الفريق المهاجم / عدد الإجراءات الدفاعية


سنتوقع نتائج المباريات للجزء الثاني من موسم 2018/2019 (أي المباريات التي لعبت في 2019). قائمة الفرق التي تلعب هذا الموسم (مع عدم مراعاة آرسنال ، أورينبورغ ، ودينامو ، وكريليا سوفيتوف ، وينيسي ، إما أنهم لا يملكون إحصائيات عن المواسم الماضية ، أو أن هناك إحصاءات قليلة عنهم):

 RPL_2018_2019 = pd.read_csv('Team Name 2018 2019.csv', encoding = 'cp1251') teamList = RPL_2018_2019['Team Name'].tolist() teamList 

صورة

نزيل المباريات مع الفرق التي لا تشارك في موسم 2018/2019:

 deleteTeam = [x for x in pd.unique(data['']) if x not in teamList] for name in deleteTeam: data = data[data[''] != name] data = data[data[''] != name] data = data.reset_index(drop=True) 

الوظيفة التي ترجع إحصائيات الفريق لموسم واحد:

 def GetSeasonTeamStat(team, season): goalScored = 0 #  goalAllowed = 0 #  gameWin = 0 # gameDraw = 0 # gameLost = 0 # totalScore = 0 #   matches = 0 #   xG = 0 #  shot = 0 # shotOnTarget = 0 #   cross = 0 # accurateCross = 0 #  totalHandle = 0 #  averageHandle = 0 #     Pass = 0 # accuratePass = 0 #  PPDA = 0 #    for i in range(len(data)): if (((data[''][i] == season) and (data[''][i] == team) and (data[''][i] == 2)) or ((data[''][i] == season-1) and (data[''][i] == team) and (data[''][i] == 1))): matches += 1 goalScored += data[''][i] goalAllowed += data[''][i] if (data[''][i] > data[''][i]): totalScore += 3 gameWin += 1 elif (data[''][i] < data[''][i]): gameLost +=1 else: totalScore += 1 gameDraw += 1 xG += data['xG'][i] shot += data[''][i] shotOnTarget += data['  '][i] Pass += data[''][i] accuratePass += data[' '][i] totalHandle += data[''][i] cross += data[''][i] accurateCross += data[' '][i] PPDA += data['PPDA'][i] averageHandle = round(totalHandle/matches, 3) #      return [gameWin, gameDraw, gameLost, goalScored, goalAllowed, totalScore, round(xG, 3), round(PPDA, 3), shot, shotOnTarget, Pass, accuratePass, cross, accurateCross, round(averageHandle, 3)] 

مثال على استخدام الوظيفة:

 GetSeasonTeamStat("", 2018) #    2017/2018 

صورة

للراحة ، يمكننا إضافة الرمز:

 returnNames = ["", "", "", "\n ", " ", "\n ", "\nxG ( )", "PPDA ( )", "\n", "  ", "\n", " ", "\n", " ", "\n (   )"] for i, n in zip(returnNames, GetSeasonTeamStat("", 2018)): print(i, n) 

صورة

لماذا تختلف إحصائياتنا عن الإحصاءات الحقيقية؟
إحصائيات حقيقية عن سبارتاك في موسم 2017/2018:

صورة

الإحصاءات مختلفة بسبب لقد أخذنا في الاعتبار مباريات الفرق التي لا تلعب في الدوري الممتاز في موسم 2018 2019. أي أننا لا نأخذ في الاعتبار مباريات Spartak - SKA ، Spartak - Tosno ، إلخ.

الوظيفة التي ستعيد إحصائيات جميع الفرق لهذا الموسم:

 def GetSeasonAllTeamStat(season): annual = collections.defaultdict(list) for team in teamList: team_vector = GetSeasonTeamStat(team, season) annual[team] = team_vector return annual 

التدريب النموذجي


سنكتب وظيفة ستعيد بيانات التدريب. انها تخلق قاموس مع ناقلات فريق لجميع الفصول. لكل لعبة ، تقوم الدالة بحساب الفرق بين متجهات الفرق لموسم معين وتكتبها إلى xTrain. تقوم الوظيفة بعد ذلك بتعيين yTrain على 1 في حالة فوز الفريق المضيف و 0 خلاف ذلك.

 def GetTrainingData(seasons): totalNumGames = 0 for season in seasons: annual = data[data[''] == season] totalNumGames += len(annual.index) numFeatures = len(GetSeasonTeamStat('', 2016)) #     xTrain = np.zeros(( totalNumGames, numFeatures)) yTrain = np.zeros(( totalNumGames )) indexCounter = 0 for season in seasons: team_vectors = GetSeasonAllTeamStat(season) annual = data[data[''] == season] numGamesInYear = len(annual.index) xTrainAnnual = np.zeros(( numGamesInYear, numFeatures)) yTrainAnnual = np.zeros(( numGamesInYear )) counter = 0 for index, row in annual.iterrows(): team = row[''] t_vector = team_vectors[team] rivals = row[''] r_vector = team_vectors[rivals] diff = [a - b for a, b in zip(t_vector, r_vector)] if len(diff) != 0: xTrainAnnual[counter] = diff if team == row['']: yTrainAnnual[counter] = 1 else: yTrainAnnual[counter] = 0 counter += 1 xTrain[indexCounter:numGamesInYear+indexCounter] = xTrainAnnual yTrain[indexCounter:numGamesInYear+indexCounter] = yTrainAnnual indexCounter += numGamesInYear return xTrain, yTrain 

نتعلم بيانات التدريب لجميع الفصول من 2015/2016 إلى 2018/2019.

 years = range(2016,2019) xTrain, yTrain = GetTrainingData(years) 

للتنبؤ باحتمال الفوز ، سوف نستخدم خوارزمية التعلم الآلي LinearRegression من مكتبة Scikit-Learn.

 from sklearn.linear_model import LinearRegression model = LinearRegression() model.fit(xTrain, yTrain) 

سنكتب وظيفة ستعود بالتوقعات. ستقوم بإرجاع قيمة بين 0 و 1 ، حيث 0 هي الخسارة و 1 هي الربح.

 def createGamePrediction(team1_vector, team2_vector): diff = [[a - b for a, b in zip(team1_vector, team2_vector)]] predictions = model.predict(diff) return predictions 

النتائج


على سبيل المثال ، دعونا نلقي نظرة على توقعات الخوارزمية لمباراة Zenit - Spartak

 team1_name = "" team2_name = "" team1_vector = GetSeasonTeamStat(team1_name, 2019) team2_vector = GetSeasonTeamStat(team2_name, 2019) print (',   ' + team1_name + ':', createGamePrediction(team1_vector, team2_vector)) print (',   ' + team2_name + ':', createGamePrediction(team2_vector, team1_vector)) 

صورة

اتضح أنه في مباراة زينيت - سبارتاك ، فإن احتمال فوز زينيت هو 47 ٪ (03/17/2019 سبارتاك 1-1 زينيت).

أقترح إجراء تنبؤ في ضوء ما يلي:
ما يصل إلى 40 ٪ - الفريق لن يفوز (الخسارة أو التعادل)
من 40 ٪ إلى 60 ٪ - احتمال كبير من التعادل
من 60٪ - بالتأكيد لن يخسر الفريق (الفوز أو السحب)

اشتقاق التوقعات لـ CSKA ضد جميع الأندية الأخرى

 for team_name in teamList: team1_name = "" team2_name = team_name if(team1_name != team2_name): team1_vector = GetSeasonTeamStat(team1_name, 2019) team2_vector = GetSeasonTeamStat(team2_name, 2019) print(team1_name, createGamePrediction(team1_vector, team2_vector), " - ", team2_name, createGamePrediction(team2_vector, team1_vector,)) 

صورة

أعطت الخوارزمية تنبؤًا صحيحًا تقريبًا لجميع المباريات التي لم تنتهي بالتعادل. التوقعات غير الدقيقة الوحيدة: سسكا موسكو - زينيت. احتمال فوز سسكا أعلى بنسبة 0.001 ، يمكن افتراض أن الفرق متساوية في القوة وستلعب في تعادل ، ولكن في النهاية فاز زينيت (3-1).

استنتاج


خوارزمية لدينا بدائية للغاية. يأخذ في الاعتبار فقط إحصائيات المباريات (ثم فقط 15 معلمة أساسية) ، والنتيجة في كرة القدم تعتمد على العديد من العوامل. حتى حالة الحقل أو الطقس يمكن أن تؤثر على نتيجة اللعبة.

بعد ذلك ، أود زيادة عدد العلامات وإنشاء عينة اختبار وتجربة العديد من الخوارزميات وتكوين النموذج والحصول على أدق التوقعات.

سأكون ممتنا لو تركت أفكارك وتعليقاتك.

Source: https://habr.com/ru/post/ar456226/


All Articles