AI-Flood-Prediction / src /train_model.py
Akash000-ui
Clean history: AI-Driven Flood Prediction System
664a316
Raw
History Blame Contribute Delete
10.7 kB
"""
ML Model Training Pipeline
Train Random Forest classifier for flood prediction
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (
classification_report,
confusion_matrix,
accuracy_score,
roc_auc_score,
roc_curve,
precision_recall_curve,
f1_score
)
import joblib
from pathlib import Path
import sys
# Add configs to path
sys.path.append(str(Path(__file__).parent.parent / 'configs'))
from config import (
PROCESSED_DATA_DIR,
MODELS_DIR,
FEATURE_COLUMNS,
TARGET_COLUMN,
RF_N_ESTIMATORS,
RF_MAX_DEPTH,
RF_MIN_SAMPLES_SPLIT,
RF_MIN_SAMPLES_LEAF,
RF_RANDOM_STATE,
TEST_SIZE
)
# Set style
sns.set_style('whitegrid')
plt.rcParams['figure.figsize'] = (10, 6)
def load_clean_data():
"""Load preprocessed training data"""
filepath = PROCESSED_DATA_DIR / 'flood_training_clean.csv'
if not filepath.exists():
print(f"❌ Clean data not found: {filepath}")
print("Run eda_analysis.py first!")
return None
df = pd.read_csv(filepath)
print(f"βœ“ Loaded clean dataset: {len(df)} samples")
return df
def prepare_features_labels(df):
"""Extract features and labels"""
X = df[FEATURE_COLUMNS].values
y = df[TARGET_COLUMN].values
print(f"\nβœ“ Features (X): {X.shape}")
print(f"βœ“ Labels (y): {y.shape}")
print(f"βœ“ Feature columns: {FEATURE_COLUMNS}")
return X, y
def split_data(X, y):
"""Split into train and test sets"""
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=TEST_SIZE,
random_state=RF_RANDOM_STATE,
stratify=y # Maintain class balance
)
print(f"\nβœ“ Train set: {X_train.shape[0]} samples")
print(f"βœ“ Test set: {X_test.shape[0]} samples")
print(f"βœ“ Train flood ratio: {y_train.sum()/len(y_train):.2%}")
print(f"βœ“ Test flood ratio: {y_test.sum()/len(y_test):.2%}")
return X_train, X_test, y_train, y_test
def train_model(X_train, y_train):
"""Train Random Forest classifier"""
print("\n" + "="*60)
print("🌲 TRAINING RANDOM FOREST MODEL")
print("="*60)
print(f"\nHyperparameters:")
print(f" n_estimators: {RF_N_ESTIMATORS}")
print(f" max_depth: {RF_MAX_DEPTH}")
print(f" min_samples_split: {RF_MIN_SAMPLES_SPLIT}")
print(f" min_samples_leaf: {RF_MIN_SAMPLES_LEAF}")
print(f" random_state: {RF_RANDOM_STATE}")
model = RandomForestClassifier(
n_estimators=RF_N_ESTIMATORS,
max_depth=RF_MAX_DEPTH,
min_samples_split=RF_MIN_SAMPLES_SPLIT,
min_samples_leaf=RF_MIN_SAMPLES_LEAF,
random_state=RF_RANDOM_STATE,
n_jobs=-1,
verbose=1
)
print("\n⏳ Training in progress...")
model.fit(X_train, y_train)
print("βœ“ Training complete!")
return model
def evaluate_model(model, X_train, X_test, y_train, y_test):
"""Comprehensive model evaluation"""
print("\n" + "="*60)
print("πŸ“Š MODEL EVALUATION")
print("="*60)
# Predictions
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
y_train_proba = model.predict_proba(X_train)[:, 1]
y_test_proba = model.predict_proba(X_test)[:, 1]
# Metrics
train_acc = accuracy_score(y_train, y_train_pred)
test_acc = accuracy_score(y_test, y_test_pred)
train_f1 = f1_score(y_train, y_train_pred)
test_f1 = f1_score(y_test, y_test_pred)
train_roc = roc_auc_score(y_train, y_train_proba)
test_roc = roc_auc_score(y_test, y_test_proba)
print(f"\n{'Metric':<20} {'Train':<15} {'Test':<15}")
print("-" * 50)
print(f"{'Accuracy':<20} {train_acc:<15.4f} {test_acc:<15.4f}")
print(f"{'F1-Score':<20} {train_f1:<15.4f} {test_f1:<15.4f}")
print(f"{'ROC-AUC':<20} {train_roc:<15.4f} {test_roc:<15.4f}")
# Confusion Matrix
print("\n--- Test Set Confusion Matrix ---")
cm = confusion_matrix(y_test, y_test_pred)
print(cm)
print(f"\nTrue Negatives: {cm[0,0]}")
print(f"False Positives: {cm[0,1]}")
print(f"False Negatives: {cm[1,0]}")
print(f"True Positives: {cm[1,1]}")
# Classification Report
print("\n--- Test Set Classification Report ---")
print(classification_report(y_test, y_test_pred, target_names=['No Flood', 'Flood']))
return {
'train_acc': train_acc,
'test_acc': test_acc,
'train_f1': train_f1,
'test_f1': test_f1,
'train_roc': train_roc,
'test_roc': test_roc,
'y_test': y_test,
'y_test_pred': y_test_pred,
'y_test_proba': y_test_proba
}
def plot_confusion_matrix(y_test, y_test_pred):
"""Plot confusion matrix heatmap"""
cm = confusion_matrix(y_test, y_test_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['No Flood', 'Flood'],
yticklabels=['No Flood', 'Flood'],
cbar_kws={'label': 'Count'})
plt.title('Confusion Matrix - Test Set', fontsize=14, fontweight='bold')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.tight_layout()
output_path = Path(__file__).parent.parent / 'data' / 'outputs' / 'confusion_matrix.png'
plt.savefig(output_path, dpi=300, bbox_inches='tight')
print(f"\nβœ“ Saved: {output_path}")
plt.close()
def plot_roc_curve(y_test, y_test_proba):
"""Plot ROC curve"""
fpr, tpr, thresholds = roc_curve(y_test, y_test_proba)
roc_auc = roc_auc_score(y_test, y_test_proba)
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='blue', lw=2, label=f'ROC Curve (AUC = {roc_auc:.3f})')
plt.plot([0, 1], [0, 1], color='red', lw=2, linestyle='--', label='Random Classifier')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate', fontsize=12)
plt.ylabel('True Positive Rate', fontsize=12)
plt.title('ROC Curve - Test Set', fontsize=14, fontweight='bold')
plt.legend(loc='lower right')
plt.grid(alpha=0.3)
plt.tight_layout()
output_path = Path(__file__).parent.parent / 'data' / 'outputs' / 'roc_curve.png'
plt.savefig(output_path, dpi=300, bbox_inches='tight')
print(f"βœ“ Saved: {output_path}")
plt.close()
def plot_feature_importance(model):
"""Plot feature importance"""
importance_df = pd.DataFrame({
'feature': FEATURE_COLUMNS,
'importance': model.feature_importances_
}).sort_values('importance', ascending=False)
print("\n" + "="*60)
print("🎯 FEATURE IMPORTANCE")
print("="*60)
print(importance_df.to_string(index=False))
# Plot
plt.figure(figsize=(10, 6))
colors = sns.color_palette("viridis", len(FEATURE_COLUMNS))
plt.barh(importance_df['feature'], importance_df['importance'], color=colors)
plt.xlabel('Importance Score', fontsize=12)
plt.ylabel('Feature', fontsize=12)
plt.title('Feature Importance - Random Forest', fontsize=14, fontweight='bold')
plt.gca().invert_yaxis()
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
output_path = Path(__file__).parent.parent / 'data' / 'outputs' / 'feature_importance.png'
plt.savefig(output_path, dpi=300, bbox_inches='tight')
print(f"\nβœ“ Saved: {output_path}")
plt.close()
def save_model(model):
"""Save trained model to disk"""
output_path = MODELS_DIR / 'random_forest_flood_model.pkl'
joblib.dump(model, output_path)
file_size = output_path.stat().st_size / 1024 # KB
print(f"\nβœ“ Model saved: {output_path}")
print(f"βœ“ File size: {file_size:.2f} KB")
def save_training_report(metrics):
"""Save training summary report"""
report = []
report.append("="*60)
report.append("FLOOD PREDICTION MODEL - TRAINING REPORT")
report.append("="*60)
report.append(f"\nModel: Random Forest Classifier")
report.append(f"Training samples: 1000")
report.append(f"Test samples: 250")
report.append(f"\nHyperparameters:")
report.append(f" n_estimators: {RF_N_ESTIMATORS}")
report.append(f" max_depth: {RF_MAX_DEPTH}")
report.append(f" min_samples_split: {RF_MIN_SAMPLES_SPLIT}")
report.append(f" min_samples_leaf: {RF_MIN_SAMPLES_LEAF}")
report.append(f"\nPerformance Metrics:")
report.append(f" Train Accuracy: {metrics['train_acc']:.4f}")
report.append(f" Test Accuracy: {metrics['test_acc']:.4f}")
report.append(f" Train F1-Score: {metrics['train_f1']:.4f}")
report.append(f" Test F1-Score: {metrics['test_f1']:.4f}")
report.append(f" Train ROC-AUC: {metrics['train_roc']:.4f}")
report.append(f" Test ROC-AUC: {metrics['test_roc']:.4f}")
report.append(f"\nβœ“ Model shows {'good generalization' if abs(metrics['train_acc'] - metrics['test_acc']) < 0.05 else 'potential overfitting'}")
report.append("\n" + "="*60)
report_text = "\n".join(report)
output_path = Path(__file__).parent.parent / 'data' / 'outputs' / 'training_report.txt'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(report_text)
print("\n" + report_text)
print(f"\nβœ“ Report saved: {output_path}")
def main():
"""Main training pipeline"""
print("\n" + "="*60)
print("🌊 FLOOD PREDICTION - MODEL TRAINING")
print("="*60)
# Load data
df = load_clean_data()
if df is None:
return
# Prepare features and labels
X, y = prepare_features_labels(df)
# Split data
X_train, X_test, y_train, y_test = split_data(X, y)
# Train model
model = train_model(X_train, y_train)
# Evaluate
metrics = evaluate_model(model, X_train, X_test, y_train, y_test)
# Visualizations
plot_confusion_matrix(metrics['y_test'], metrics['y_test_pred'])
plot_roc_curve(metrics['y_test'], metrics['y_test_proba'])
plot_feature_importance(model)
# Save model
save_model(model)
# Save report
save_training_report(metrics)
print("\n" + "="*60)
print("βœ… TRAINING COMPLETE!")
print("="*60)
print("\nGenerated Files:")
print(" πŸ“Š confusion_matrix.png")
print(" πŸ“Š roc_curve.png")
print(" πŸ“Š feature_importance.png")
print(" πŸ“„ training_report.txt")
print(" πŸ’Ύ random_forest_flood_model.pkl")
print("\nβœ“ Ready for Phase 4: GEE Integration & Testing")
if __name__ == "__main__":
main()