def test_from_and_to_hist(): h3 = hist.NamedHist( hist.axis.Regular(25, -3.5, 3, name="x", flow=False), hist.axis.Regular(21, -4, 5, name="y", flow=False), storage=hist.storage.Weight(), ) x2 = np.random.randn(1_000) y2 = 0.5 * np.random.randn(1_000) h3.fill(x=x2, y=y2) from zfit._data.binneddatav1 import BinnedData for _ in range(10): # make sure this works many times h1 = BinnedData.from_hist(h3) np.testing.assert_allclose(h1.variances(), h3.variances()) np.testing.assert_allclose(h1.values(), h3.values()) unbinned = h1.to_unbinned() assert unbinned.value().shape[1] == 2 assert unbinned.value().shape[0] == unbinned.weights.shape[0] h3recreated = h1.to_hist() assert h3recreated == h3 bh3 = bh.Histogram(h1) np.testing.assert_allclose(h1.variances(), bh3.variances()) np.testing.assert_allclose(h1.values(), bh3.values())
def __init__( self, data: ztyping.BinnedDataInputType, extended: Optional[ztyping.ExtendedInputType] = None, norm: Optional[ztyping.NormInputType] = None, name: str = "HistogramPDF", ) -> None: """Binned PDF resembling a histogram. Simple histogram PDF that can be used to model a histogram as a PDF. Args: data: Histogram to be used as PDF. extended: |@doc:pdf.init.extended| The overall yield of the PDF. If this is parameter-like, it will be used as the yield, the expected number of events, and the PDF will be extended. An extended PDF has additional functionality, such as the `ext_*` methods and the `counts` (for binned PDFs). |@docend:pdf.init.extended| |@doc:pdf.init.extended.auto| If `True`, the PDF will be extended automatically if the PDF is extended using the total number of events in the histogram. This is the default. |@docend:pdf.init.extended.auto| norm: |@doc:pdf.init.norm| Normalization of the PDF. By default, this is the same as the default space of the PDF. |@docend:pdf.init.norm| name: |@doc:model.init.name| Human-readable name or label of the PDF for better identification. Has no programmatical functional purpose as identification. |@docend:model.init.name| """ if extended is None: extended = True if not isinstance(data, ZfitBinnedData): if isinstance(data, PlottableHistogram): from zfit._data.binneddatav1 import BinnedData data = BinnedData.from_hist(data) else: raise TypeError( "data must be of type PlottableHistogram (UHI) or ZfitBinnedData" ) params = {} if extended is True: self._automatically_extended = True extended = znp.sum(data.values()) else: self._automatically_extended = False super().__init__(obs=data.space, extended=extended, norm=norm, params=params, name=name) self._data = data
def __init__( self, model: ztyping.BinnedPDFInputType, data: ztyping.BinnedDataInputType, constraints: ConstraintsInputType = None, options: OptionsInputType = None, ): model = convert_to_container(model) data = convert_to_container(data) from zfit._data.binneddatav1 import BinnedData data = [ BinnedData.from_hist(d) if (isinstance(d, PlottableHistogram) and not isinstance(d, ZfitBinnedData)) else d for d in data ] not_binned_pdf = [ mod for mod in model if not isinstance(mod, ZfitBinnedPDF) ] not_binned_data = [ dat for dat in data if not isinstance(dat, ZfitBinnedData) ] not_binned_pdf_msg = ( "The following PDFs are not binned but need to be. They can be wrapped in an " f"BinnedFromUnbinnedPDF. {not_binned_pdf} ") not_binned_data_msg = ( "The following datasets are not binned but need to be. They can be converted to a binned " f"using the `to_binned` method. {not_binned_data}") error_msg = "" if not_binned_pdf: error_msg += not_binned_pdf_msg if not_binned_data: error_msg += not_binned_data_msg if error_msg: raise ValueError(error_msg) super().__init__( model=model, data=data, constraints=constraints, fit_range=None, options=options, )
def _convert_input_binned_x(self, x, none_is_space=None): if x is None and none_is_space: return self.space if isinstance(x, uhi.typing.plottable.PlottableHistogram) and not isinstance( x, ZfitBinnedData ): x = BinnedData.from_hist(x) if not isinstance(x, ZfitBinnedData): if not isinstance(x, ZfitSpace): if not isinstance(x, ZfitUnbinnedData): try: x = Data.from_tensor(obs=self.obs, tensor=x) except Exception as error: raise TypeError( f"Data to {self} has to be Binned Data, not {x}. (It can also be unbinned Data)" + f" but conversion to it failed (see also above) with the following error:" + f" {error})" ) from error # TODO: should we allow spaces? Or what? return x
def test_from_and_to_binned(): h3 = hist.Hist( hist.axis.Regular(3, -3, 3, name="x", flow=False), hist.axis.Regular(2, -5, 5, name="y", flow=False), storage=hist.storage.Weight(), ) x2 = np.random.randn(1_000) y2 = 0.5 * np.random.randn(1_000) h3.fill(x=x2, y=y2) from zfit._data.binneddatav1 import BinnedData h1 = BinnedData.from_hist(h3) for _ in range(10): # make sure this works many times unbinned = h1.to_unbinned() binned = unbinned.to_binned(space=h1.space) np.testing.assert_allclose(binned.values(), h1.values()) # we can't test the variances, this info is lost h1 = binned bh3 = bh.Histogram(h1) np.testing.assert_allclose(h1.values(), bh3.values())
def test_with_obs(): from zfit._data.binneddatav1 import BinnedData h1 = hist.NamedHist( hist.axis.Regular(25, -3.5, 3, name="x", flow=False), hist.axis.Regular(21, -4, 5, name="y", flow=False), hist.axis.Regular(15, -2, 1, name="z", flow=False), storage=hist.storage.Weight(), ) x2 = np.random.randn(1_000) y2 = 0.5 * np.random.randn(1_000) z2 = 0.3 * np.random.randn(1_000) h1.fill(x=x2, y=y2, z=z2) h = BinnedData.from_hist(h1) obs = ("x", "y", "z") obs2 = ("y", "x", "z") assert obs == h.obs h2 = h.with_obs(obs2) assert h2.obs == obs2 np.testing.assert_allclose(h.values()[:, 3, 5], h2.values()[3, :, 5]) np.testing.assert_allclose(h.variances()[:, 3, 5], h2.variances()[3, :, 5])