File size: 6,081 Bytes
bd41331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# src/models/train_model.py
"""

Main training script for fraud detection model

"""
import pandas as pd
import numpy as np
import logging
import warnings
from sklearn.impute import SimpleImputer
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline as ImbPipeline
import xgboost as xgb
from catboost import CatBoostClassifier
import lightgbm as lgb
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression

from src.config.parameters import (
    DATA_PARAMS, MODEL_PARAMS, SMOTE_PARAMS, 
    ARTIFACT_PATHS, RAW_DATA_DIR
)
from src.utils.data_preprocessing import DataPreprocessor
from src.utils.feature_engineering import FeatureEngineer
from src.utils.model_utils import ModelTrainer, save_model_artifacts
from src.utils.monitoring import setup_logging, log_model_performance

warnings.filterwarnings('ignore')

def main():
    """Main training pipeline"""
    # Setup logging
    logger = setup_logging()
    logger.info("="*50)
    logger.info("FRAUD DETECTION MODEL TRAINING STARTED")
    logger.info("="*50)
    
    try:
        # 1. Data Loading and Preprocessing
        logger.info("Step 1: Data Loading and Preprocessing")
        preprocessor = DataPreprocessor()
        
        # Load data
        df = preprocessor.load_data(DATA_PARAMS['raw_data_path'])
        
        # Basic preprocessing
        df = preprocessor.basic_preprocessing(df)
        
        # 2. Feature Engineering
        logger.info("Step 2: Feature Engineering")
        feature_engineer = FeatureEngineer()
        df_processed = feature_engineer.engineer_features(df, is_training=True)
        
        # Update preprocessor with feature engineering artifacts
        preprocessor.scaler = feature_engineer.scaler
        preprocessor.legit_amount_mean = feature_engineer.legit_amount_mean
        preprocessor.amount_bin_edges = feature_engineer.amount_bin_edges
        preprocessor.top_corr_features = feature_engineer.top_corr_features
        
        # Also save the time scaler
        if hasattr(feature_engineer, 'time_scaler'):
            preprocessor.time_scaler = feature_engineer.time_scaler
        
        # 3. Train-Test Split
        logger.info("Step 3: Train-Test Split")
        X_train, X_test, y_train, y_test = preprocessor.split_data(df_processed)
        
        # Save preprocessing artifacts
        preprocessor.save_preprocessing_artifacts(df_processed, X_train)
        
        # 4. Model Training Setup
        logger.info("Step 4: Model Training Setup")
        trainer = ModelTrainer()
        
        # Define base models for stacking
        base_models = [
            ('xgb', xgb.XGBClassifier(**MODEL_PARAMS['xgb'])),
            ('cat', CatBoostClassifier(**MODEL_PARAMS['catboost'])),
            ('lgb', lgb.LGBMClassifier(**MODEL_PARAMS['lightgbm']))
        ]
        
        meta_model = LogisticRegression(**MODEL_PARAMS['logistic_regression'])
        stacking_classifier = StackingClassifier(
            estimators=base_models, 
            final_estimator=meta_model, 
            cv=5
        )
        
        # Create pipeline with SMOTE
        pipeline = ImbPipeline([
            ('imputer', SimpleImputer(strategy='median')),
            ('smote', SMOTE(**SMOTE_PARAMS)),
            ('classifier', stacking_classifier)
        ])
        
        # 5. Model Training and Evaluation
        logger.info("Step 5: Model Training and Evaluation")
        
        # Train and evaluate with MLflow logging
        results = trainer.train_and_log_model(
            model=pipeline,
            X_train=X_train,
            y_train=y_train,
            X_test=X_test,
            y_test=y_test,
            model_name="Stacking_Ensemble_SMOTE",
            parameters={
                **MODEL_PARAMS,
                **SMOTE_PARAMS,
                'pipeline_steps': ['imputer', 'smote', 'stacking_classifier']
            }
        )
        
        # 6. Save Model Artifacts
        logger.info("Step 6: Saving Model Artifacts")
        save_model_artifacts(
            model=results['model'],
            optimal_threshold=results['optimal_threshold']
        )
        
        # 7. Log Final Results
        logger.info("Step 7: Final Results Summary")
        log_model_performance(
            metrics={k: v for k, v in results['test_metrics'].items() 
                     if isinstance(v, (int, float))},
            model_name="Final Stacking Ensemble"
        )
        
        logger.info("="*50)
        logger.info("TRAINING COMPLETED SUCCESSFULLY!")
        logger.info("="*50)
        
        # Print summary
        print("\n" + "="*60)
        print("FRAUD DETECTION MODEL TRAINING SUMMARY")
        print("="*60)
        print(f"Dataset Shape: {df.shape}")
        print(f"Features after Engineering: {X_train.shape[1]}")
        print(f"Training Samples: {X_train.shape[0]}")
        print(f"Test Samples: {X_test.shape[0]}")
        print(f"Fraud Cases (Train): {y_train.sum()}")
        print(f"Fraud Cases (Test): {y_test.sum()}")
        print("\nKey Metrics (Test Set):")
        print(f"  Accuracy:  {results['test_metrics']['accuracy']:.4f}")
        print(f"  Precision: {results['test_metrics']['precision']:.4f}")
        print(f"  Recall:    {results['test_metrics']['recall']:.4f}")
        print(f"  F1-Score:  {results['test_metrics']['f1']:.4f}")
        print(f"  ROC-AUC:   {results['test_metrics']['roc_auc']:.4f}")
        print(f"  PR-AUC:    {results['test_metrics']['pr_auc']:.4f}")
        print(f"Optimal Threshold: {results['optimal_threshold']:.4f}")
        print(f"\nModel saved to: {ARTIFACT_PATHS['model_pipeline']}")
        print("="*60)
        
        return results
        
    except Exception as e:
        logger.error(f"Training failed with error: {str(e)}", exc_info=True)
        raise


if __name__ == "__main__":
    results = main()