Futbolli (futbolli) është sporti më i ndjekur në botë dhe asnjë ngjarje klubi nuk është më e madhe se finalet e UEFA Champions League (UCL). Me finalen mes Manchester Cityt dhe Interit që do të luhet këtë të dielë, siç shihet në tendencat e fundit, ka pasur një rritje të mënyrave të ndryshme të parashikimit të rezultatit të kësaj loje. Ekspertët kanë bërë parashikimet e tyre dhe vezët kanë bërë të tyret. Ekspertët përgjithësisht pajtohen se Manchester City është favorit për të fituar Ligën e Kampionëve këtë vit dhe për të plotësuar kështu trefishin e tyre. Megjithatë, një parashikim që përfshin një tufë vezësh parashikon që Interi do ta fitojë atë. Kjo më bëri të shfrytëzoj fuqinë e të dhënave për të bërë parashikimin tim dhe për të testuar fuqinë e vezës.

Në epokën e Inteligjencës Artificiale dhe informatikës me kompleksitet të lartë, është bërë shumë më e lehtë përdorimi i të dhënave për të bërë parashikimet e veta. Për të arritur qëllimin tim për të parashikuar rezultatin e finaleve të UCL, krijova një program duke përdorur Python3, Keras dhe TensorFlow, NumPy, Pandas, Scikit-learn, SciPy dhe të dhëna nga FBref.

TL;DR

Për ata që janë këtu vetëm për të ditur se çfarë parashikoi AI, rezultati ka të ngjarë të jetë 2–1 për Cityme një shans 67.5% që Manchester City të fitojë në çdo rezultat. Për ata që duan të kuptojnë procesin pas marrjes së këtij parashikimi, lexoni më tej.

Marrja e të dhënave

Ju mund të përdorni një skedar Jupyter Notebook dhe Python për kodin për të parashikuar rezultatet e ndeshjes për sezonin 2022–23 për UCL dhe të dhënat që kam fshirë nga FBref si tre skedarë të Microsoft Excel përmes lidhjes GitHub më poshtë:



Parapërpunimi

Ok, le të fillojmë. Së pari përpunova të dhënat nga tre skedarë duke përfshirë ndeshjet, statistikat e secilit ekip që luan dhe statistikat kundër secilit ekip që luan. I bashkova të dhënat në dy matrica, X (të dhënat që do të hartohen) dhe y (vlerat me të cilat do të hartohen të dhënat në X). X përbëhej nga statistikat e çdo ndeshjeje për një ekip të caktuar (d.m.th., për Chelsea kundër Real, ne do të kishim X të përbërë nga statistikat e Chelsea dhe statistikat e Realit kundër dhe y që përbëhet nga golat e Chelsea të shënuar në lojë). E kam përjashtuar qëllimisht shtëpi/lag në matricën time X pasi finalet nuk janë as në shtëpi e as jashtë për asnjërën skuadër.

#Importing libraries for data processing
import pandas as pd
import numpy as np

#Getting the data (fixtures, team stats, and stats against the team)
fixtures = pd.read_excel('Fixtures.xlsx').values
stats = pd.read_excel("Team Stats.xlsx").values
vs_stats = pd.read_excel("Vs Stats.xlsx").values

#Temp is used & re-used to visualize the intermediate steps
temp=[]
for i in fixtures:
    temp.append(str(i[1]).split("–"))
    
fixtures = np.delete(fixtures, 1, 1)
fixtures = np.append(fixtures, temp, 1)

fixturesArranged=[]
y = []
for i in fixtures:
    fixturesArranged.append([i[0], i[1]])
    y.append(i[2])           
    fixturesArranged.append([i[1], i[0]])
    y.append(i[3])

#Creating a function that would prepare our dataset for the neural network as a tensor/matrix
def process_fixtures(fixturesArranged):
    temp=[]
    temp2=[]
    for i in fixturesArranged:
        _t1 = str(i[0]).split()
        print(_t1)
        _t2 = str(i[1]).split()
        print(_t2)
        for j in stats:
            if ((_t1[0] in str(j[0])) and (_t1[1] in str(j[0]))):
                temp.append(j)
        for j in vs_stats:
            if ((_t2[0] in str(j[0])) and (_t2[1] in str(j[0]))):
                temp2.append(j)
                
    X = np.append(fixturesArranged, temp, 1)
    X = np.append(X, temp2, 1)
    X = np.delete(X, [0,1,2], 1)
    X = np.delete(X, 21, 1)
    return X

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
def split_data():
  X = process_fixtures(fixturesArranged)

  #Splitting data into training and testing datasets
  
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

  #Scaling the data appropriately to impart uniformity to the data

  X_train = sc.fit_transform(X_train)
  X_test = sc.transform(X_test)
  return X_train, X_test, y_train, y_test

Vini re se funksionet përdoren këtu për të lejuar ripërdorimin e të njëjtit proces dhe/ose për ta bërë më të lehtë ndjekjen.

Trajnimi

Më pas, ne krijojmë modelin tonë. Kjo mund të bëhet në mënyra të ndryshme, por unë përdora qasjen vijuese:

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
import os

