24 | 离线评估:常用的推荐系统离线评估方法有哪些?
那这个所谓的“效果”到底指的是什么呢?我们一般用什么方法来衡量这个“效果”呢?我们又应该如何根据效果评估的结果来更新模型呢?这就是模型评估篇要解决的问题。
离线评估的主要方法
常用的离线评估方法主要有五种,分别是:Holdout 检验、交叉检验、自助法、时间切割、离线 Replay。接下来,我们一一来看。
Holdout 检验、交叉检验和自助法
Holdout 检验是最基础、最常用的离线评估方法,它将原始样本集随机划分为训练集和测试集两部分,通过随机分配样本比例来评估模型的性能。Holdout 检验的关键词是“随机”,因为样本的划分是随机的。为了消除随机性,我们使用交叉验证来评估模型性能,该方法需要先将样本集划分为 k 个大小相等的样本子集,然后依次进行 k 次模型训练和评估,最后取所有 k 次评估指标的平均值作为最终的评估指标。当样本规模比较小时,划分训练集和测试集可能会导致训练集进一步减小,影响模型的训练效果。自助法可以在一定程度上解决这个问题,但需要注意其可能改变原有数据的分布,导致模型产生一定程度的偏差。
时间切割
在预测过程中,可能会存在作弊现象,因为训练模型时使用了 TN 时间窗口的数据,但在预测时使用了 TL 时间窗口的数据,这会导致结果与预测结果不同,就像有一个时光机穿越到了明天,知道股票会涨,但又穿越回来预测说明天股票会涨,这样的行为被称为“作弊”。为了避免这种情况,通常会使用时间切割的方案来划分训练集和测试集,以确保训练集和测试集的比例在 3:1 到 10:1 之间。
离线 Replay
基于 Spark 的离线评估方法实践
val Array(trainingSamples, testSamples) = samples.randomSplit(Array(0.9, 0.1))
val cv = new CrossValidator()
.setEstimator(modelPipeline)
.setEvaluator(new BinaryClassificationEvaluator)
.setEstimatorParamMaps(paramGrid)
.setNumFolds(10) // Use 3+ in practice
val cvModel = cv.fit(training)
这段代码中有三个关键参数,一是 setEstimator,这是我们要评估的对象,它需要把我们构建的模型 pipeline 设置进去;二是 setEvaluator,它用来设置评估所用的方法和指标;三是 setNumFolds,它设置的是交叉检验中 k 的值,也就是把样本分成多少份用于交叉检验。本质上 Spark 的 CrossValidator 其实是通过交叉检验来选择模型的最优参数,但也可以通过模型中 cvModel.avgMetrics 参数查看模型的评估指标。
接下来,我们来实现时间切割方法。既然是要按时间划分,如果你知道样本的时间跨度,直接用 where 语句就可以把训练集和测试集划分开了,这也是我最推荐的方法,因为它最高效,不用专门判断切割点。如果你不知道样本的时间跨度,就要按照时间求取样本的分位数。具体来说就是,通过 Spark 的 approxQuantile 函数,我们可以找到划分样本集为 8:2 的训练集和测试集的时间戳的值。那么接下来我们根据这个值通过 where 语句划分就可以了。我把这个过程的关键代码贴到了下面,供你参考。完整的源代码,你可以参考 com.wzhe.sparrowrecsys.offline.spark.featureeng.FeatureEngForRecModel 中的 splitAndSaveTrainingTestSamplesByTimeStamp 函数。
//找到时间切割点
val quantile = smallSamples.stat.approxQuantile("timestampLong", Array(0.8), 0.05)
val splitTimestamp = quantile.apply(0)
//切割样本为训练集和测试集
val training = smallSamples.where(col("timestampLong") <= splitTimestamp).drop("timestampLong")
val test = smallSamples.where(col("timestampLong") > splitTimestamp).drop("timestampLong")
小结
这节课,我们学习了五种主流的推荐模型离线评估方法,它们分别是 Holdout 检验、交叉检验、自助法、时间切割和离线 Replay。其中,Holdout 检验最简单常用,它通过随机划分的方式把样本集划分成训练集和测试集。而交叉检验的评估效果更加稳定准确,它通过划分样本集为 k 份,再进行 k 次评估取平均的方式得到最终的评估指标。自助法是为了解决样本量过少而提出的,它可以通过有放回采样的方式扩充训练集,但有改变数据本身分布的风险。而时间切割法在某个时间点上把样本分成前后两份,分别用于模型训练和评估,避免引入未来信息。最后是离线 Replay,它通过仿真线上模型更新过程来进行评估,是最接近线上环境的离线评估方法,但实现起来比较复杂。总之,各种评估方法都有优有劣,你需要根据实践中的侧重点选择使用,我把它们的优缺点也总结在了文稿的表格里,方便你进行对比。