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


import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Предполагаем, что df, date_col, target, weight_col уже определены
# date_col = 'end_month_plan'
# target = 'renewed_fact_rate'
# weight_col = 'portfolio_share'

# Группировка по pr_p_n
grouped = df.groupby('pr_p_n').apply(
    lambda g: pd.Series({
        'weighted_target': np.average(g[target], weights=g[weight_col]),
        'total_weight': g[weight_col].sum(),
        'count': len(g)
    })
).reset_index()

# Сортируем для плавной линии
grouped = grouped.sort_values('pr_p_n')

# Построение графика
fig, ax = plt.subplots(figsize=(10, 6))

# Основной график – точки с размером, пропорциональным объёму
sc = ax.scatter(grouped['pr_p_n'], grouped['weighted_target'],
                s=grouped['total_weight'] / grouped['total_weight'].max() * 200,  # масштабируем размер
                alpha=0.6, edgecolors='k', linewidth=0.5)

# Линия тренда (можно добавить сглаживание, но для простоты – просто соединим точки)
ax.plot(grouped['pr_p_n'], grouped['weighted_target'], linestyle='--', color='gray', alpha=0.5)

ax.set_xlabel('pr_p_n')
ax.set_ylabel('Взвешенная доля пролонгаций')
ax.set_title('Зависимость взвешенной доли пролонгаций от pr_p_n\n(размер точек = суммарный вес portfolio_share)')
ax.grid(True, alpha=0.3)

# Добавим цветовую шкалу для размера (опционально)
# Но проще оставить как есть

plt.tight_layout()
plt.show()

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Предполагаем, что df, target, weight_col определены

# Создаём копию для экспериментов
df_copy = df.copy()

# Определяем шаги округления для new_delta
bins = [0.5, 1.0, 2.0]

fig, axes = plt.subplots(1, len(bins), figsize=(15, 5))
fig.suptitle('Зависимость взвешенной доли пролонгаций от new_delta (разные шаги округления)', fontsize=14)

for ax, step in zip(axes, bins):
    # Округляем new_delta до заданного шага
    df_copy['new_delta_binned'] = np.round(df_copy['new_delta'] / step) * step
    
    # Группируем по бинам
    grouped = df_copy.groupby('new_delta_binned').apply(
        lambda g: pd.Series({
            'weighted_target': np.average(g[target], weights=g[weight_col]),
            'total_weight': g[weight_col].sum(),
            'count': len(g)
        })
    ).reset_index()
    
    # Удаляем группы с малым объёмом (например, < 1% от общего веса) для чистоты
    total_weight_all = grouped['total_weight'].sum()
    grouped = grouped[grouped['total_weight'] / total_weight_all > 0.01]
    
    grouped = grouped.sort_values('new_delta_binned')
    
    # Строим точки с размером
    ax.scatter(grouped['new_delta_binned'], grouped['weighted_target'],
               s=grouped['total_weight'] / grouped['total_weight'].max() * 200,
               alpha=0.6, edgecolors='k', linewidth=0.5)
    ax.plot(grouped['new_delta_binned'], grouped['weighted_target'], linestyle='--', color='gray', alpha=0.5)
    
    ax.set_xlabel(f'new_delta (шаг {step})')
    ax.set_ylabel('Взвешенная доля')
    ax.set_title(f'Шаг округления = {step}')
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()