为可重复的研究/结果选择“正确”的种子

机器算法验证 机器学习 预测模型 造型 错误 可重复研究
2022-04-14 14:29:54

我创建这篇文章是为了围绕我对用于复制统计模型结果的种子数的选择的想法展开讨论。以下是关于我如何提出这个想法以及如何应用它的一些背景知识。

我有一个数据集,称为数据,它有 506 个观察值、13 个预测变量和 1 个连续响应变量。我通过随机抽样 380 个索引而不进行替换,将数据拆分为训练和测试集,将与数据数据帧中的 380 个索引相等的行中的观察结果存储到称为 train 的数据帧中,并将剩余的 126 个观察结果存储到称为 test 的数据帧中.

创建训练集和测试集后,我使用glm函数构建了一个线性模型,使用predict函数预测了测试集的结果,并计算了测试集的预测值与其实际值之间的 MSE。在本例中,我获得了 16.65786 的 MSE。我把代码留在这里过夜,因为该回家了。

用于此的 R 代码是:

library(MASS)
data <- Boston

index <- sample(x = 1:nrow(data), size = round(nrow(data)*0.75), replace = FALSE)
train <- data[index, ]
test <- data[-index, ]

lm1.fit <- glm(medv ~ ., data = train)

pr.lm1 <- predict(lm1.fit, test)
(MSE.lm1 <- sum((pr.lm1 - test$medv)^2) / nrow(test))

第二天,我意识到我应该设置一个种子,以便用于创建训练集和测试集的随机索引(行)样本在每次运行代码时都是相同的。所以我选择了种子 1 并重新运行了上面的代码。这次我收到了 28.72933 的 MSE,与我前一天晚上获得的 MSE 相差很大。这引发了一个问题,如果我选择的种子是导致异常情况的种子,或者我获得的非种子结果是异常情况怎么办。也许这两个结果都是异常情况!所以我做了一些调查。

我使用 for 循环 10,000 次,每次获取一个新的随机索引样本,创建一个新的训练和测试集,建立一个线性模型,预测测试集的结果,并计算 MSE。我将 10,000 个 MSE 中的每一个都存储在一个数据框中,并计算了 MSE 的平均值和中值。我还查看了看起来大致正常的 MSE 分布。我再次重新运行了forloop,以确保MSE的平均值和中位数没有太大变化,它们没有。

前 10,000 个 MSE 的平均值为 24.13,中位数为 23.51。
第二个 10,000 个 MSE 的平均值为 24.01,中位数为 23.48。

用于此的 R 代码是:

error <- data.frame(err = rep(0, 10000))
for(i in 1:10000)
{
 index <- sample(x = 1:nrow(data), size = round(nrow(data)*0.75), 
                 replace = FALSE) 
 train <- data[index, ]
 test <- data[-index, ]

 #Linear Model 1 - No Data Cleaning
 lm1.fit <- glm(medv ~ ., data = train)
 summary(lm1.fit)

 pr.lm1 <- predict(lm1.fit, test)
 error[i, 1] <- sum((pr.lm1 - test$medv)^2) / nrow(test)
}
summary(error[, 1])

我做的最后一件事是循环通过相同的模型构建过程,直到我找到一个种子,导致 MSE 介于 20,000 个 MSE 的平均值和中位数之间。

用于此的 R 代码是:

for(i in 1:10000)
{
 set.seed(i)
 index <- sample(x = 1:nrow(data), size = round(nrow(data)*0.75), 
 replace = FALSE) 
 train <- data[index, ]
 test <- data[-index, ]

 #Linear Model 1 - No Data Cleaning
 lm1.fit <- glm(medv ~ ., data = train)
 summary(lm1.fit)

 pr.lm1 <- predict(lm1.fit, test)
 error <- sum((pr.lm1 - test$medv)^2) / nrow(test)
 if(error > 23 & error < 24){print(i)}
}

