Загрузка данных


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))