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


# -*- coding: utf-8 -*-
# modules/forecast_modeling.py

import numpy as np
from datetime import datetime, timedelta

def monte_carlo_forecast(pool_values, pool_weights=None, num_simulations=100000, p1=0.05, p2=0.95):
    """
    Выполняет симуляцию методом Монте-Карло.
    :param pool_values: Список значений показателей (пул).
    :return: Словарь с результатами {'lower_bound', 'upper_bound', 'median', 'simulations'}.
    """
    if not pool_values:
        raise ValueError("Пул значений для симуляции пуст.")
        
    probabilities = None if pool_weights is None else np.array(pool_weights) / sum(pool_weights)
    
    results = []
    n = len(pool_values)
    for _ in range(num_simulations):
        # Выбираем случайное количество событий k
        k = np.random.randint(1, n + 1)
        sample = np.random.choice(pool_values, size=k, p=probabilities)
        results.append(np.sum(sample))

    if not results:
        return {"error": "Не удалось получить результаты симуляции."}

    results_array = np.array(results)
    return {
        "lower_bound": float(np.percentile(results_array, p1 * 100)),
        "upper_bound": float(np.percentile(results_array, p2 * 100)),
        "median": float(np.median(results_array)),
        "simulations": results_array.tolist()
    }

def generate_trajectory(lambda_val, days_forward, step_days):
    """
    Генерирует траекторию значений по дням.
    :param lambda_val: Интенсивность событий (в день).
    :param days_forward: Количество дней для прогноза.
    :param step_days: Шаг отображения графика.
    :return: Траектория для графика и полная история ежедневных значений.
    """
    value_pool_positive = [1, 2, 3, 4, 5]
    trajectory = []
    current_value = 0
    daily_values_history = []
    start_date = datetime.now().date() # Определяем дату начала здесь

    for day_offset in range(days_forward + 1):
        daily_sum = 0
        num_events_today = np.random.poisson(lam=lambda_val)
        for _ in range(num_events_today):
            event_value = np.random.choice(value_pool_positive)
            daily_sum += event_value
            
        current_value += daily_sum
        daily_values_history.append(current_value)

        # Вывод в консоль оставлен для наглядности
        current_date = start_date + timedelta(days=day_offset)
        print(f"{current_date}: Событий: {num_events_today:2d}. Итог дня: {daily_sum:6.2f}. Накоплено: {current_value:6.2f}")

        if day_offset % step_days == 0 or day_offset == days_forward:
            trajectory.append(current_value)
            
    return trajectory, daily_values_history

# --- НОВАЯ ФУНКЦИЯ-ОБЕРТКА ---
def make_forecast(lambda_val, days_forward, iterations, s_min, s_max, step_days=1):
    """
    Главный метод для вызова из GUI.
    Объединяет генерацию траектории и расчет границ прогноза.
    :param lambda_val: Параметр интенсивности Пуассона.
    :param days_forward: Горизонт планирования в днях.
    :param iterations: Кол-во итераций для симуляции.
    :param s_min: Нижняя граница квантиля (например, 0.05).
    :param s_max: Верхняя граница квантиля (например, 0.95).
    :param step_days: Шаг построения траектории.
    :return: Результаты симуляции.
    """
    # 1. Генерируем входные данные (траекторию)
    _, trajectory_daily = generate_trajectory(lambda_val, days_forward, step_days)

    # 2. Проводим симуляцию Монте-Карло над полученными данными
    results = monte_carlo_forecast(
        pool_values=trajectory_daily,
        num_simulations=iterations,
        p1=s_min,
        p2=s_max
    )
    return results