# -*- 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