Source code for hepstats.hypotests.hypotests_object

from ..utils.fit.api_check import is_valid_loss, is_valid_fitresult, is_valid_minimizer
from ..utils.fit.api_check import is_valid_data, is_valid_pdf
from ..utils.fit import get_nevents


[docs]class HypotestsObject(object): """Base object in `hepstats.hypotests` to manipulate a loss function and a minimizer. Args: * **input** : loss or fit result * **minimizer** : minimizer to use to find the minimum of the loss function """ def __init__(self, input, minimizer): if is_valid_fitresult(input): self._loss = input.loss self._bestfit = input elif is_valid_loss(input): self._loss = input self._bestfit = None else: raise ValueError("{} is not a valid loss funtion or fit result!".format(input)) if not is_valid_minimizer(minimizer): raise ValueError("{} is not a valid minimizer !".format(minimizer)) self._minimizer = minimizer self.minimizer.verbosity = 0 self._parameters = {} for m in self.model: for d in m.get_params(): self._parameters[d.name] = d @property def loss(self): """ Returns the loss / likelihood function. """ return self._loss @property def minimizer(self): """ Returns the minimizer. """ return self._minimizer @property def bestfit(self): """ Returns the best fit values of the model parameters. """ if getattr(self, "_bestfit", None): return self._bestfit else: print("Get fit best values!") self.minimizer.verbosity = 5 mininum = self.minimizer.minimize(loss=self.loss) self.minimizer.verbosity = 0 self._bestfit = mininum return self._bestfit @bestfit.setter def bestfit(self, value): """ Set the best fit values of the model parameters. Args: * **value**: fit result """ if not is_valid_fitresult(value): raise ValueError("{} is not a valid fit result!".format(input)) self._bestfit = value @property def model(self): """ Returns the model. """ return self.loss.model @property def data(self): """ Returns the data. """ return self.loss.data @property def constraints(self): """ Returns the constraints on the loss / likehood function. """ return self.loss.constraints
[docs] def get_parameter(self, name): """ Returns the parameter in loss function with given input name. Args: name (str): name of the parameter to return """ return self._parameters[name]
[docs] def set_params_to_bestfit(self): """ Set the values of the parameters in the models to the best fit values """ for m in self.model: for d in m.get_params(): d.set_value(self.bestfit.params[d]["value"])
[docs] def lossbuilder(self, model, data, weights=None): """ Method to build a new loss function. Args: * **model** (List): The model or models to evaluate the data on * **data** (List): Data to use * **weights** (optional, List): the data weights Example with `zfit`: >>> data = zfit.data.Data.from_numpy(obs=obs, array=np.random.normal(1.2, 0.1, 10000)) >>> mean = zfit.Parameter("mu", 1.2) >>> sigma = zfit.Parameter("sigma", 0.1) >>> model = zfit.pdf.Gauss(obs=obs, mu=mean, sigma=sigma) >>> loss = calc.lossbuilder(model, data) Returns: Loss function """ assert all(is_valid_pdf(m) for m in model) assert all(is_valid_data(d) for d in data) msg = "{0} must have the same number of components as {1}" if len(data) != len(self.data): raise ValueError(msg.format("data", "`self.data")) if len(model) != len(self.model): raise ValueError(msg.format("model", "`self.model")) if weights is not None and len(weights) != len(self.data): raise ValueError(msg.format("weights", "`self.data`")) if weights is not None: for d, w in zip(data, weights): d.set_weights(w) loss = type(self.loss)(model=model, data=data) loss.add_constraints(self.constraints) return loss
[docs]class ToysObject(HypotestsObject): """Base object in `hepstats.hypotests` to manipulate a loss function, a minimizer and sample a model (within the loss function) to do toy experiments. Args: * **input** : loss or fit result * **minimizer** : minimizer to use to find the minimum of the loss function * **sampler** : function used to create sampler with models, number of events and floating parameters in the sample. * **sample** : function used to get samples from the sampler. """ def __init__(self, input, minimizer, sampler, sample): super(ToysObject, self).__init__(input, minimizer) self._toys = {} self._sampler = sampler self._sample = sample self._toys_loss = {}
[docs] def sampler(self, floating_params=None): """ Create sampler with models. Args: * **floating_params** (list): floating parameters in the sampler Example with `zfit`: >>> sampler = calc.sampler(floating_params=[zfit.Parameter("mean")]) """ self.set_params_to_bestfit() nevents = [] for m, d in zip(self.loss.model, self.loss.data): if m.is_extended: nevents.append("extended") else: nevents.append(get_nevents(d)) return self._sampler(self.loss.model, nevents, floating_params)
[docs] def sample(self, sampler, ntoys, poi=None): """ Returns the samples generated from the sampler for a given value of a parameter of interest Args: * **sampler** (list): generator of samples * **ntoys** (int): number of samples to generate * **poi** (POI, optional): in the sampler Example with `zfit`: >>> mean = zfit.Parameter("mean") >>> sampler = calc.sampler(floating_params=[mean]) >>> sample = calc.sample(sampler, 1000, POI(mean, 1.2)) """ return self._sample(sampler, ntoys, parameter=poi.parameter, value=poi.value)
[docs] def toys_loss(self, parameter_name): """ Construct a loss function constructed with a sampler for a given floating parameter Args: * **parameter_name**: name floating parameter in the sampler Returns: Loss function Example with `zfit`: >>> loss = calc.toys_loss(zfit.Parameter("mean")) """ if parameter_name not in self._toys_loss: parameter = self.get_parameter(parameter_name) sampler = self.sampler(floating_params=[parameter]) self._toys_loss[parameter.name] = self.lossbuilder(self.model, sampler) return self._toys_loss[parameter_name]