Partitionnement de Dataset
Vue d'ensemble
Les partitions train/validation/test sont la garde-fou la plus importante contre le surapprentissage et la fuite de données. Une mauvaise partition invalide tout ce qui en découle. Partitionner une fois, verrouiller la partition, et ne jamais laisser les données de test influencer aucune décision.
Quand utiliser
Utilisez cette skill quand :
- Préparer les données pour l'apprentissage supervisé.
- Concevoir des protocoles d'évaluation pour la comparaison de modèles.
- Configurer des folds de validation croisée.
- Assurer l'absence de fuite de données entre les partitions.
Ne pas utiliser pour :
- Évaluation en apprentissage non supervisé — des règles différentes s'appliquent.
- Prévision de séries temporelles avec backtesting — utilisez les skills
dartsouprophet. - Nettoyage de données — utilisez
dataset-cleaningavant le partitionnement.
Stratégies de partitionnement
1. Partitionnement Aléatoire Standard (IID)
from sklearn.model_selection import train_test_split
# Partition unique (graine fixe, stratifiée)
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
stratify=y,
random_state=42 # NE JAMAIS changer cela à la légère
)
# Train / validation / test (deux étapes)
X_temp, X_test, y_temp, y_test = train_test_split(
X, y, test_size=0.15, stratify=y, random_state=42
)
X_train, X_val, y_train, y_val = train_test_split(
X_temp, y_temp, test_size=0.1765, stratify=y_temp, random_state=42
)
# Résultat : 70% train, 15% val, 15% test
2. Partitionnement Stratifié (Déséquilibre de classe)
# Stratifier sur la cible ET les attributs protégés
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
stratify=df[['target', 'gender', 'region']].apply(tuple, axis=1),
random_state=42
)
3. Partitionnement au Niveau du Groupe (Pas de Contamination Croisée)
from sklearn.model_selection import GroupShuffleSplit
# Quand les lignes du même groupe DOIVENT rester ensemble
# Exemple : plusieurs échantillons par patient
gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
train_idx, test_idx = next(gss.split(X, y, groups=df['patient_id']))
X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
4. Partitionnement de Série Temporelle (Pas de Fuite Future)
# Partitionnement chronologique — NE JAMAIS mélanger les données temporelles
df = df.sort_values('timestamp')
split_idx = int(len(df) * 0.8)
train = df.iloc[:split_idx]
test = df.iloc[split_idx:]
# Pour plusieurs fenêtres de backtesting :
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, test_idx in tscv.split(X):
X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
# Chaque fold utilise des données anciennes pour l'entraînement, plus récentes pour le test
Configuration de Validation Croisée
from sklearn.model_selection import StratifiedKFold, RepeatedStratifiedKFold
# 5-fold standard
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# Répétée pour les petits datasets
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=3, random_state=42)
Liste de vérification Prévention de Fuite
Avant de verrouiller la partition, vérifiez :
- Pas de fuite d'ID : la même entité n'apparaît pas en train et test.
- Pas de fuite temporelle : tous les timestamps d'entraînement précèdent tous les timestamps de test.
- Pas de fuite de cible : aucune feature dérivée des données de test (y compris imputation, mise à l'échelle, encodage).
- Pas de fuite de groupe : les groupes (patients, utilisateurs, expériences) sont complètement dans une seule partition.
- Stratification préservée : distribution de la cible similaire entre les partitions.
# Validation de la distribution de partition
for split_name, split_df in [('train', train_df), ('val', val_df), ('test', test_df)]:
print(f"{split_name}: {split_df['target'].value_counts(normalize=True).to_dict()}")
# Vérification d'intégrité du groupe
train_groups = set(train_df['group_id'])
test_groups = set(test_df['group_id'])
assert len(train_groups & test_groups) == 0, "Fuite de groupe détectée !"
Verrouillage de la Partition
Une fois créée, sauvegardez les affectations de partition de manière immuable :
# Ajouter colonne de partition et sauvegarder
df['split'] = 'train'
df.loc[val_idx, 'split'] = 'val'
df.loc[test_idx, 'split'] = 'test'
# Sauvegarder avec version
df.to_parquet('dataset_v1.0.0_with_splits.parquet', index=False)
# Sauvegarder les indices de partition pour la reproductibilité
np.savez('split_indices_v1.0.0.npz',
train=train_idx, val=val_idx, test=test_idx)
Porte de Qualité
Une partition est valide quand :
- Chaque ligne appartient exactement à une partition.
- Aucune fuite de groupe, entité ou timestamp n'existe.
- La distribution de la cible est cohérente entre les partitions (dans la tolérance).
- Les artefacts de partition (indices, affectations) sont sauvegardés et versionnés.
- Toutes les décisions de prétraitement sont prises en utilisant uniquement l'ensemble d'entraînement.