StratifiedShuffleSplit()函数的详细理解

今天做一个机器学习项目,预测房价的问题, 里面学习到了一个函数StratifiedShuffleSplit()函数, 参考了一些文章讲解,但是有点模糊,所以自己就又思考了很久,搞明白了这个函数。 这里记录一下。

这是函数的原型:

sklearn.model_selection.StratifiedShuffleSplit(n_splits=10, test_size=’default’, train_size=None, random_state=None)

   
   
  • 1

首先,先解释一下这个函数是干什么用的? 打乱数据集用的,类似train_test_split()函数, 但是和后者不一样,后者是给定一个数据集,比如我10个训练样本, 然后给出一个比例,比如8:2,那么我就随机按照比例把数据集分成8个训练集2个测试集样本。 但是前者不仅要进行随机打乱,最后选取的测试集和训练集的时候还要考虑样本类别的比例, 也就是我们说的分层抽样, train_test_split()可以理解成纯随机抽样,不考虑任何分布, 而StratifiedShuffle()可以理解成分成抽样,考虑类别的分布,还是有点懵,,好吧,后面我会给出详细的演示。

我们先从StratifiedShuffleSplit()函数的参数开始吧:
然后解释一下参数的含义:
参数 n_splits是将训练数据分成train/test对的组数,可根据需要进行设置,默认为10

参数test_size和train_size是用来设置train/test对中train和test所占的比例。例如:
1.提供10个数据num进行训练和测试集划分
2.设置train_size=0.8 test_size=0.2
3.train_num=numtrain_size=8 test_num=numtest_size=2
4.即10个数据,进行划分以后8个是训练数据,2个是测试数据

注*:train_num≥2,test_num≥2 ;test_size+train_size可以小于1*

这是啥? 不懂。 这是我的第一感觉, 虽然上面的描述知道,但是如果我改个参数,比如test_size,就会发现很多奇葩的报错,后面我也一一整理。

先根据上面说的,看个例子:

上面这个是我参考的一篇博客:https://www.bbsmax.com/A/kPzOkPexzx/
可能有人看了上面的代码也好,参数解释也好, 依然没有弄明白这个函数有什么含义,和train_test_split()有啥区别,我也没明白, 但是我后来想明白了,所以我下面有我的分析。

先分析上面这个例子:弄懂上面参数的含义。

  • n_splits是train/test的组数, 6也就是说,我随机打乱数据集得到train和test数据对6组,也就是6行。 但这个分成train和test是考虑分层抽样的,不是随机分的, 后面解释。
  • test_size=0.5 是说,每一行不是一个train和test对吗? 0.5说明,我测试集的数量占的比例是0.5, 也就是训练集合测试集各一半数量。也看到了,得到的结果中,每一行中train和test列表的长度是不是一样呢?但是这个train和test后面的这个列表是啥呢?
  • train_index, test_index是索引下标,也就是第几个训练样本,比如我分析第一行, train[5 4 0 6]的意思是说:我在整个数据集中随机选择第5个 第4个 第0个 第6个训练样本,后面的test是说: 我整个数据集选择剩下的1 2 3 7个样本,后面的都一样。

重点来了,下面正式我对这个函数的理解:

好了,基本上说清了一些参数的含义,但是究竟是怎么分的呢? 拿一个少点的数据集举个例子:


X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1,2]])
Y = np.array([0, 0, 0, 1, 1])
ss = StratifiedShuffleSplit(n_splits=5, test_size=0.5, random_state=seed) 

for train_index, test_index in ss.split(X, Y):
    print(train_index, test_index)
   
 结果:
[4 0] [1 2 3]
[1 4] [0 2 3]
[3 1] [0 2 4]
[2 3] [1 4 0]
[3 0] [4 1 2]

看上面的例子, 比较简单,就是五个训练样本,3个负的2个正的,每个训练样本2个特征。

我们看看

ss = StratifiedShuffleSplit(n_splits=5, test_size=0.5, random_state=seed) 

 
 
  • 1

这个是怎么工作的, 首先根据我们上面的分析,n_splits=5, test_size=5就是说我把数据集随机分,最后得到的训练集/测试集对是5组,每一组测试集占的比例是5.

那么下面的都是啥意思呢? 为啥是这么分的? 讲具体过程:
首先,我前面说过,StratifiedShuffleSplit这个函数是带有分层抽样的, 分层抽样是什么? 后面我会和纯随机抽样合起来举个例子就明白了。 现在知道是分层抽样, 那么怎么分层抽样的?