我选择使用 47 的种子,导致 MSE 为 23.63085。我相信这种获得种子的方法更准确地描述了模型准确预测的能力,而不是仅仅随机挑选种子或找到能提供最佳结果的种子(我认为这是“作弊”)。

我对你们所有统计学家的问题是,这似乎是一种合理的意识形态/方法吗?有没有更合适的方法?以这种方式采摘种子有缺点吗?

提前感谢大家的意见!


[Scortchi] 谢谢 - 我试图简洁并将两点混为一谈:(1)特别是 OP 的重新发明 Monte-Carlo 交叉验证;& (2) 样本外 MSE 估计对所用种子的敏感性表明他们应该使用某种形式的重新采样验证,而不是训练/测试拆分。– 斯科奇

[Brandon] @Scortchi 所以你说的是我应该简单地使用以下代码:

library(MASS)  
data <- Boston  

lm1.fit <- glm(medv ~ ., data = data)  

library(boot)  
set.seed(1)  
cvResult <- cv.glm(data = data, glmfit = lm1.fit, K = 10)  
cvResult$delta 

这导致 cv 预测误差为 23.38074,非常接近使用我上面的 long 方法获得的预测误差。我对么?

2个回答

种子的选择不应该影响最终的结果,否则你就有问题了。那么为什么我们需要种子呢?原因主要是为了调试和故障排除。

什么叫做最终结果假设您正在分析一种药物的功效,并使用蒙特卡罗模拟来得出某种临界值。种子对于你关于药物是否有效的结论应该无关紧要。

考虑一下:如果您使用 R 并且我正在起诉 Excel,我将如何使用您的种子?无论我们的软件包和平台有什么差异,我都应该能够重现最终结果。

当然,种子会影响获得的临界值的确切值,例如3.12 78765876 而不是3.12 8765987 与另一个种子,但这不是您研究的最终结果。假设检验统计量为 20.5,那么两个种子之间临界值的差异并不重要。实际上,你甚至不应该报告超过第三位的临界值,只显示 3.13,除非它是出于调试目的。

但是,如果不知何故第四位有效数字的差异导致或破坏了这种药物,那么我们就有问题了。这意味着我们不能使用这个临界值,或者我们需要增加模拟次数来确定第四位数字并将种子之间的差异减少到一个更小的数字。

因此,您需要设置其他模拟参数,以使种子对您的研究结论无关紧要。不要以任何方式“优化”种子。

在我的实践中,我有一些有趣的项目,客户会坚持报告所有计算出来的数字,例如 $31,456,890.01。模拟可能会产生 1% 的精度,因此不同种子之间的数字会以第二位或第三位数字变化。此外,模型本身的准确度最多只有 10% 左右,所以我会向物理学家报告 3e7。然而,会计师会抱怨这个数字看起来“四舍五入”,这让审计师抓狂:在他们看来,就像有人在“煮账”。我们最终将这些数字报告给美分,并存储种子,以便在审计请求时可以重现这些数字。

您当然可以使用“种子优化”来欺骗性能。例如,假设我正在比较两个只返回纯噪声的估计器。在使用交叉验证时,我 50% 的种子会说估计器 A 比 B 好,所以我需要做的就是确保我选择了一个好的种子,然后去发表我的论文!

这是否意味着使用保存的种子是不好的?并不真地。种子的全部意义在于你有一个脚本,有人可以使用它来完全重现你得到的确切结果。如果您声称交叉验证的 MSE 是 1.2,而研究人员说“嗯,我不相信……”,只需在他们面前重新运行脚本,他们就会看到这就是您所得到的。

现在,您可以优化种子以获得 1.2 MSE 吗?绝对地。但是以完全相同的方式,他们可以采用相同的脚本,多次更改种子,并确保结果几乎可以复制!因此,您可以使用种子来准确复制您看到的结果……然后通过在完全相同的脚本上随机使用其他种子来测试其可靠性。