Voici une fonction Python qui divise une trame de données Pandas en trames de données d'entraînement, de validation et de test avec un échantillonnage stratifié. Il effectue cette division en appelant train_test_split()deux fois la fonction de scikit-learn .
import pandas as pd
from sklearn.model_selection import train_test_split
def split_stratified_into_train_val_test(df_input, stratify_colname='y',
                                         frac_train=0.6, frac_val=0.15, frac_test=0.25,
                                         random_state=None):
    '''
    Splits a Pandas dataframe into three subsets (train, val, and test)
    following fractional ratios provided by the user, where each subset is
    stratified by the values in a specific column (that is, each subset has
    the same relative frequency of the values in the column). It performs this
    splitting by running train_test_split() twice.
    Parameters
    ----------
    df_input : Pandas dataframe
        Input dataframe to be split.
    stratify_colname : str
        The name of the column that will be used for stratification. Usually
        this column would be for the label.
    frac_train : float
    frac_val   : float
    frac_test  : float
        The ratios with which the dataframe will be split into train, val, and
        test data. The values should be expressed as float fractions and should
        sum to 1.0.
    random_state : int, None, or RandomStateInstance
        Value to be passed to train_test_split().
    Returns
    -------
    df_train, df_val, df_test :
        Dataframes containing the three splits.
    '''
    if frac_train + frac_val + frac_test != 1.0:
        raise ValueError('fractions %f, %f, %f do not add up to 1.0' % \
                         (frac_train, frac_val, frac_test))
    if stratify_colname not in df_input.columns:
        raise ValueError('%s is not a column in the dataframe' % (stratify_colname))
    X = df_input # Contains all columns.
    y = df_input[[stratify_colname]] # Dataframe of just the column on which to stratify.
    # Split original dataframe into train and temp dataframes.
    df_train, df_temp, y_train, y_temp = train_test_split(X,
                                                          y,
                                                          stratify=y,
                                                          test_size=(1.0 - frac_train),
                                                          random_state=random_state)
    # Split the temp dataframe into val and test dataframes.
    relative_frac_test = frac_test / (frac_val + frac_test)
    df_val, df_test, y_val, y_test = train_test_split(df_temp,
                                                      y_temp,
                                                      stratify=y_temp,
                                                      test_size=relative_frac_test,
                                                      random_state=random_state)
    assert len(df_input) == len(df_train) + len(df_val) + len(df_test)
    return df_train, df_val, df_test
Voici un exemple de travail complet.
Considérez un ensemble de données qui a une étiquette sur laquelle vous souhaitez effectuer la stratification. Cette étiquette a sa propre distribution dans l'ensemble de données d'origine, disons 75% foo, 15% baret 10% baz. Maintenant, divisons l'ensemble de données en train, validation et test en sous-ensembles en utilisant un ratio 60/20/20, où chaque division conserve la même distribution des étiquettes. Voir l'illustration ci-dessous:

Voici l'exemple d'ensemble de données:
df = pd.DataFrame( { 'A': list(range(0, 100)),
                     'B': list(range(100, 0, -1)),
                     'label': ['foo'] * 75 + ['bar'] * 15 + ['baz'] * 10 } )
df.head()
#    A    B label
# 0  0  100   foo
# 1  1   99   foo
# 2  2   98   foo
# 3  3   97   foo
# 4  4   96   foo
df.shape
# (100, 3)
df.label.value_counts()
# foo    75
# bar    15
# baz    10
# Name: label, dtype: int64
Maintenant, appelons la split_stratified_into_train_val_test()fonction ci-dessus pour obtenir des trames de données d'entraînement, de validation et de test suivant un rapport 60/20/20.
df_train, df_val, df_test = \
    split_stratified_into_train_val_test(df, stratify_colname='label', frac_train=0.60, frac_val=0.20, frac_test=0.20)
Les trois dataframes df_train, df_valet df_testcontiennent toutes les lignes d'origine, mais leurs tailles suivront le rapport ci-dessus.
df_train.shape
#(60, 3)
df_val.shape
#(20, 3)
df_test.shape
#(20, 3)
De plus, chacune des trois divisions aura la même répartition du label, à savoir 75% foo, 15% baret 10% baz.
df_train.label.value_counts()
# foo    45
# bar     9
# baz     6
# Name: label, dtype: int64
df_val.label.value_counts()
# foo    15
# bar     3
# baz     2
# Name: label, dtype: int64
df_test.label.value_counts()
# foo    15
# bar     3
# baz     2
# Name: label, dtype: int64