18、线性模型与深度学习:从足球比赛预测到神经网络探索

线性模型与深度学习:从足球比赛预测到神经网络探索

1. 线性模型在足球比赛预测中的应用

在处理数据时,由于2000年8月之前的数据存在大量列缺失的情况,这些数据被移除。在尝试 COORDINATE_DESCENT_NAIVE 时出现了错误,但其他结果仍具有一定的参考价值。以下是不同求解器和 alpha 值下的均方误差(MSE)、对数损失误差(logloss error)结果:
| 求解器(solver) | alpha | MSE | logloss error |
| — | — | — | — |
| IRLSM | 0 | 0.075 0.292 | 0.0791 |
| COORDINATE_DESCENT | 0 | 0.077 0.297 | 0.0802 |
| L_BFGS | 0 | 0.08 | 0.31 | 0.0839 |
| IRLSM | 0.99 | 0.098 0.343 | 0.0931 |
| COORDINATE_DESCENT | 0.5 | 0.101 0.352 | 0.0941 |
| IRLSM | 0.5 | 0.101 0.352 | 0.0942 |
| COORDINATE_DESCENT | 0.99 | 0.1 | 0.35 | 0.0953 |
| L_BFGS | 0.5 | 0.81 | 2.302 | 0.8899 |
| L_BFGS | 0.99 | 0.81 | 2.302 | 0.8899 |

然而,所有这些结果都不如默认模型(得分0.0782)。这表明在这种情况下,默认的广义线性模型(GLM)参数可能难以被超越。

接下来看足球比赛结果预测,这是一个具有挑战性的数据集。预测基于近期表现和博彩公司赔率形式的专家预测。具体操作步骤如下:
1. 运行相关脚本设置H2O,加载数据,并定义训练集、验证集、测试集、输入变量 x 、不包含赔率的输入变量 xNoOdds 和输出变量 y 。确保使用 football.train2.csv football.valid2.csv football.test2.csv ,因为这些文件中的缺失值已被处理,而GLM对缺失值处理效果不佳。
2. 构建一个简单的线性模型,仅使用博彩公司平均胜赔作为单一输入,其他采用默认设置。该模型可作为评估其他模型的基准。以下是R代码:

mAvH <- h2o.glm("BbAvH", "HomeWin", train,
  model_id = "GLM_defaults_HomeWin_BbAvH",
  validation_frame = valid, family = "binomial")

该模型的AUC和准确率结果如下:
| 数据集 | HomeWin (AUC) | HomeWin (Accuracy) |
| — | — | — |
| 训练集 | 0.618 | 0.589 |
| 验证集 | 0.675 | 0.650 |
| 测试集 | 0.650 | 0.634 |

然后,构建两个感兴趣的模型:一个使用所有字段预测主场获胜( m1 ),另一个不使用博彩公司赔率预测主场获胜( m2 )。

m1 <- h2o.glm(x, "HomeWin", train,
  model_id = "GLM_defaults_HomeWin_Odds",
  validation_frame = valid, family = "binomial")
m2 <- h2o.glm(xNoOdds, "HomeWin", train,
  model_id = "GLM_defaults_HomeWin_NoOdds",
  validation_frame = valid, family = "binomial")

使用 compareModels() 函数查看它们的AUC和准确率:

res <- compareModels(c(m1,m2), test)
round(res[",AUC",], 3)
round(res[",Accuracy",], 3)

结果如下:
| 数据集 | Odds (AUC) | NoOdds (AUC) | Odds (Accuracy) | NoOdds (Accuracy) |
| — | — | — | — | — |
| 训练集 | 0.636 | 0.595 | 0.607 | 0.582 |
| 验证集 | 0.678 | 0.625 | 0.650 | 0.615 |
| 测试集 | 0.645 | 0.612 | 0.622 | 0.605 |

从准确率来看,以0.634为目标(验证集为0.650),使用更多字段反而使模型表现更差。查看 m1 的重要输入变量,前24个变量都是博彩赔率,第25个是 res5a ,这使得结果变差有些奇怪。对于 m2 ,不使用博彩赔率时得分自然更低,但也不算太差。其前五大变量如下:
| 名称(names) | 系数(coefficients) | 符号(sign) |
| — | — | — |
| res20A | 0.199159 | NEG |
| res20H | 0.183050 | POS |
| Div.E0 | 0.098531 | POS |
| HS1 | 0.080411 | POS |
| res5H | 0.062600 | POS |

