且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样

更新时间:2022-09-19 12:02:02

1.4 基本抽样、分层抽样和一致抽样
相当多的数据分析人员蔑视采样。通常要想处理整个数据集,只有改进模型。实际上,在这两者之间进行权衡会很复杂。首先,可以在抽样的数据集上建立更复杂的模型,特别是模型的时间复杂度是非线性(比如在大多数情况下至少是N* log(N))时更是如此。用更快的周期构建模型可让用户能更快地迭代模型,使其按***方式收敛。在很多情况下,若在整个数据集上建立模型,则在改进预测精度时可能会增加操作时间。
若一次只关注一个子问题,则可更好地理解整个问题域,因此在一些具体情形下可将滤波与采样适当结合。在许多情况下,分区是算法(比如稍后要介绍的决策树)的基础。通常,问题的本质要求重点专注原始数据的子集(比如,网络安全分析往往集中在一组特定的IP而不是整个互联网),因为基于这样的假设可以加快迭代。如果建模方法是正确的,那么在一开始就包含网络中所有IP集可能会让问题复杂化。
当处理罕见事件(如广告技术领域(ADTECH)中的点击率)时,需要使用不同的概率对正例和反例进行抽样,有时也叫作过采样(oversampling),这样可在短时间内得到更好的预测结果。
从根本上讲,对每一行数据抽样相当于抛硬币(或者叫随机数生成器)。因此,这非常像一个流过滤操作,这里的过滤是在一个系统添加的列上进行的,该列的值是随机数。具体代码如下所示:
《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样

以上代码可以正常运行,但是有几个缺点:
虽然通常会取原始文件行数的5%,但在处理之前并不知道该文件的行数。
抽样结果具有不确定性,很难在测试或验证时再重复这个过程。
为了解决第一个问题,需要给函数传入一个更复杂的对象,因为需要在遍历原始列表的过程中维持状态,这会导致原来的算法不具有函数式和并行化(稍后会讨论):

《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样
《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样

上面的代码将输出numLines行。分层抽样(stratified sampling)与蓄水池抽样(reservoir sampling)相似,对于按其他属性定义的所有层,它能得到相同的输入/输出行比率。该算法的实现过程为:将原始数据集分成对应的N个子集,执行蓄水池抽样,然后合并结果。MLlib库(将在第3章中讨论)已经实现了分层抽样算法:
《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样

还有一个更微妙的方法。有时候需要在多个数据集上得到值一致的子集,以此实现再现性(reproducibility)或与另一个采样数据集建立联系。一般来讲,如果对两个数据集采样,结果会包含多个ID的随机子集,它们之间很少有(或者没有)交集。可用加密哈希函数来解决该问题,哈希函数(例如MD5或SHA1)至少在理论上会得到统计意义不相关的比特序列。这里使用的MurmurHash函数在scala.util.hashing包中。
《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样
《Scala机器学习》一一1.4 基本抽样、分层抽样和一致抽样

这个函数保证返回完全相同的记录子集(这些记录是基于第一个字段的值),即要么返回所有与第一个字段某个值相等的记录,要么就不返回。这将得到只有约十六分之一的原始样本。hash的范围是0到65 535。
MurmurHash是什么函数?它不是一个加密哈希函数!
与MD5和SHA1之类的加密哈希函数不同,MurmurHash不是专门被设计成难以找到一个逆函数的哈希函数。但它真的非常高效,这正是该例子所关心的。