# -*- coding: utf-8 -*-
# modules/forecasting.py
import numpy as np
def monte_carlo_forecast(pool_values, pool_weights=None, num_simulations=100000, p1=0.05, p2=0.95):
"""
Выполняет симуляцию методом Монте-Карло с учетом весов.
:param pool_values: Список значений показателей (пул).
:param pool_weights: Список весов для каждого показателя. Если None, используется равновероятный выбор.
:param num_simulations: Количество итераций симуляции.
:param p1: Нижняя граница квантиля (например, 0.05).
:param p2: Верхняя граница квантиля (например, 0.95).
:return: Словарь с результатами.
"""
if not pool_values:
raise ValueError("Пул значений для симуляции пуст.")
# Если веса не заданы, создаем массив из единиц (равновероятный выбор)
if pool_weights is None:
probabilities = None
else:
# Важно: веса должны быть приведены к вероятностям (сумма = 1)
total_weight = sum(pool_weights)
probabilities = np.array(pool_weights) / total_weight
results = []
n = len(pool_values)
for _ in range(num_simulations):
# Выбираем k - размер подмножества. Для простоты возьмем случайное от 1 до n
k = np.random.randint(1, n + 1)
# Выбираем k элементов из пула с учетом весов
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()
}