前两个变量是基于前20场比赛结果的“长期球队实力”估计,客队实力为负影响,主队实力为正影响,这是合理的。第三个变量表明如果比赛是顶级联赛,主场获胜的可能性更大。第四个变量显示主队最近一场比赛的射门次数越多,获胜机会越大。

2. 调整GLM模型

既然使用所有列的结果比仅使用一列更差,那么能否调整GLM以获得更好的结果呢?这里专注于使用所有可用列预测主场获胜的情况。由于有79列,远低于IRLSM求解器的500列指南,因此继续使用该求解器。对于二项式分类,设置 family = "binomial" ,链接函数固定为“logit”。

使用早停策略、开启 lambda 搜索,并尝试三个主要的 alpha 值(0.0用于岭回归,1.0用于套索回归,0.5用于弹性网络)。以下是相关代码:

g <- h2o.grid("glm", grid_id = "GLM_1",
  hyper_params = list(
    alpha = c(0, 0.5, 0.99)
  ),
  x = x, y = "HomeWin", training_frame = train,
  validation_frame = valid,
  family = "binomial",
  lambda_search = TRUE,
  stopping_metric = "AUC",
  stopping_tolerance = 0,
  stopping_rounds = 4,
  max_iterations = 100
)

结果显示,精确到三位小数时,所有 alpha 值的测试集AUC相同(0.645),略低于基准模型。准确率结果也不太理想。最佳 alpha 值为0.0,再次尝试一些较低的 alpha 值(0.05和0.15),0.0仍然是最佳值,模型之间的差异较小。最终结论是没有其他值得调整的参数,最佳模型的表现与默认模型相同,测试集AUC为0.645。

3. 深度学习(神经网络)简介

深度学习是神经网络的新流行名称,它在当前的人工智能和机器学习领域取得了显著进展。深度学习算法在人类容易解决但其他机器学习方法困难的问题上表现出色,如模式识别。然而,它也有缺点,如训练速度慢、是黑盒模型难以解释、处理分类输入有一定困难。如果问题是计算公司年度交易的应纳税额,神经网络不是合适的选择。

H2O的深度学习实现易于使用,能处理大部分细节,只需一行代码就能获得不错的结果。不过,仍有大量参数需要调整,但大部分参数无需过多关注。

4. 神经网络的工作原理

在H2O中,神经网络采用前馈神经网络实现,设计用于在大型数据集的集群上并行运行,目前不支持GPU。其基本原理如下:
- 神经元是一个接受多个数值输入并输出一个数值的函数。这些神经元组织成层,一层中所有神经元的输出成为下一层每个神经元的输入。
- 第一层是数据(训练样本、测试样本或生产中的实际输入),最后一层是输出(答案)。如果是回归问题,输出层有一个神经元;如果是分类问题,输出层的每个可能答案对应一个神经元,每个输出值是该答案的概率,选择概率最高的答案。输入层和输出层之间的层称为隐藏层。
- 每个隐藏层的神经元对其每个输入都有一个权重,修改这些权重是网络学习的方式。每个神经元还有一个“偏置”输入,可视为连接到常量输入的权重,在训练过程中也会被调整。

训练过程是从随机权重开始,输入第一个训练样本和正确答案,计算误差,然后根据误差调整权重以减少误差。处理完所有训练数据称为一个 epoch,可指定算法执行的 epoch 数。与其他深度学习库不同,H2O不使用小批量,权重在每个样本后更新。在多节点集群上运行时,每个节点独立工作一次迭代,迭代结束时将网络权重与其他节点的权重平均。

5. 神经网络中的数字与类别处理

在神经网络中,一切都是数字,当所有预测变量都是数值时,神经网络表现最佳。对于分类输入,每个可能的值会成为一个输入神经元,采用独热编码。例如,对于性别字段(“Male”、“Female”、“Unknown”)和年龄字段(数字),会有四个输入神经元:
- Male?
- Female?
- Gender-unknown?
- Age

