Spaces:
Runtime error
Runtime error
Update core/train_eval.py
Browse files- core/train_eval.py +30 -5
core/train_eval.py
CHANGED
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
| 3 |
import torch
|
| 4 |
from torch import nn, optim
|
| 5 |
from sklearn.preprocessing import StandardScaler
|
| 6 |
-
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
|
| 7 |
from torch.utils.data import DataLoader, TensorDataset
|
| 8 |
import matplotlib.pyplot as plt
|
| 9 |
import os
|
|
@@ -26,6 +26,27 @@ def mean_absolute_percentage_error(y_true, y_pred):
|
|
| 26 |
return np.mean(np.abs((y_true[non_zero] - y_pred[non_zero]) / y_true[non_zero])) * 100
|
| 27 |
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
def train_and_evaluate(
|
| 30 |
df,
|
| 31 |
future_df,
|
|
@@ -85,7 +106,7 @@ def train_and_evaluate(
|
|
| 85 |
patience = 5
|
| 86 |
counter = 0
|
| 87 |
best_model_state = None
|
| 88 |
-
last_lr = lr
|
| 89 |
|
| 90 |
model.train()
|
| 91 |
for epoch in range(epochs):
|
|
@@ -111,7 +132,6 @@ def train_and_evaluate(
|
|
| 111 |
val_loss /= len(val_loader)
|
| 112 |
val_losses.append(val_loss)
|
| 113 |
|
| 114 |
-
# Step scheduler and manually log learning rate changes
|
| 115 |
scheduler.step(val_loss)
|
| 116 |
current_lr = optimizer.param_groups[0]['lr']
|
| 117 |
if current_lr != last_lr and verbose:
|
|
@@ -161,12 +181,18 @@ def train_and_evaluate(
|
|
| 161 |
mae = mean_absolute_error(targets_inv, preds_inv)
|
| 162 |
r2 = r2_score(targets_inv, preds_inv)
|
| 163 |
mape = mean_absolute_percentage_error(targets_inv, preds_inv)
|
|
|
|
|
|
|
|
|
|
| 164 |
|
| 165 |
result["metrics"] = {
|
| 166 |
"R2": round(r2, 4),
|
|
|
|
|
|
|
| 167 |
"RMSE": round(rmse, 4),
|
| 168 |
"MAE": round(mae, 4),
|
| 169 |
-
"MAPE": round(mape, 4) if not np.isnan(mape) else None
|
|
|
|
| 170 |
}
|
| 171 |
|
| 172 |
result["forecast"] = preds_inv
|
|
@@ -183,7 +209,6 @@ def train_and_evaluate(
|
|
| 183 |
|
| 184 |
result["latest_prediction"] = future_pred_inv[0].tolist()
|
| 185 |
|
| 186 |
-
# Include actual future values if available
|
| 187 |
if not future_df.empty:
|
| 188 |
result["future_actuals"] = future_df['value'].values.tolist()[:horizon]
|
| 189 |
|
|
|
|
| 3 |
import torch
|
| 4 |
from torch import nn, optim
|
| 5 |
from sklearn.preprocessing import StandardScaler
|
| 6 |
+
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, explained_variance_score
|
| 7 |
from torch.utils.data import DataLoader, TensorDataset
|
| 8 |
import matplotlib.pyplot as plt
|
| 9 |
import os
|
|
|
|
| 26 |
return np.mean(np.abs((y_true[non_zero] - y_pred[non_zero]) / y_true[non_zero])) * 100
|
| 27 |
|
| 28 |
|
| 29 |
+
def mean_absolute_scaled_error(y_true, y_pred, y_train):
|
| 30 |
+
"""Calculate MASE, using naive forecast as denominator."""
|
| 31 |
+
y_true, y_pred = np.array(y_true), np.array(y_pred)
|
| 32 |
+
errors = np.abs(y_true - y_pred)
|
| 33 |
+
# Naive forecast: use previous value as prediction
|
| 34 |
+
naive_errors = np.abs(y_train[1:] - y_train[:-1])
|
| 35 |
+
mean_naive_error = np.mean(naive_errors) if len(naive_errors) > 0 else 1.0
|
| 36 |
+
return np.mean(errors) / mean_naive_error if mean_naive_error != 0 else np.nan
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def mean_directional_accuracy(y_true, y_pred):
|
| 40 |
+
"""Calculate MDA: percentage of correct direction predictions."""
|
| 41 |
+
y_true, y_pred = np.array(y_true), np.array(y_pred)
|
| 42 |
+
if len(y_true) < 2:
|
| 43 |
+
return np.nan
|
| 44 |
+
true_diff = np.sign(y_true[1:] - y_true[:-1])
|
| 45 |
+
pred_diff = np.sign(y_pred[1:] - y_pred[:-1])
|
| 46 |
+
correct = np.sum(true_diff == pred_diff)
|
| 47 |
+
return (correct / (len(y_true) - 1)) * 100
|
| 48 |
+
|
| 49 |
+
|
| 50 |
def train_and_evaluate(
|
| 51 |
df,
|
| 52 |
future_df,
|
|
|
|
| 106 |
patience = 5
|
| 107 |
counter = 0
|
| 108 |
best_model_state = None
|
| 109 |
+
last_lr = lr
|
| 110 |
|
| 111 |
model.train()
|
| 112 |
for epoch in range(epochs):
|
|
|
|
| 132 |
val_loss /= len(val_loader)
|
| 133 |
val_losses.append(val_loss)
|
| 134 |
|
|
|
|
| 135 |
scheduler.step(val_loss)
|
| 136 |
current_lr = optimizer.param_groups[0]['lr']
|
| 137 |
if current_lr != last_lr and verbose:
|
|
|
|
| 181 |
mae = mean_absolute_error(targets_inv, preds_inv)
|
| 182 |
r2 = r2_score(targets_inv, preds_inv)
|
| 183 |
mape = mean_absolute_percentage_error(targets_inv, preds_inv)
|
| 184 |
+
evs = explained_variance_score(targets_inv, preds_inv)
|
| 185 |
+
mase = mean_absolute_scaled_error(targets_inv, preds_inv, original_values[:len(original_values)-horizon])
|
| 186 |
+
mda = mean_directional_accuracy(targets_inv, preds_inv)
|
| 187 |
|
| 188 |
result["metrics"] = {
|
| 189 |
"R2": round(r2, 4),
|
| 190 |
+
"Explained Variance": round(evs, 4),
|
| 191 |
+
"MDA (%)": round(mda, 4) if not np.isnan(mda) else None,
|
| 192 |
"RMSE": round(rmse, 4),
|
| 193 |
"MAE": round(mae, 4),
|
| 194 |
+
"MAPE (%)": round(mape, 4) if not np.isnan(mape) else None,
|
| 195 |
+
"MASE": round(mase, 4) if not np.isnan(mase) else None
|
| 196 |
}
|
| 197 |
|
| 198 |
result["forecast"] = preds_inv
|
|
|
|
| 209 |
|
| 210 |
result["latest_prediction"] = future_pred_inv[0].tolist()
|
| 211 |
|
|
|
|
| 212 |
if not future_df.empty:
|
| 213 |
result["future_actuals"] = future_df['value'].values.tolist()[:horizon]
|
| 214 |
|