APP下载

使用Python和PyTorch构建神经网络预测足球联赛比赛结果

消息来源:baojiabao.com 作者: 发布时间:2026-05-15

报价宝综合消息使用Python和PyTorch构建神经网络预测足球联赛比赛结果

本文分为两部分来讲解如何建立使用Python和PyTorch来预测足球比赛结果的神经网络。第一部分中,我们将解释如何使用Python和Pandas库从资料集中收集和准备资料。第二部分中,我们将解释如何使用Python和PyTorch平台建立和设定神经网络模型。

第一部分

关于资料

我们使用的资料是足球比赛结果,这些结果来自巴西联赛,2010赛季(BLC 2010),2011赛季(BLC 2011)和2012赛季(BLC 2012)。这些不同的资料集可以提供该方法的预测能力。联赛采用20支球队积分制。每支球队都将在主客场各进行一次比赛。以这种方式,总共进行38轮比赛并且每轮进行了10场比赛,因此每届联赛共产生380场比赛。

这些资料集来自UOL Sports网站BLC 2010,BLC 2011,BLC 2012,并转换为三个CSV档案(每个赛季一个)。

资料集格式

检视CSV档案中的资料集。

每个CSV档案包含一个标题行和760行资料。每行包含49个特征。我们不会使用资料集中提供的所有这49个特征。我们只使用其中的27个特征。

在本问中,我们将使用Python作为程式语言。为了收集和准备资料集,我们将使用Pandas库。对于神经网络模型(训练和测试),我们将使用PyTorch平台。

收集并准备资料集

首先,我们需要下载CSV档案并储存。在本文中,我们只使用BLC 2010中的资料集。您也可以使用其他CSV档案作为资料集进行尝试。

输入:

import pandas

filepath = "data/training_2010.csv"

df = pandas.read_csv(filepath)

print(df) # print to check

输出:

Pandas库是处理资料的绝佳选择。

在上面的程式码中,我们只是将CSV档案中的所有资料载入到Panda Dataframe(df)。我们现在有一个包含所有资料的大资料帧,我们需要选择所需的资料并从资料帧中提取它。如上所述,此资料集包含760行资料,每行包含49个特征。每行代表该队在一轮比赛中的所有资料。为了准备在PyTorch模型中使用的资料,我们需要遵循以下方式:

选择并提取我们想要的特征;为训练分离资料;分离测试资料;将0到1之间的资料归一化;随机选择训练和测试集;将训练和测试集分为输入和输出;转换两个输出集。这个方法对于准备要在PyTorch模型中使用的资料非常方便。本文中,我们将使用BLC 2010资料集完成此方法,也可以用于其他资料集。

选择并提取特征

如上所述,资料集包含49个特征。在本文中,我们值使用其中的的27个特征。

输入:

extract = [5, 6, 7, 8, 9, 10, 13, 14, 16, 17, 18, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 37, 38, 47, 48, 49]

df = df.iloc[:, extract] # df with the desired columns (features)

print(df) # print to the check

输出:

在上面的程式码中,我们建立了一个数组来选择我们想要的特征,其中列索引来自我们的。然后我们使用Pandas iloc函式从原始资料帧中提取所需的特征。可以尝试提取其他特征。重要提示:最后三个索引[47, 48, 49]是必不可少的,因为它们储存匹配结果。

分离资料进行训练和测试

我们将使用Pandas iloc函式将资料集拆分为训练和测试集。训练集是第1轮到第37轮每场比赛的统计资料。测试集是第38轮中每场比赛的统计资料。每轮包含10场比赛(即10行资料)。

输入:

training = df.iloc[:-10] # select all the rows except the last 10

test = df.iloc[-10:] # elect the last 10 rows

print(training) # print to check

print(test) # print to check

输出:

输出训练和测试资料时,您可以检视资料帧的维度。请注意,训练资料帧有[750行x 30列],这意味着我们有一个包含从第1轮到第37轮统计资料的资料帧。请注意,测试资料帧有[10行x 30列],这意味着我们有一个包含第38轮统计资料的资料帧。

将0到1之间的资料归一化

检视我们现在的值。值可以从0变化到300以上。我们需要将这些值归一化到0和1之间。我们将检查每个列(最后三个除外,即结果)的最大值,然后将该列的所有值除以10、100或1000。我们可以使用以下程式码解决此问题。

输入:

# normalize the data between 0 and 1

for e in range(len(training.columns) - 3): # iterate for each column

# check the maximum value in each column