对于21岁男性,输入为:
- Male = 1
- Female = 0
- Gender-unknown = 0
- Age = 21

对于未回答性别问题的55岁人,输入为:
- Male = 0
- Female = 0
- Gender-unknown = 1
- Age = 55

H2O会自动处理包含数值、整数和枚举变量的数据集的所有数据操作。

6. 有序因子的处理

如果年龄作为分类输入,例如分为“under 18”、“18 to 24”、“25 to 39”、“40 to 59”、“60+”,这是一个有序因子。是否将其转换为单个数值输入是一个棘手的问题。在这种情况下,建议保留为五个类别,因为难以确定如何转换为数字,且数据的意图可能是作为生活方式的代理。但如果年龄字段由20个干净的五年范围类别组成,则更倾向于将其转换为单个值。

7. 网络层的选择

使用 h2o.deeplearning() 时,主要关注两个方面:训练的 epoch 数和网络的形状(层数和每层的神经元数)。层数和神经元数越多,训练和使用的速度越慢,因此应尽量减少。理论上,一个隐藏层足以表示所有数据,但实际中往往不够,而且大多数人不认为只有一个隐藏层的是深度学习。

选择层数和神经元数的一些提示如下:
- 对于非线性问题,从两层开始尝试。
- 问题的非线性程度越高,需要的层数越多。如果感觉模型无法学习,可以尝试增加一层、增加 epoch 数或增加训练数据。但如果已经有五层,增加第六层可能不会有帮助,且训练时间会大幅增加。
- 一层中的神经元越多,对数据的理解越清晰。如果感觉模型有大致概念但不够精确,可以尝试增加神经元、增加 epoch 数或增加训练数据。
- 输入数据越多,第一个隐藏层可能需要的神经元越多。
- 输出神经元越多,最后一个隐藏层可能需要的神经元越多。
- 层数越多,越可能从丢弃函数中受益。

可以通过查看得分历史图来判断增加 epoch 数是否有帮助。如果线条波动剧烈且总体趋势横向,增加 epoch 数可能无济于事;如果线条变得平坦,增加 epoch 数可能会有小的改进,但收益递减。

训练深度学习模型的时间主要由训练样本数乘以 epoch 数决定。模型中的权重数也会影响训练时间,两层之间的权重数是两层神经元数的乘积,不要忘记计算输入层和输出层。例如,一个100x100的网络,有2个数值输入和1个输出,有(2 * 100) + (100 * 100) + (100 * 1) = 10,300个权重;如果增加一个同样有100个神经元的第三层,权重数变为(2 * 100) + (100 * 100) + (100 * 100) + (100 * 1) = 20,300个,模型可能会更好地理解问题,但可能需要更多时间收敛。

8. 激活函数

在神经网络中,神经元内部的函数即激活函数起着关键作用。它决定了神经元如何将输入信号转换为输出信号,对网络的学习和表达能力有着重要影响。常见的激活函数有以下几种:
- Sigmoid函数 :其公式为 ( f(x)=\frac{1}{1 + e^{-x}} ),该函数将输入值映射到 (0, 1) 区间,具有平滑的曲线,常用于二分类问题的输出层,可将输出解释为概率值。但它存在梯度消失问题,当输入值非常大或非常小时,函数的导数趋近于 0,导致在反向传播过程中梯度更新缓慢。
- ReLU函数 :即修正线性单元,公式为 ( f(x) = max(0, x) )。它计算简单,能有效缓解梯度消失问题,使得网络训练速度更快。在隐藏层中广泛应用,许多深度学习模型都采用 ReLU 作为默认的激活函数。不过,ReLU 存在“死亡 ReLU”问题,当输入值为负数时,神经元的输出为 0,且在后续训练中可能无法恢复。
- Tanh函数 :公式为 ( f(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}} ),它将输入值映射到 (-1, 1) 区间,与 Sigmoid 函数类似,但输出范围更广。Tanh 函数的均值更接近 0,在某些情况下能使训练更稳定。

