02.关于sklean.StratifiedShuffleSplit()函数的粗浅解释

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

      这是函数的原型:

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

      首先,先解释一下这个函数是干什么用的? 打乱数据集用的,类似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个数据进行训练和测试集划分
            2.设置train_size=0.8 test_size=0.2
            3.train_num=num*train_size=8            test_num=num*test_size=2
            4.总计10个数据,进行划分以后其中8个是训练数据,剩余2个是测试数据

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

      这是啥? 不懂。 这是我的第一感觉, 虽然上面的描述知道,但是如果我改个参数,比如test_size,就会发现很多奇葩的报错(我所遇到的错误会贴在下面),后面我也一一整理并分析其原因。

      先根据上面说的,看个例子:
在这里插入图片描述
      先分析上面这个例子:弄懂上面参数的含义。

      n_splits是train/test对的组数, 参数中的6指的是,目前随机打乱数据集得到train和test数据对6组,也就是6行(每一行都由训练数据集和测试数据集中的数据在原始数据集中的下标构成)。 但这个分成train和test是考虑分层抽样的,不是随机分的, 后面将解释如何进行分层抽样。
      参数test_size=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]

      让我们先关注语句:

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

      首先根据我们上面的分析,n_splits=5, test_size=5就是说我把数据集随机分,最后得到的训练集/测试集对是5组,每一组测试集占的比例是0.5.并且按照分层抽样的方法划分数据集。其中的具体过程如下:

      所谓分层抽样,就是按照比例选取数据, 上面每一组训练集/测试集对的生成总计经历如下过程:
      第一步, 根据test_splits=0.5可知,每一组测试集和训练集数据规模比例为1:1。那么我们就可以先尝试进行划分,当前有5个数据样本, 按照严格的1:1的比例,那么得到训练集和测试集的数据个数分别为2.5和2.5。这显然不合理,因为不存在0.5个数据样本。 所以测试集样本数目会上取整变成了3, 训练集数据样本数变成了2, 以此类推, 每一组的划分方式不尽相同。其中参数n_split=5表示一共进行5次这种划分。但是在实际的项目当中,我们仅需要划分一次。也就是设置n_split严格等于1即可。
      第二步, 分层抽样,我们已经有了每一组训练集应该2个,测试集应该3个,那么这个2个和3个应该怎么划分呢? 记住采用了分层抽样 ,是这样分的, 来看一下类别比例,我们发现,Y里面3个0,2个1,也就是3个负样本,2个正样本,比例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个正样本 ,是随机分配的。

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

Error01:令 test_size = 0.2

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个样本,按照正负比例的话,肯定只选择负类样本,那么我们这个测试集的意义何在? 我们测试不就是想测测训练的模型的误差吗? 哪里有光拿负类测试的? 所以,这个报错就是说,你的测试集训练样本数少于类别数,没法测试。

Error02:令 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名女的,这样就有很大的偏差了。 所以随机抽样的方式就不好了。

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

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

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

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值