所谓分层抽样,就是按照比例选取数据, 上面每一组训练集/测试集对其实两步过程:

  • 第一步, 根据test_splits
    我们设置了0.5, 说明,每一组测试集和训练集1:1,那么我们就可以先分了,5个数据样本, 1:1的比例,那么得到训练集和测试集的个数2.5和2.5,但是分数怎么行? 所以测试集会上取整变成了3, 训练集个数变成了2, 所以有2个训练集样本,3个测试集一样, 每一组都是这样算,一共5组(这个书就是n_splits控制)
  • 第二步, 分层抽样
    我们已经有了每一组训练集应该2个,测试集应该3个,那么这个2个和3个应该怎么划分呢? 记住采用了分层抽样 ,是这样分的, 来看一下类别比例,我们发现,Y里面3个0,2个1,也就是3个负样本,2个正样本,比例3:2。
    我们分层抽样的话, 按照这个比例来,训练样本2个,含负样本的个数2 * 3/5=1.2 含正样本的个数2 * 2/5=0.8,四舍五入后,1个负样本,1个正样本。 所以你可以看看,这五组的训练样本,肯定是包含1个正样本,1个负样本。 而测试集那边同理, 3个样本, 负:正=3:2 所以负样本的个数3*3/5=1.8,正样本的个数3 * 2/5=1.2 四舍五入, 2个负样本,1个正样本。
    所以可以看看五组的测试样本里面肯定是2个负样本,1个正样本 ,随机分的。

好了,讲到这里,大理论就讲完了,看看我尝试修改一下,看看出现的错误,就更能明白上面的原理了


ss = StratifiedShuffleSplit(n_splits=5, test_size=0.2, random_state=seed) 

结果:
ValueError: The test_size = 1 should be greater or 
equal to the number of classes = 2

我遇到这个问题的时候,就蒙了, 怎么改了改出现错误了呢? 按照上面一分析,就懂了

首先,我们得先明白,test_size=0.2是说,我们按照4:1的比例划分每一组的训练集/测试集对, 5个数据样本的话,很显然,我们得训练集4个样本,测试集1个样本。 那么,为什么还给我们报错呢? 那个错事啥意思呢?
答: 测试集1个样本,我们可以想想,我们的数据有两类的,正类和负类,而测试集只有1个样本,按照正负比例的话,肯定只选择负类样本,那么我们这个测试集的意义何在? 我们测试不就是想测测训练的模型的误差吗? 哪里有光拿负类测试的? 所以,这个报错就是说,你的测试集训练样本数少于类别数,没法测试。

  • 第二个尝试是:改改类别分布,此时test_size=0.5

  • 
    
    Y = np.array([0, 0, 0, 0, 1])
    
    结果:
    ValueError: The least populated class in y has only 1 member, 
    which is too few. The minimum number of groups for any class 
    cannot be less than 2.
    

    这个问题,是不是又蒙了? 我们还是来分析一下:

    我们根据test_size知道,训练集/测试集样本个数1:1,也就是一半,一半,我们知道5个数据样本,根据上面2个放在训练集,3个放在测试集,这个是没有问题的, 但是再考虑这个正负的比例就出问题了, Y有4个负类,1个正类,比例是4:1, 那么我们训练集样本里面2个样本应该是啥呢? 2*4/5 = 1.6 四舍五入, 2个负类样本,0个正类样本, 这样就出问题了,哪有训练集里面只有负类没有正类的。 所以报错说某个集合里面至少有正类和负类

    所以,经过上面的分析,我们大体知道StratifiedShuffleSplit这个函数究竟是怎么完成分层抽样的了。但是, 这个分层抽样和随机抽样到底有啥区别和如何在实践中使用呢?

    分层抽样 VS 随机抽样

    假设, 某一家公司想要打电话给1000个人来调研几个问题, 他们不会在电话簿中随机抽取1000个人,随机也就是任意抽取1000个, 而是应该保证,我抽取的这1000个人尽量代表全体人口。 例如: 美国人口组成51.3%女性,48.7%男性, 那么如果想进行一场有效的调查,可以试图维持这一比例:即513名女性,487名男性, 这就是分层抽样。 将人口划分为均匀的子集,每个子集被称为一层,然后从每层中抽取正确的实例数量,确保测试集合代表了总的人口比例。 如果使用纯随机抽样,可能会出现偏斜,取出了900名男的,100名女的,这样就有很大的偏差了。 所以随机抽样的方式就不好了。

    如何用呢?

    在机器学习的分类任务中,如果发现样本存在严重的数据不平衡问题,比如正负样本的比例相差的很大,那么这时候就有必要进行分层抽样了。 毕竟如果随机抽样的话,测试样本可能只有一类,如果恰巧是样本很多的那种类别,那么准确率可以达到很大很大,但其实有可能模型并不能把样本少的类给辨别出来,所以这种情况下,随机抽样的隐患很大,可以考虑分层抽样。 也就是是否需要分层抽样,需要考虑样本的类别分布。

    其次,如果不是分类任务,而是其他的任务比如回归任务,也可以使用分层抽样,这时候,可以选择与目标最相关的属性进行分层抽样。比如考虑一个场景,房屋数据集中认为地区收入在房价中占很重要的作用,想分开的训练集和测试集中各种收入所占的比重与原数据集中所占的比重相同,这时候就可以采用分层抽样。

    当数据集样本的个数很大(远远大于属性个数)的时候,其实随机和分层的效果差不多。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值