# Model Framework Architecture

This document explains the modular model architecture implemented in the `imperfekt/prediction` module.

## Overview

The framework is designed to be:
- **Modular**: Each model type is implemented as a separate class
- **Extensible**: Easy to add new model types 
- **Standardized**: Common interface for all models
- **Maintainable**: Clear separation of concerns

## Directory Structure

```
imperfekt/prediction/
├── models.py           # Core model classes and evaluation functions
├── utils.py            # Feature generation utilities
├── hyperparameter_tuning.py  # Tools for model tuning
└── minimal_working_example.py # Example pipeline for early sepsis prediction
```

## Core Components

### Base Model Class

All models inherit from the `BaseModel` class in `models.py`, which provides:
- Common interface for training and evaluation
- Standardized data preparation (train/test split, scaling)
- Mission/case-level data splitting to prevent data leakage
- Unified metrics calculation
- Feature importance extraction

### Implemented Model Types

1. **LogisticRegressionModel**: Sklearn-based logistic regression
2. **LightGBMModel**: LightGBM implementation
3. **XGBoostModel**: XGBoost implementation

### Feature Generation

The framework supports two types of features:
- **Imperfekt Features**: Advanced features generated by the Imperfekt library
- **Baseline Features**: Simple statistical aggregations of vital signs

## Usage Examples

### Basic Usage

```python
from prediction.models import LogisticRegressionModel, evaluate_and_compare_models
from prediction.utils import generate_imperfekt_non_seq_features

# Load and prepare data
data = ...  # Load your data
features = generate_imperfekt_non_seq_features(data, target_col="target")

# Create and train model
model = LogisticRegressionModel(random_state=42)
# Train with mission/case-level splitting (prevents data leakage)
trained_model, metrics = model.train(features, "target", id_col="id", group_split=True)

# Or use standard row-level splitting (not recommended for time-series data)
# trained_model, metrics = model.train(features, "target", group_split=False)

# Access metrics
print(metrics["roc_auc"])
```
