def calc_metrics(comp, weight_col):
y_true = comp[target].values
y_pred = comp[pred_col].values
weights = comp[f'{weight_col}_fact'].values
benchmark = np.average(y_true, weights=weights)
comp['benchmark'] = benchmark
mae = mean_absolute_error(y_true, y_pred)
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
mape = np.mean(np.abs((y_true - y_pred) / np.maximum(np.abs(y_true), 1e-6))) * 100
r2 = r2_score(y_true, y_pred)
b_mae = mean_absolute_error(y_true, comp['benchmark'])
b_rmse = np.sqrt(mean_squared_error(y_true, comp['benchmark']))
b_mape = np.mean(np.abs((y_true - comp['benchmark']) / np.maximum(np.abs(y_true), 1e-6))) * 100
b_r2 = r2_score(y_true, comp['benchmark'])
wmae = np.average(np.abs(y_true - y_pred), weights=weights)
wrmse = np.sqrt(np.average((y_true - y_pred)**2, weights=weights))
wmape = np.average(np.abs((y_true - y_pred) / np.maximum(np.abs(y_true), 1e-6)), weights=weights) * 100
b_wmae = np.average(np.abs(y_true - comp['benchmark']), weights=weights)
b_wrmse = np.sqrt(np.average((y_true - comp['benchmark'])**2, weights=weights))
b_wmape = np.average(np.abs((y_true - comp['benchmark']) / np.maximum(np.abs(y_true), 1e-6)), weights=weights) * 100
return pd.DataFrame({
'MAE': [mae, b_mae],
'RMSE': [rmse, b_rmse],
'MAPE (%)': [mape, b_mape],
'R2': [r2, b_r2],
'wMAE': [wmae, b_wmae],
'wRMSE': [wrmse, b_wrmse],
'wMAPE (%)': [wmape, b_wmape]
}, index=['Model', 'Benchmark'])
# Train + Test (общий портфель)
comp_train = aggregate_weighted(train_df, date_col, target, weight_col).merge(
aggregate_weighted(train_df, date_col, pred_col, weight_col), on=date_col, suffixes=('_fact', '_pred'))
comp_test = aggregate_weighted(test_df, date_col, target, weight_col).merge(
aggregate_weighted(test_df, date_col, pred_col, weight_col), on=date_col, suffixes=('_fact', '_pred'))
print('=== TRAIN ===')
display(calc_metrics(comp_train, weight_col).round(3))
print('=== TEST ===')
display(calc_metrics(comp_test, weight_col).round(3))
# По сегментам
for seg in ['prem', 'mid']:
print(f'=== {seg.upper()} ===')
for df_part, label in [(train_df, 'Train'), (test_df, 'Test')]:
df_seg = df_part[df_part['segment'] == seg].copy()
comp = aggregate_weighted(df_seg, date_col, target, weight_col).merge(
aggregate_weighted(df_seg, date_col, pred_col, weight_col), on=date_col, suffixes=('_fact', '_pred'))
print(f' {label}:')
display(calc_metrics(comp, weight_col).round(3))