激活函数 公式 优点 缺点
Sigmoid ( f(x)=\frac{1}{1 + e^{-x}} ) 输出在 (0, 1) 区间,可解释为概率 梯度消失问题
ReLU ( f(x) = max(0, x) ) 计算简单,缓解梯度消失 死亡 ReLU 问题
Tanh ( f(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}} ) 输出在 (-1, 1) 区间,均值接近 0 存在一定的梯度消失问题
9. 深度学习在数据集中的应用步骤

下面以一个具体的数据集为例,说明使用 H2O 进行深度学习的操作步骤:
1. 数据准备 :确保数据集的格式正确,处理缺失值。如果数据集中包含分类变量,H2O 会自动进行独热编码。
2. 加载数据到 H2O :使用 H2O 的相关函数将数据加载到 H2O 环境中。
3. 划分数据集 :将数据集划分为训练集、验证集和测试集,用于模型的训练、调优和评估。
4. 构建深度学习模型 :使用 h2o.deeplearning() 函数构建模型,设置必要的参数,如 epochs (训练的 epoch 数)、 hidden (隐藏层的神经元数)等。以下是一个示例代码:

library(h2o)
h2o.init()

# 加载数据
data <- h2o.importFile("your_data.csv")

# 划分数据集
splits <- h2o.splitFrame(data, ratios = c(0.7, 0.15), seed = 123)
train <- splits[[1]]
valid <- splits[[2]]
test <- splits[[3]]

# 定义输入和输出变量
x <- setdiff(names(train), "target_column")
y <- "target_column"

# 构建深度学习模型
model <- h2o.deeplearning(
  x = x,
  y = y,
  training_frame = train,
  validation_frame = valid,
  epochs = 10,
  hidden = c(100, 100),
  activation = "ReLU"
)
  1. 模型评估 :使用测试集评估模型的性能,可使用常见的评估指标,如准确率、AUC 等。
# 模型预测
predictions <- h2o.predict(model, test)

# 评估模型
performance <- h2o.performance(model, test)
print(h2o.accuracy(performance))
print(h2o.auc(performance))
10. 深度学习模型的调优策略

为了提高深度学习模型的性能,可采用以下调优策略:
- 调整网络结构 :尝试不同的层数和每层的神经元数,根据问题的复杂度和数据集的大小进行调整。
- 选择合适的激活函数 :根据问题的特点选择合适的激活函数,如对于二分类问题,Sigmoid 函数可能更合适;对于隐藏层,ReLU 函数通常效果较好。
- 调整学习率 :学习率控制着权重更新的步长,过大的学习率可能导致模型无法收敛,过小的学习率会使训练速度变慢。可以尝试不同的学习率,或者使用学习率衰减策略。
- 使用正则化方法 :如 L1 和 L2 正则化,可防止模型过拟合。在 H2O 中,可以通过设置 lambda 参数来实现。
- 增加训练数据 :更多的训练数据可以提高模型的泛化能力,减少过拟合的风险。

11. 总结与对比

线性模型和深度学习模型各有优缺点,适用于不同的场景。线性模型在数据存在线性关系时表现出色,能够以较少的努力获得较好的模型,且在处理大规模数据集时速度较快。例如在足球比赛预测中,线性模型可以通过简单的设置得到一个基准模型。而深度学习模型在处理非线性问题和模式识别方面具有优势,但训练速度慢,是黑盒模型难以解释。

以下是两者的对比表格:
| 模型类型 | 优点 | 缺点 | 适用场景 |
| — | — | — | — |
| 线性模型 | 训练速度快,易于解释,对线性数据效果好 | 不适合非线性数据和复杂模式识别 | 数据存在线性关系的场景 |
| 深度学习模型 | 擅长处理非线性问题和模式识别 | 训练速度慢,难以解释,处理分类输入有困难 | 非线性问题和模式识别场景 |

在实际应用中,应根据问题的特点和数据集的情况选择合适的模型。如果对模型的可解释性要求较高,线性模型可能是更好的选择;如果追求更高的准确率和处理复杂问题的能力,深度学习模型可能更合适。同时,也可以尝试将两种模型结合使用,发挥各自的优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值