【问题标题】:Stratified Train/Test-split in scikit-learnscikit-learn 中的分层训练/测试拆分
【发布时间】:2015-06-08 21:39:19
【问题描述】:

我需要将我的数据分成训练集 (75%) 和测试集 (25%)。我目前使用以下代码执行此操作:

X, Xt, userInfo, userInfo_train = sklearn.cross_validation.train_test_split(X, userInfo)   

但是,我想对我的训练数据集进行分层。我怎么做?我一直在研究 StratifiedKFold 方法,但不允许我指定 75%/25% 的拆分,只对训练数据集进行分层。

【问题讨论】:

    标签: python scikit-learn


    【解决方案1】:

    [0.17 更新]

    查看sklearn.model_selection.train_test_split的文档:

    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                        stratify=y, 
                                                        test_size=0.25)
    

    [/更新为 0.17]

    有一个拉取请求here。 但你可以简单地做train, test = next(iter(StratifiedKFold(...))) 并根据需要使用训练和测试索引。

    【讨论】:

    • @AndreasMueller 有没有简单的方法对回归数据进行分层?
    • @Jordan 在 scikit-learn 中没有实现任何东西。我不知道标准方法。我们可以使用百分位数。
    • @AndreasMueller 您是否见过这种方法比 StratifiedShuffleSplit 慢得多的行为?我使用的是 MNIST 数据集。
    • @activatedgeek 这似乎很奇怪,因为 train_test_split(...stratify=) 只是调用 StratifiedShuffleSplit 并进行第一次拆分。随时使用可重现的示例在跟踪器上打开问题。
    • @AndreasMueller 实际上我没有打开一个问题,因为我有一种强烈的感觉我做错了什么(即使它只有 2 行)。但如果我今天仍然能够多次重现它,我会这样做!
    【解决方案2】:

    TL;DR : 使用 StratifiedShuffleSplittest_size=0.25

    Scikit-learn 为分层拆分提供了两个模块:

    1. StratifiedKFold :该模块可用作直接 k 折交叉验证运算符:因为它将设置 n_folds 训练/测试集,从而使两个类中的类均等平衡。

    这里有一些代码(直接来自上面的文档)

    >>> skf = cross_validation.StratifiedKFold(y, n_folds=2) #2-fold cross validation
    >>> len(skf)
    2
    >>> for train_index, test_index in skf:
    ...    print("TRAIN:", train_index, "TEST:", test_index)
    ...    X_train, X_test = X[train_index], X[test_index]
    ...    y_train, y_test = y[train_index], y[test_index]
    ...    #fit and predict with X_train/test. Use accuracy metrics to check validation performance
    
    1. StratifiedShuffleSplit:这个模块创建了一个具有同样平衡(分层)类的单一训练/测试集。本质上,这就是您想要的n_iter=1。您可以在此处提及与train_test_split 相同的测试大小

    代码:

    >>> sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
    >>> len(sss)
    1
    >>> for train_index, test_index in sss:
    ...    print("TRAIN:", train_index, "TEST:", test_index)
    ...    X_train, X_test = X[train_index], X[test_index]
    ...    y_train, y_test = y[train_index], y[test_index]
    >>> # fit and predict with your classifier using the above X/y train/test
    

    【讨论】:

    • 请注意,从 0.18.x 开始,n_iter 对于 StratifiedShuffleSplit 应该是 n_splits - 并且它的 API 略有不同:scikit-learn.org/stable/modules/generated/…
    • 如果 y 是 Pandas 系列,请使用 y.iloc[train_index], y.iloc[test_index]
    • @Owlright 我尝试使用熊猫数据框,而 StratifiedShuffleSplit 返回的索引不是数据框中的索引。 dataframe index: 2,3,5the first split in sss:[(array([2, 1]), array([0]))]:(
    • @tangy 为什么这是一个 for 循环?是不是在调用X_train, X_test = X[train_index], X[test_index] 行时会覆盖X_trainX_test?那为什么不只是一个next(sss)
    • 如果你遇到“TypeError: 'StratifiedShuffleSplit' object is not iterable”,或许这篇文章可以帮到你:stackoverflow.com/questions/53899066/…
    【解决方案3】:

    您可以使用 Scikit learn 中提供的 train_test_split() 方法简单地做到这一点:

    from sklearn.model_selection import train_test_split 
    train, test = train_test_split(X, test_size=0.25, stratify=X['YOUR_COLUMN_LABEL']) 
    

    我还准备了一个简短的 GitHub Gist,展示了 stratify 选项的工作原理:

    https://gist.github.com/SHi-ON/63839f3a3647051a180cb03af0f7d0d9

    【讨论】:

      【解决方案4】:

      这是一个连续/回归数据的示例(直到this issue on GitHub 得到解决)。

      min = np.amin(y)
      max = np.amax(y)
      
      # 5 bins may be too few for larger datasets.
      bins     = np.linspace(start=min, stop=max, num=5)
      y_binned = np.digitize(y, bins, right=True)
      
      X_train, X_test, y_train, y_test = train_test_split(
          X, 
          y, 
          stratify=y_binned
      )
      
      • 其中start 是最小值,stop 是连续目标的最大值。
      • 如果您不设置 right=True,那么它或多或少会将您的最大值设为单独的 bin,并且您的拆分总是会失败,因为该额外 bin 中的样本太少。

      【讨论】:

        【解决方案5】:

        除了@Andreas Mueller 接受的答案,只想添加上面提到的@tangy:

        StratifiedShuffleSplit 最接近 train_test_split(stratify = y) 具有以下附加功能:

        1. 默认分层
        2. 通过指定n_splits,重复拆分数据

        【讨论】:

          【解决方案6】:

          StratifiedShuffleSplit 是在我们选择了应该在我们即将生成的所有小数据集中均匀表示的列之后完成的。 '通过保留每个类的样本百分比来进行折叠。'

          假设我们有一个数据集“数据”,其中有一列“季节”,我们希望获得“季节”的偶数表示,那么它看起来像这样:

          from sklearn.model_selection import StratifiedShuffleSplit
          sss=StratifiedShuffleSplit(n_splits=1,test_size=0.25,random_state=0)
          
          for train_index, test_index in sss.split(data, data["season"]):
              sss_train = data.iloc[train_index]
              sss_test = data.iloc[test_index]
          

          【讨论】:

            【解决方案7】:

            因此,最好将数据集拆分为训练集和测试集,以在每个类中保留与原始数据集中观察到的相同比例的示例。

            这称为分层训练测试拆分。

            我们可以通过将“stratify”参数设置为原始数据集的 y 分量来实现这一点。 train_test_split() 函数将使用它来确保训练集和测试集在每个类中的示例比例都存在于提供的“y”数组中。

            【讨论】:

              【解决方案8】:
              #train_size is 1 - tst_size - vld_size
              tst_size=0.15
              vld_size=0.15
              
              X_train_test, X_valid, y_train_test, y_valid = train_test_split(df.drop(y, axis=1), df.y, test_size = vld_size, random_state=13903) 
              
              X_train_test_V=pd.DataFrame(X_train_test)
              X_valid=pd.DataFrame(X_valid)
              
              X_train, X_test, y_train, y_test = train_test_split(X_train_test, y_train_test, test_size=tst_size, random_state=13903)
              

              【讨论】:

                【解决方案9】:

                将上面的 @tangy 答案更新为 scikit-learn 的当前版本:0.23.2 (StratifiedShuffleSplit documentation)。

                from sklearn.model_selection import StratifiedShuffleSplit
                
                n_splits = 1  # We only want a single split in this case
                sss = StratifiedShuffleSplit(n_splits=n_splits, test_size=0.25, random_state=0)
                
                for train_index, test_index in sss.split(X, y):
                    X_train, X_test = X[train_index], X[test_index]
                    y_train, y_test = y[train_index], y[test_index]
                

                【讨论】:

                  猜你喜欢
                  • 2017-04-11
                  • 2021-07-26
                  • 2019-04-10
                  • 2020-06-22
                  • 2021-06-20
                  • 2020-10-25
                  • 2018-12-07
                  • 2018-04-22
                  • 2020-01-03
                  相关资源
                  最近更新 更多