# models/regression.py import pandas as pd import numpy as np from typing import Literal, Dict, Any from sklearn.linear_model import LinearRegression from sklearn.ensemble import GradientBoostingRegressor from sklearn.neural_network import MLPRegressor from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error from sklearn.preprocessing import MinMaxScaler RegressionModelType = Literal['linear', 'xgb', 'mlp'] class LoadLimitRegressor: """ Regressor สำหรับหา load limit จาก temperature พยากรณ์โหลดสูงสุดที่เป็นไปได้จากค่าความร้อน """ def __init__(self, model_type: RegressionModelType = 'xgb'): self.model_type = model_type self.scaler_X = MinMaxScaler() self.scaler_y = MinMaxScaler() self.model = None self.feature_names = None def fit(self, df: pd.DataFrame, temp_col: str = 'MaxTemp', load_col: str = 'mw_max'): """ เทรน regression model เพื่อหา relationship ระหว่างอุณหภูมิ ➜ โหลดสูงสุด """ X = df[[temp_col]].values y = df[[load_col]].values X_scaled = self.scaler_X.fit_transform(X) y_scaled = self.scaler_y.fit_transform(y) if self.model_type == 'linear': self.model = LinearRegression() elif self.model_type == 'xgb': self.model = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3) elif self.model_type == 'mlp': self.model = MLPRegressor(hidden_layer_sizes=(64, 32), max_iter=1000) else: raise ValueError(f"Unsupported model type: {self.model_type}") self.model.fit(X_scaled, y_scaled.ravel()) self.feature_names = [temp_col] def predict(self, max_temp_values: np.ndarray) -> np.ndarray: """ พยากรณ์โหลดสูงสุดที่เป็นไปได้ จากค่าความร้อน """ X_scaled = self.scaler_X.transform(max_temp_values.reshape(-1, 1)) y_scaled = self.model.predict(X_scaled).reshape(-1, 1) y = self.scaler_y.inverse_transform(y_scaled) return y.flatten() def evaluate(self, df: pd.DataFrame, temp_col: str = 'MaxTemp', load_col: str = 'mw_max') -> Dict[str, float]: """ ประเมินผลโมเดล regression """ y_true = df[load_col].values y_pred = self.predict(df[temp_col].values) return { 'rmse': np.sqrt(mean_squared_error(y_true, y_pred)), 'mae': mean_absolute_error(y_true, y_pred), 'r2': r2_score(y_true, y_pred) } class CapacityAnalyzer: """ วิเคราะห์ capacity จริง (Real Capacity) เทียบกับทฤษฏี 80% ใช้ features เพิ่มเติม (TEPR, STRR, temp margin) เพื่อประมาณ capacity จริง ที่อาจสูงกว่า 80% theoretical """ def __init__(self, model_type: RegressionModelType = 'xgb'): self.model_type = model_type self.scalers = {} self.model = None self.feature_names = None def fit(self, df: pd.DataFrame, target_col: str = 'mw_max', feature_cols: list = None, calibration_factor: float = 1.0) -> None: """ เทรน model สำหรับหา real capacity Args: df: DataFrame ที่มีข้อมูล load, temp, measurement target_col: ชื่อ column เป้าหมาย (load actual) feature_cols: ชื่อ columns ที่ใช้เป็น features ถ้า None ใช้ default: ['MaxTemp', 'temp_margin_available', 'tepr_mean', 'strr_mean'] calibration_factor: factor สำหรับ calibrate ผล (default 1.0) """ if feature_cols is None: # Default features available_cols = df.columns.tolist() feature_cols = [] if 'MaxTemp' in available_cols: feature_cols.append('MaxTemp') if 'temp_margin_available' in available_cols: feature_cols.append('temp_margin_available') if 'tepr_mean' in available_cols: feature_cols.append('tepr_mean') if 'strr_mean' in available_cols: feature_cols.append('strr_mean') # ถ้าไม่มี feature พอ ใช้เฉพาะ MaxTemp if not feature_cols: feature_cols = ['MaxTemp'] # ตรวจสอบว่ามี feature ทั้งหมดหรือไม่ available_features = [col for col in feature_cols if col in df.columns] if not available_features: raise ValueError(f"❌ ไม่มี features {feature_cols} ใน data!") X = df[available_features].values y = df[[target_col]].values # Normalize each feature self.scalers = {} X_scaled = np.zeros_like(X) for i, col in enumerate(available_features): scaler = MinMaxScaler() X_scaled[:, i] = scaler.fit_transform(X[:, i:i+1]).flatten() self.scalers[col] = scaler # Train model if self.model_type == 'linear': self.model = LinearRegression() elif self.model_type == 'xgb': self.model = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3) elif self.model_type == 'mlp': self.model = MLPRegressor(hidden_layer_sizes=(64, 32), max_iter=1000) else: raise ValueError(f"Unsupported model type: {self.model_type}") # Normalize target self.scaler_y = MinMaxScaler() y_scaled = self.scaler_y.fit_transform(y) self.model.fit(X_scaled, y_scaled.ravel()) self.feature_names = available_features self.calibration_factor = calibration_factor def predict_capacity(self, df: pd.DataFrame) -> np.ndarray: """ พยากรณ์ real capacity จริง """ if self.model is None: raise ValueError("❌ Model ยังไม่ได้ train! ให้เรียก fit() ก่อน") # ดึงแต่ features ที่มี X = df[self.feature_names].values # Scale features X_scaled = np.zeros_like(X) for i, col in enumerate(self.feature_names): if col in self.scalers: X_scaled[:, i] = self.scalers[col].transform(X[:, i:i+1]).flatten() # Predict y_scaled = self.model.predict(X_scaled).reshape(-1, 1) y = self.scaler_y.inverse_transform(y_scaled) # Apply calibration factor return (y.flatten() * self.calibration_factor) def evaluate(self, df: pd.DataFrame, actual_col: str = 'mw_max') -> Dict[str, Any]: """ ประเมินผลโมเดล capacity analysis """ y_true = df[actual_col].values y_pred = self.predict_capacity(df) metrics = { 'rmse': np.sqrt(mean_squared_error(y_true, y_pred)), 'mae': mean_absolute_error(y_true, y_pred), 'r2': r2_score(y_true, y_pred), 'features_used': self.feature_names } return metrics