Spaces:
Sleeping
Sleeping
| from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor | |
| from sklearn.linear_model import LogisticRegression, Ridge | |
| from sklearn.pipeline import Pipeline | |
| from lightgbm import LGBMClassifier, LGBMRegressor | |
| from typing import Tuple, Any, Dict | |
| from src.monitoring.logger import get_logger | |
| logger = get_logger(__name__) | |
| class ModelSelectionEngine: | |
| """Dynamically selects the optimal model and its base parameters based on data sparsity, size and task.""" | |
| def get_model_candidate(n_samples: int, n_features: int, is_sparse: bool, is_regression: bool = False, aggressive: bool = False) -> Any: | |
| """Selects a base model candidate for the dataset traits.""" | |
| from sklearn.ensemble import StackingClassifier, StackingRegressor | |
| from sklearn.linear_model import LogisticRegression, Ridge | |
| # Aggressive Mode: Use XGBoost and CatBoost in the stack | |
| if aggressive: | |
| from xgboost import XGBClassifier, XGBRegressor | |
| from catboost import CatBoostClassifier, CatBoostRegressor | |
| if is_regression: | |
| logger.info("🔥 AGGRESSIVE MODE: Building Elite Regression Stack (RF + LGBM + XGB + CatBoost)") | |
| estimators = [ | |
| ('rf', RandomForestRegressor(n_estimators=100, n_jobs=-1, random_state=42)), | |
| ('lgbm', LGBMRegressor(n_estimators=100, n_jobs=-1, random_state=42, verbose=-1)), | |
| ('xgb', XGBRegressor(n_estimators=100, n_jobs=-1, random_state=42, verbosity=0)), | |
| ('cat', CatBoostRegressor(n_estimators=100, random_state=42, verbose=0)) | |
| ] | |
| return StackingRegressor( | |
| estimators=estimators, | |
| final_estimator=Ridge(), | |
| cv=3, | |
| n_jobs=-1 | |
| ) | |
| else: | |
| logger.info("🔥 AGGRESSIVE MODE: Building Elite Classification Stack (RF + LGBM + XGB + CatBoost)") | |
| estimators = [ | |
| ('rf', RandomForestClassifier(n_estimators=100, n_jobs=-1, random_state=42, class_weight='balanced')), | |
| ('lgbm', LGBMClassifier(n_estimators=100, n_jobs=-1, random_state=42, verbose=-1, class_weight='balanced')), | |
| ('xgb', XGBClassifier(n_estimators=100, n_jobs=-1, random_state=42, verbosity=0)), | |
| ('cat', CatBoostClassifier(n_estimators=100, random_state=42, verbose=0)) | |
| ] | |
| return StackingClassifier( | |
| estimators=estimators, | |
| final_estimator=LogisticRegression(), | |
| cv=3, | |
| n_jobs=-1 | |
| ) | |
| if is_regression: | |
| if n_samples < 1000: | |
| logger.info("Selecting RandomForestRegressor for small regression.") | |
| return RandomForestRegressor(n_jobs=-1, random_state=42) | |
| else: | |
| logger.info("Selecting StackingRegressor (RF + LGBM + Ridge) for peak accuracy.") | |
| estimators = [ | |
| ('rf', RandomForestRegressor(n_estimators=100, n_jobs=-1, random_state=42)), | |
| ('lgbm', LGBMRegressor(n_estimators=100, n_jobs=-1, random_state=42, verbose=-1)), | |
| ('ridge', Ridge(alpha=1.0)) | |
| ] | |
| return StackingRegressor( | |
| estimators=estimators, | |
| final_estimator=Ridge(), | |
| cv=3, | |
| n_jobs=-1 | |
| ) | |
| else: | |
| if is_sparse and n_samples < 5000: | |
| logger.info("Selecting Logistic Regression for sparse data.") | |
| return LogisticRegression(solver='liblinear', max_iter=1000, class_weight='balanced') | |
| elif n_samples < 1000: | |
| logger.info("Selecting Random Forest for robust small-scale learning.") | |
| return RandomForestClassifier(n_jobs=-1, random_state=42, class_weight='balanced') | |
| else: | |
| logger.info("Selecting StackingClassifier (RF + LGBM + LogReg) for peak accuracy.") | |
| estimators = [ | |
| ('rf', RandomForestClassifier(n_estimators=100, n_jobs=-1, random_state=42, class_weight='balanced')), | |
| ('lgbm', LGBMClassifier(n_estimators=100, n_jobs=-1, random_state=42, verbose=-1, class_weight='balanced')), | |
| ('lr', LogisticRegression(max_iter=1000, class_weight='balanced')) | |
| ] | |
| return StackingClassifier( | |
| estimators=estimators, | |
| final_estimator=LogisticRegression(), | |
| cv=3, | |
| n_jobs=-1 | |
| ) | |
| def create_unified_pipeline(preprocessor: Any, model: Any) -> Pipeline: | |
| """Wraps preprocessor and model into a single versioned pipeline.""" | |
| return Pipeline([ | |
| ('preprocessor', preprocessor), | |
| ('model', model) | |
| ]) | |
| def get_param_grid(model: Any) -> Dict[str, Any]: | |
| """Returns search space for the selected model.""" | |
| from sklearn.ensemble import VotingClassifier, VotingRegressor, StackingClassifier, StackingRegressor | |
| if isinstance(model, (VotingClassifier, VotingRegressor, StackingClassifier, StackingRegressor)): | |
| grid = {} | |
| # Standard ensembles have (name, estimator) pairs in .estimators | |
| est_names = [name for name, _ in model.estimators] | |
| if 'rf' in est_names: | |
| grid['model__rf__n_estimators'] = [50, 100] | |
| if 'lgbm' in est_names: | |
| grid['model__lgbm__learning_rate'] = [0.05, 0.1] | |
| if 'xgb' in est_names: | |
| grid['model__xgb__max_depth'] = [3, 6] | |
| if 'cat' in est_names: | |
| grid['model__cat__depth'] = [4, 6] | |
| return grid | |
| if isinstance(model, LogisticRegression): | |
| return {'model__C': [0.1, 1.0, 10.0]} | |
| if isinstance(model, (RandomForestClassifier, RandomForestRegressor)): | |
| return {'model__n_estimators': [50, 100]} | |
| if isinstance(model, (LGBMClassifier, LGBMRegressor)): | |
| return {'model__learning_rate': [0.05, 0.1]} | |
| if isinstance(model, Ridge): | |
| return {'model__alpha': [0.1, 1.0, 10.0]} | |
| return {} | |