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


# Визуализация прогнозных результатов модели

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.metrics import mean_absolute_error, r2_score

# ------------------------------------------------------------
# 1. Параметры (используем те же, что и в остальном ноутбуке)
# ------------------------------------------------------------
weight_col = 'sum_total_out'        # уже определено
date_col = 'end_month_plan'         # уже определено
target = 'renewed_fact_rate'        # уже определено
pred_col = 'prediction'             # уже определено

train_end = pd.Timestamp('2025-02-01')
train_df = df[df[date_col] < train_end].copy()
test_df = df[df[date_col] >= train_end].copy()

# ------------------------------------------------------------
# 2. Функции построения (без дублирования aggregate_weighted)
# ------------------------------------------------------------
def get_comparison(df_part, date_col, target, pred_col, weight_col):
    """Возвращает объединённый DataFrame с фактом и прогнозом."""
    if len(df_part) == 0:
        return pd.DataFrame()
    
    # Используем существующую функцию aggregate_weighted
    fact = aggregate_weighted(df_part, date_col, target, weight_col)
    pred = aggregate_weighted(df_part, date_col, pred_col, weight_col)
    comp = fact.merge(pred, on=date_col, suffixes=('_fact', '_pred'))
    return comp


def plot_forecast(ax, comp, date_col, target, pred_col, weight_col, title):
    """Построение одного графика прогноза."""
    if len(comp) == 0:
        ax.text(0.5, 0.5, 'Нет данных', ha='center', va='center', transform=ax.transAxes)
        ax.set_title(title)
        return
    
    y_true = comp[target].values
    y_pred = comp[pred_col].values
    weights = comp[weight_col].values   # используем weight_col без суффикса
    
    ax.plot(comp[date_col], y_true, marker='o', label='Факт', color='blue', linewidth=2)
    ax.plot(comp[date_col], y_pred, marker='s', label='Прогноз', color='red', linewidth=2)
    ax.set_title(title)
    ax.set_ylabel('Доля пролонгаций')
    ax.grid(True, alpha=0.3)
    ax.tick_params(axis='x', rotation=45)
    
    ax2 = ax.twinx()
    ax2.bar(comp[date_col], weights, alpha=0.3, color='gray', width=15, label='Объём')
    ax2.set_ylabel('Суммарный объём (sum_total_out)', color='gray')
    ax2.tick_params(axis='y', labelcolor='gray')
    
    mae = mean_absolute_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    ax.text(0.05, 0.95, f'MAE = {mae:.3f}\nR² = {r2:.3f}', 
            transform=ax.transAxes, fontsize=10,
            verticalalignment='top',
            bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
    
    ax.legend(loc='lower left')

# ------------------------------------------------------------
# 3. Сбор данных и построение
# ------------------------------------------------------------
segments = ['mass', 'mid', 'prem']
comparisons = {}

# Общий портфель
comparisons[('все сегменты', 'train')] = get_comparison(train_df, date_col, target, pred_col, weight_col)
comparisons[('все сегменты', 'test')] = get_comparison(test_df, date_col, target, pred_col, weight_col)

# По сегментам
for seg in segments:
    train_seg = train_df[train_df['segment'] == seg].copy()
    test_seg = test_df[test_df['segment'] == seg].copy()
    comparisons[(seg, 'train')] = get_comparison(train_seg, date_col, target, pred_col, weight_col)
    comparisons[(seg, 'test')] = get_comparison(test_seg, date_col, target, pred_col, weight_col)

# Графики
order = ['все сегменты'] + segments

fig1, axes1 = plt.subplots(2, 2, figsize=(16, 12))
for ax, label in zip(axes1.flatten(), order):
    comp = comparisons.get((label, 'train'), pd.DataFrame())
    plot_forecast(ax, comp, date_col, target, pred_col, weight_col, title=f'{label} (train)')
plt.suptitle('Прогнозные результаты модели (train, до 02.2025)', fontsize=14)
plt.tight_layout()
plt.show()

fig2, axes2 = plt.subplots(2, 2, figsize=(16, 12))
for ax, label in zip(axes2.flatten(), order):
    comp = comparisons.get((label, 'test'), pd.DataFrame())
    plot_forecast(ax, comp, date_col, target, pred_col, weight_col, title=f'{label} (test)')
plt.suptitle('Прогнозные результаты модели (test, с 02.2025)', fontsize=14)
plt.tight_layout()
plt.show()