num = max(training.iloc[:, e].max(), test.iloc[:, e].max())

if num training.iloc[:, e] /= 10

test.iloc[:, e] /= 10

elif num training.iloc[:, e] /= 100

test.iloc[:, e] /= 100

elif num training.iloc[:, e] /= 1000

test.iloc[:, e] /= 1000

else:

print("Error in normalization! Please check!")

print(training) # print to check

print(test) # print to check

输出:

现在我们有两个资料帧(一个用于训练,一个用于测试),两者都在0和1之间归一化。

随机选择训练和测试集

为什么要随机选择资料?随机选择资料可确保模型保持通用性并且减少过度拟合。在我们的例子中,我们可能需要对资料进行混洗,因为该资料集按其类/目标(即团队/结果)进行排序。在这里,您需要进行随机选择,以确保您的训练/测试集能够代表资料的整体分布。

在训练集中每行代表一场比赛的一个队的统计资料。所有比赛都按顺序排列,这意味着第0行的球队与第1行的球队比赛;第2行的球队与第3行的球队比赛;以此类推。.这意味着如果在偶数行(0,2,4,......)中的球队赢得比赛,则下面的球队将失败。同时也意味着如果一支偶数队中的球队得到平局,下面的球队也会得到平局。这是因为第0行和第1行是相同的匹配。

随机选择是一项简单的任务,可以通过多种方式完成。我们使用Pandas中的sample方法来解决此问题。

输入:

training = training.sample(frac=1) # shuffle the training data

test = test.sample(frac=1) # shuffle the test data

print(training) # print to check

print(test) # print to check

输出:

frac引数指定了随机样本中要返回的行的比例,所以frac = 1表示返回所有行(随机顺序)。

将训练和测试集分成输入和输出

接下来要做的是将训练和测试集分成输入和输出集。这是一个简单的任务,我们将使用iloc来完成它。

输入:

# all rows, all columns except for the last 3 columns

training_input = training.iloc[:, :-3]

# all rows, the last 3 columns

training_output = training.iloc[:, -3:]

# all rows, all columns except for the last 3 columns

test_input = test.iloc[:, :-3]

# all rows, the last 3 columns

test_output = test.iloc[:, -3:]

print(test_input) #print to check

print(test_output) #print to check

输出:

可以输出所有结果来检视。我们在这里做的是将训练资料帧分成另外两个资料帧:training_input和training_output。我们对测试集做了同样的事情。

转换两个输出集

训练输入集和测试输入集已经准备就绪。现在我们可能需要转换两个输出集。因为两个输出集都包含三个列,分别代表win(赢),draw(平),defeat(输)。如果win列中有1,则表示该轮比赛中的该队赢得了比赛。平和输列的情况相同。这意味着我们有三个类,我们在模型的输出层需要三个节点/神经元。为了更好地处理我们的模型,我们将这三个类转换为两个类。

这个新的输出将代表这支球队是否获胜(0或者1)。因此,通过这种方式,我们将训练三种不同的神经网络模型:一个模型表示胜利,一个模型表示平局,一个模型表示失败。

本文中我将展示赢家的方案。输家和平局方案遵循相同的想法。如果队伍赢得了比赛,则输出值为1。如果队伍失败或者平局,则输出值为0。我们需要做的就是将三列输出转换为一列。

输入:

# separating the output into two classes: win or draw-defeat

# for the winners convert the output:

# from (1, 0, 0) to 1

# from (0, 1, 0) to 0

# from (0, 0, 1) to 0

def convert_output_win(source):

target = source.copy() # make a copy from source

