k折交叉验证:如何根据Stata中随机生成的整数变量过滤数据

k-fold cross validation: how to filter data based on a randomly generated integer variable in Stata

下面的内容看起来很明显,但它的行为并不像我期望的那样。我想在不使用 SCC 包的情况下进行 k 折交叉验证,并认为我可以过滤我的数据和 运行 我自己对子集的回归。

首先,我生成一个具有 1 到 5 之间随机整数的变量(5 折交叉验证),然后循环遍历每个折数。我想按折叠数过滤数据,但使用布尔过滤器无法过滤任何内容。为什么?

奖金:捕获所有测试 MSE 并对其进行平均的最佳方法是什么?在 Python 中,我只会制作一个列表或一个 numpy 数组并取平均值。

gen randint = floor((6-1)*runiform()+1)

recast int randint

forval b = 1(1)5 {
    xtreg c.DepVar ///  // training set
    c.IndVar1 ///
    c.IndVar2 ///
    if randint !=`b' ///
    , fe vce(cluster uuid)

    xtreg c.DepVar /// // test set, needs to be performed with model above, not a               
    c.IndVar1 ///      // new model...
    c.IndVar2 ///
    if randint ==`b' ///
    , fe vce(cluster uuid)
}

编辑:测试集需要在模型适合训练集的情况下执行。我更改了代码中的注释以反映这一点。

最终过滤问题的解决方案是我在引号中使用标量来定义边界,我有:

replace randint = floor((`varscalar'-1)*runiform()+1)

而不只是

replace randint = floor((varscalar-1)*runiform()+1)

何时何地在 Stata 中使用引号让我感到困惑。我不能只在循环中使用 varscalar,我必须使用 `=varscalar',但出于某种原因我可以使用 varscalar - 1 并获得预期的结果。有趣的是,我不能使用

replace randint = floor((`varscalar')*runiform()+1)

我想我应该使用

replace randint = floor((`=varscalar')*runiform()+1)

那为什么可以用带负一不带等号的版本呢??

下面的回答还是非常有帮助的,我从中学到了很多。

事实上,这里发生了两件不一定直接相关的事情。 1) 如何使用随机生成的整数值过滤数据和 2) k 折交叉验证程序。

对于第一个,我将在下面留下一个示例,它可以帮助您使用 Stata 和一些可以轻松转移到其他问题(例如矩阵生成和操作来存储指标)的工具来解决问题。但是,我不会将您的代码草图和我的示例称为“k 折交叉验证”,主要是因为它们在测试和训练数据中都符合模型。尽管如此,严格来说,情况应该是,模型应该在训练数据中进行训练,并使用这些参数,评估模型在测试数据中的性能。

有关程序的进一步参考 Scikit-learn has done brilliant work explaining it,其中包括多个可视化效果。

话虽这么说,但这里有些东西可能会有所帮助。

clear all
set seed 4
set obs 100
*Simulate model
gen x1 = rnormal()
gen x2 = rnormal()
gen y = 1 + 0.5 * x1 + 1.5 *x2 + rnormal()
gen byte randint = runiformint(1, 5)
tab randint
/*
    randint |      Freq.     Percent        Cum.
------------+-----------------------------------
          1 |         17       17.00       17.00
          2 |         18       18.00       35.00
          3 |         21       21.00       56.00
          4 |         19       19.00       75.00
          5 |         25       25.00      100.00
------------+-----------------------------------
      Total |        100      100.00 
*/
// create a matrix to store results
matrix res = J(5,4,.)
matrix colnames res = "R2_fold"  "MSE_fold" "R2_hold"  "MSE_hold"
matrix rownames res ="1" "2" "3" "4" "5"
// show formated empty matrix 
matrix li res
/*
res[5,4]
    R2_fold  MSE_fold   R2_hold  MSE_hold
1         .         .         .         .
2         .         .         .         .
3         .         .         .         .
4         .         .         .         .
5         .         .         .         .
*/

// loop over different samples
forvalues b = 1/5 {
    // run the model using fold == `b'
    qui reg y x1 x2 if randint ==`b' 
    // save R squared training
    matrix res[`b', 1] = e(r2) 
    // save rmse training
    matrix res[`b', 2] = e(rmse)  

    // run the model using fold != `b'
    qui reg y x1 x2 if randint !=`b' 
    // save R squared training (?)
    matrix res[`b', 3] = e(r2)
    // save rmse testing (?)
    matrix res[`b', 4] = e(rmse)  
}

// Show matrix with stored metrics
mat li res 
/*
res[5,4]
     R2_fold   MSE_fold    R2_hold   MSE_hold
1  .50949187  1.2877728  .74155365  1.0070531
2  .89942838  .71776458  .66401888   1.089422
3  .75542004  1.0870525  .68884359  1.0517139
4  .68140328  1.1103964  .71990589  1.0329239
5  .68816084  1.0017175  .71229925  1.0596865
*/

// some matrix algebra workout to obtain the mean of the metrics
mat U = J(rowsof(res),1,1)
mat sum = U'*res
/* create vector of column (variable) means */
mat mean_res = sum/rowsof(res)
// show the average of the metrics acros the holds
mat li mean_res
/*
mean_res[1,4]
      R2_fold   MSE_fold    R2_hold   MSE_hold
c1  .70678088  1.0409408  .70532425  1.0481599
*/