Prevent data leakage by always performing the train-test split before any feature engineering or preprocessing, and by fitting all transformers only on the training data. Then, apply these fitted transformers to both the training and test sets.
Here’s a breakdown of best practices:
1. Split Data First: Your initial step must be to divide your dataset into training and testing sets. This ensures that the test set remains completely unseen during any subsequent data preparation or model training.
```python
from sklearn.model_selection import train_test_split
import pandas as pd
# Assuming X is your features DataFrame and y is your target Series
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y # stratify for classification tasks
)
```
2. Fit Transformers on Training Data Only: Any statistical calculation (e.g., mean, standard deviation for scaling; unique categories for encoding; imputation values) needed for feature engineering must be derived solely from the training data. Apply the fit_transform() method to the training set and transform() to the test set.
```python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # Fit on train, then transform train
X_test_scaled = scaler.transform(X_test) # Transform test using parameters learned from train
```
3. Utilize Pipelines for Consistency: Scikit-learn's Pipeline and ColumnTransformer are critical tools for encapsulating preprocessing steps. A pipeline ensures that the fit() method is called only on the training data for all steps, and transform() is called appropriately on both training and test data (or during cross-validation).
```python
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
# Example pipeline for numerical features
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler())
])
# Integrate into a full model pipeline
model_pipeline = Pipeline(steps=[
('preprocessor', numerical_transformer), # Or ColumnTransformer for mixed types
('classifier', LogisticRegression())
])
model_pipeline.fit(X_train, y_train)
y_pred = model_pipeline.predict(X_test)
```
4. Cross-Validation within Pipelines: When performing cross-validation, always ensure that your preprocessing steps are inside the cross-validation loop. A Pipeline handles this automatically when used with GridSearchCV or cross_val_score, preventing data from one fold from leaking into another during preprocessing.
5. Handle Time-Series Data Separately: For time-series data, a standard random train_test_split is inappropriate. Use sklearn.model_selection.TimeSeriesSplit to maintain the temporal order, ensuring that your model is only trained on past data to predict future events.