target[\'new\'] = 2 # create a new column with any value

for i, rows in target.iterrows():

if rows[\'win\'] == 1:

rows[\'new\'] = 1

if rows[\'draw\'] == 1:

rows[\'new\'] = 0

if rows[\'defeat\'] == 1:

rows[\'new\'] = 0

return target.iloc[:, -1] # return all rows, the last column

training_output = convert_output_win(training_output)

test_output = convert_output_win(test_output)

您可能希望建立一个函式来解决此问题,以便更轻松地维护/重用程式码。

到目前为止我们已经完成了资料整理!

第二部分

这部分中我们将重点关注建立和设定神经网络模型。然后我们将训练和测试模型,最后我们将检查结果。

什么是PyTorch?

根据官方网站介绍,PyTorch是一个基于python的科学计算软件包:

NumPy的替代品,可以使用GPU的强大功能;深度学习研究平台,提供最大的灵活性和速度。PyTorch最好的东西之一是Tensors(张量)。Tensors与NumPy的ndarray类似,另外Tensors也可以用于GPU以加速计算。

安装PyTorch

安装PyTorch很简单。只需按照PyTorch官方网站的“入门”部分中的说明操作即可。

如何构造随机初始化矩阵的示例:

import torch

x = torch.rand(5, 3)

print(x)

首先

什么是人工神经网络(ANN)。根据维基百科:

人工神经网络是一种计算系统,它受到构成动物大脑的生物神经网络的启发,但不一定完全相同。这类系统通过考虑例项“学习”执行任务,通常不需要编写任何特定于任务的规则。

人工神经网络是基于一组被称为人工神经元的连线单元或节点的集合,这些单元或节点对生物大脑中的神经元进行的建模。每个连线,就像生物大脑中的突触一样,都能将讯号从一个人工神经元传递到另一个。一个接收到讯号的人工神经元可以处理它,然后向连线到它的其他人工神经元发出讯号。

下图显示了神经网络图的一个例子。

构建前馈神经网络

现在让我们看看如何构建一个简单的前馈网络模型。前馈模型在输入和输出层之间具有隐藏层。在每个隐藏层之后,应用一个启用函式来引入非线性。下面是一个前馈模型的例子。

import torch

class Net(torch.nn.Module):

def __init__(self, input_size, hidden_size):

super(Net, self).__init__()

self.input_size = input_size

self.hidden_size = hidden_size

self.fc1 = torch.nn.Linear(self.input_size, self.hidden_size)

self.relu = torch.nn.ReLU()

self.fc2 = torch.nn.Linear(self.hidden_size, 1)

self.sigmoid = torch.nn.Sigmoid()

def forward(self, x):

hidden = self.fc1(x)

relu = self.relu(hidden)

output = self.fc2(relu)

output = self.sigmoid(output)

return output

正如您在此示例中所看到的,我们建立的模型只包含一个隐藏层,但您可以根据需要新增任意数量的隐藏层。当我们有两个以上的隐藏层时,该模型也称为深层或多层前馈模型或多层感知器模型(MLP)。

在隐藏层之后,我们使用ReLU作为启用,然后将资讯传送到输出层。这是为了从隐藏层的线性输出引入非线性。ReLU在这里做的是:如果函式应用于一组数值,则任何负值都将转换为0,否则这些值将保持不变。例如,如果输入集为[-2,0,3,-4,7],则函式将返回[0,0,3,0,7]。

我们使用Sigmoid作为输出启用函式。我们要做的预测是我们在第一部分中提到的二元分类任务,这意味着我们有二元类别可以预测。Sigmoid是一个很好用的函式,因为它计算目标输出为label1的概率(范围在0和1之间)。启用函式的选择取决于你的任务。

现在,让我们使用我们建立的这个模型来建立足球比赛的预测器。

训练模型

神经网络的典型训练程式如下:

定义具有一些可学习引数(或权重)的神经网络。遍历输入资料集。通过网络处理输入。计算损失。传播梯度回归网络引数。通常使用简单的更新规则来更新网络的权重:weight = weight — learning_rate * gradient。资料

在第一部分中,我们的资料已准备就绪。我们有四个资料帧(training_input,training_output,test_input,test_output)。要在PyTorch中使用此集合,我们可能需要将这些资料帧转换为Tensors。使用torch.FloatTensor()很简单。

输入:

#convert to tensors

training_input = torch.FloatTensor(training_input.values)

training_output = torch.FloatTensor(training_output.values)

test_input = torch.FloatTensor(test_input.values)

test_output = torch.FloatTensor(test_output.values)

设定模型,标准,优化器

让我们定义模型,它的输入维度等于我们拥有的特征数量。对于隐藏维度,我们将其定义为30。对于损失函式(标准),我们使用BCELoss()(二进位制交叉熵损失),因为我们的任务是对二进位制结果进行分类。我们使用的优化器是SGD(随机梯度下降),学习率为0.9。

输入:

input_size = training_input.size()[1] # number of features selected

hidden_size = 30 # number of nodes/neurons in the hidden layer

model = Net(input_size, hidden_size) # create the model

criterion = torch.nn.BCELoss() # works for binary classification

# without momentum parameter

optimizer = torch.optim.SGD(model.parameters(), lr = 0.9)

#with momentum parameter

optimizer = torch.optim.SGD(model.parameters(), lr = 0.9, momentum=0.2)

训练模型

为了检验模型的改进情况,我们可以在模型训练前检验测试损失,并将其与训练后的测试损失进行比较。

输入:

model.eval()

y_pred = model(test_input)

before_train = criterion(y_pred.squeeze(), test_output)

print(\'Test loss before training\' , before_train.item())

在mode.eval()这里设定PyTorch模组为评估模式。在此模式下,模型不会学习新的权重。我们只是想在训练前看到损失。为了训​​练,我们应该将模式切换回训练模式。

输入:

model.train()

epochs = 5000

errors = []

for epoch in range(epochs):

optimizer.zero_grad()

# Forward pass

y_pred = model(training_input)

# Compute Loss

loss = criterion(y_pred.squeeze(), training_output)

errors.append(loss.item())

print(\'Epoch {}: train loss: {}\'.format(epoch, loss.item()))

# Backward pass

loss.backward()

optimizer.step()

现在开始进行训练,首先,我们将模组模式切换到model.train(),以便在每个周期之后可以学习新的权重。然后我们将训练的周期数定义为5000(您可以根据需要更改)。optimizer.zero_grad()在我们开始反向传播之前将梯度设定为零。这是必要的步骤,因为PyTorch积累了来自前一个周期的反向传递的梯度。我们还设定了一个误差阵列以保持每个周期的损失,并在过程结束时绘制图表。

在正向传递和损失计算之后,我们通过呼叫loss.backward()来执行反向传递,其计算梯度。然后相应地使用optimizer.step()更新权重。训练过程可能需要一段时间,具体取决于您设定的训练周期。

测试模型

现在,训练已经完成。让我们看看训练后测试损失是如何变化的。同样,我们将模组模式切换回评估模式并检查测试损失,如下例所示。

输入:

model.eval()

y_pred = model(test_input)

after_train = criterion(y_pred.squeeze(), test_output)

print(\'Test loss after Training\' , after_train.item())

您一定想知道我们的模型是否产生了好的或坏的预测。让我们看一下使用matplotlib库绘制一些图表。

import matplotlib.pyplot as plt

def plotcharts(errors):

errors = np.array(errors)

plt.figure(figsize=(12, 5))

graf02 = plt.subplot(1, 2, 1) # nrows, ncols, index

graf02.set_title(\'Errors\')

plt.plot(errors, \'-\')

plt.xlabel(\'Epochs\')

graf03 = plt.subplot(1, 2, 2)

graf03.set_title(\'Tests\')

a = plt.plot(test_output.numpy(), \'yo\', label=\'Real\')

plt.setp(a, markersize=10)

a = plt.plot(y_pred.detach().numpy(), \'b+\', label=\'Predicted\')

plt.setp(a, markersize=10)

plt.legend(loc=7)

plt.show()

plotcharts(errors)

视觉化资料和结果是很重要的事情之一!

这些图表非常简单,只是为了便于结果的视觉化。我们不打算使用图表来证实或反驳模型的效率。

第一个图表是每个训练周期的误差进度。看看它在训练过程中如何减少。第二个图表用黄色圆圈表示实际值(Win :x = 1,Draw-Defeat : x = 0); 以及用蓝色十字表示预测值。蓝色十字越接近黄色圆圈,这个预测就越准确。如果蓝色十字在黄色圆圈内部,或者非常接近它,则意味着模型正确地预测了结果。换句话说,如果蓝色十字架远离黄色圆圈,则意味着模型对这场比赛做出了错误的预测。

在这个特殊情况下,我们的模型做出了8个正确的预测,2个错误的预测。我们的模型预测比赛结果的准确率达到80%。

为了改进预测,以下是可以应尝试更改的引数列表:

学习率:float介于0和1之间。动量率:float介于0和1之间。隐藏层数:更改模型的结构,新增更多隐藏层。隐藏层中的神经元/节点数。训练周期:训练的次数越多准确率会越高。重要的提示:

正如我们前面提到的,这个例子演示了一个模型,这个模型可以预测一支球队是赢得比赛还是平局或者失败。执行其他模型以预测另外两个类别,即一个队伍是否会输掉一场比赛或打成平局;或者一支球队是平局还是会胜利或失败。为了正确执行此操作,请记住正确更改convert_output_win() 函式。

由于有许多不同的超引数和模型选择技术被广泛使用,所以,您可以选择提供最佳效能的其他超引数和模型结构。

在本文中我们介绍了很多内容:

收集和准备资料;构建和设定神经网络模型;训练和测试模型;检查结果。我们希望您已经学会了如何使用神经网络来预测体育比赛的结果。

2020-01-17 02:49:00

相关文章