checkpoint_path = "/content/ucl.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

import tensorflow as tf
es = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=16)
ckpt = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_dir, monitor='loss', verbose=1, save_best_only=True, save_weights_only=True, mode='min')

def create_regressor():
  # Initialising the regressor
  regressor = Sequential()

  # input layer and first hidden layer
  regressor.add(Dense(units = 32, kernel_initializer = 'uniform', activation = 'relu', input_dim = 46))
  regressor.add(Dropout(0.2))

  # second hidden layer
  regressor.add(Dense(units = 16, kernel_initializer = 'uniform', activation = 'relu'))
  regressor.add(Dropout(0.2))

  # third hidden layer
  regressor.add(Dense(units = 8, kernel_initializer = 'uniform', activation = 'relu'))
  regressor.add(Dropout(0.2))

  # fourth hidden layer
  regressor.add(Dense(units = 4, kernel_initializer = 'uniform', activation = 'relu'))
  regressor.add(Dropout(0.2))

  # output layer
  regressor.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'linear'))

  # compiling the model
  regressor.compile(optimizer = 'adam', loss = 'mean_squared_error', metrics = ['accuracy'])
  
  return regressor

Përmbledhja e modelit është si më poshtë:

Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_10 (Dense)            (None, 32)                1504      
                                                                 
 dropout_8 (Dropout)         (None, 32)                0         
                                                                 
 dense_11 (Dense)            (None, 16)                528       
                                                                 
 dropout_9 (Dropout)         (None, 16)                0         
                                                                 
 dense_12 (Dense)            (None, 8)                 136       
                                                                 
 dropout_10 (Dropout)        (None, 8)                 0         
                                                                 
 dense_13 (Dense)            (None, 4)                 36        
                                                                 
 dropout_11 (Dropout)        (None, 4)                 0         
                                                                 
 dense_14 (Dense)            (None, 1)                 5         
                                                                 
=================================================================
Total params: 2,209
Trainable params: 2,209
Non-trainable params: 0
_________________________________________________________________

Për të trajnuar modelin, unë thjesht e vendos këtë model në të dhënat e mia X-train dhe y_train, duke përdorur Ndalimin e Hershëm për të përfunduar stërvitjen kur regresori nuk po përmirësohet për periudha të gjata kohore. Unë përdor gjithashtu një pikë kontrolli model për të ruajtur versionin më të mirë të modelit tim, d.m.th., versionin me humbjen më të vogël.

#Training

regressor = create_regressor()
X_train, X_test, y_train, y_test = split_data()
regressor.fit(np.asarray(X_train).astype('float32'), np.asarray(y_train).astype('float32'), batch_size = 10, epochs = 10000, shuffle = True, callbacks=[es,ckpt])

Testimi dhe Vlerësimi

Tani për pak minuta modelja u trajnua. Megjithatë, përpara se të bëja ndonjë parashikim, më duhej të testoja modelin tim dhe të merrja statistika që do të na jepnin njohuri se sa i besueshëm është modeli.

# Evaluating the model

preds = regressor.predict(X_test)

y_test = np.array([int(i) for i in y_test])
print(y_test)
print(preds[:,0])

diff = preds[:,0] - y_test
print(diff)

mean = np.mean(diff)
std = np.std(diff)

print("[error_mean: {:.2f}, sample_error_stddev: {:.2f}".format(mean, std))

Zbulova se modeli im kishte një mesatare gabimi prej afërsisht -0.06 dhe një devijim standard prej 1.34, që është një vlerë e respektueshme për një sport të dominuar nga kaosi matematik.

Parashikimet

Tani mund të parashikojmë rezultatin e ndeshjes City-Inter.

import math

fixturePred = [["Manchester City eng", "it Inter"], ["it Inter", "Manchester City eng"]] #Manchester City Eng and it Inter were formatting of FBref data
X_pred = process_fixtures(fixturePred)
X_pred = sc.transform(X_pred)
y_pred = np.reshape(regressor.predict(X_pred), (1,-1))[0]
print(y_pred) #The regressor's prediction of the scoreline

from scipy.stats import norm
z_score = ((y_pred[0]-y_pred[1])-mean)/math.sqrt(2*std)
p_value = norm.cdf(z_score) #probability that City wins given that errors made by the regressor are independent
print(p_value) #The probability that Manchester City wins the game

Mjerisht, modelja arriti në përfundimin e saj. Dhe, përfundimi ishte diçka që ne e presim në këtë pikë: një shans afërsisht 67.5% që Manchester City të fitojë në çdo rezultat, më e mundshme nga të cilat ai parashikoi ishte 1.54–0.8, që në rrumbullakim ishte rezultati 2–1 (si pikët dhjetore nuk janë të mundshme).

Kështu, shanset nuk janë në favor të vezëve me një shans të ulët 32.5% për të fituar (duke supozuar se një barazim zgjidhet përpara gjuajtjeve të penalltive), por kush e di? Sportet, veçanërisht futbolli, janë të njohur për (dhe tërheqës) për shkak të paparashikueshmërisë së tyre.