Source code for preliz.unidimensional.combine_roulette

import numpy as np

from preliz.internal.distribution_helper import get_distributions, process_extra
from preliz.internal.optimization import fit_to_epdf


[docs] def combine_roulette(responses, weights=None, dist_names=None, params=None): """ Combine multiple elicited distributions into a single distribution. Parameters ---------- responses : list of tuples Typically, each tuple comes from the ``.inputs`` attribute of a ``Roulette`` object and represents a single elicited distribution. weights : array-like, optional Weights for each elicited distribution. Defaults to None, i.e. equal weights. The sum of the weights must be equal to 1, otherwise it will be normalized. dist_names: list List of distributions names to be used in the elicitation. Defaults to ["Normal", "BetaScaled", "Gamma", "LogNormal", "StudentT"]. params : str, optional Extra parameters to be passed to the distributions. The format is a string with the PreliZ's distribution name followed by the argument to fix. For example: "TruncatedNormal(lower=0), StudentT(nu=8)". Returns ------- PreliZ distribution """ if params is not None: extra_pros = process_extra(params) else: extra_pros = [] if weights is None: weights = np.full(len(responses), 1 / len(responses)) else: weights = np.array(weights, dtype=float) if np.any(weights < 0): raise ValueError("The weights must be positive.") weights /= weights.sum() if not all(records[3:] == responses[0][3:] for records in responses): raise ValueError( "To combine single elicitation instances, the grid should be the same for all of them." ) if dist_names is None: dist_names = ["Normal", "BetaScaled", "Gamma", "LogNormal", "StudentT"] new_pdf = {} for records, weight in zip(responses, weights): chips = records[2] for x_i, pdf_i in zip(records[0], records[1]): if x_i in new_pdf: new_pdf[x_i] += pdf_i * weight * chips else: new_pdf[x_i] = pdf_i * weight * chips total = sum(new_pdf.values()) mean = 0 for x_i, pdf_i in new_pdf.items(): val = pdf_i / total mean += x_i * val new_pdf[x_i] = val var = 0 for x_i, pdf_i in new_pdf.items(): var += pdf_i * (x_i - mean) ** 2 std = var**0.5 # Assuming all the elicited distributions have the same x_min and x_max x_min = responses[0][3] x_max = responses[0][4] fitted_dist = fit_to_epdf( get_distributions(dist_names), list(new_pdf.keys()), list(new_pdf.values()), mean, std, x_min, x_max, extra_pros, ) return fitted_dist