Skip to content

Commit 3d87157

Browse files
author
domosedy
committed
feat(exponential): add posterior predictive function
1 parent da200f6 commit 3d87157

1 file changed

Lines changed: 45 additions & 6 deletions

File tree

src/pysatl_core/families/exponential_family.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
DistributionType,
2121
GenericCharacteristicName,
2222
ParametrizationName,
23+
UnivariateContinuous,
2324
)
2425

2526
if TYPE_CHECKING:
@@ -44,9 +45,14 @@ def transform_to_base_parametrization(self) -> ExponentialFamilyParametrization:
4445

4546

4647
@dataclass
47-
class ExponentialConjugateHyperparameters:
48-
effective_suff_stat_value: NumberParameter
49-
effective_sample_size: int
48+
class ExponentialConjugateHyperparameters(Parametrization):
49+
effective_suff_stat_value: NumericArray
50+
effective_sample_size: Number
51+
52+
def transform_to_base_parametrization(self) -> ExponentialFamilyParametrization:
53+
return ExponentialFamilyParametrization(
54+
np.append(self.effective_suff_stat_value, self.effective_sample_size)
55+
)
5056

5157

5258
class ContinuousExponentialClassFamily(ParametricFamily):
@@ -250,10 +256,10 @@ def func(parametrization: Parametrization, x: Any) -> Any:
250256
return func
251257

252258
def posterior_hyperparameters(
253-
self, prior_hyper: ExponentialConjugateHyperparameters, sample: list[Any]
259+
self, parametrizaiton: ExponentialConjugateHyperparameters, sample: list[Any]
254260
) -> ExponentialConjugateHyperparameters:
255-
posterior_effective_suff_stat_value = prior_hyper.effective_suff_stat_value
256-
posterior_effective_sample_size = prior_hyper.effective_sample_size
261+
posterior_effective_suff_stat_value = parametrizaiton.effective_suff_stat_value
262+
posterior_effective_sample_size = parametrizaiton.effective_sample_size
257263
if hasattr(sample, "__iter__") and not isinstance(sample, str):
258264
posterior_effective_suff_stat_value += np.sum(
259265
[self._sufficient(x) for x in sample], # type: ignore[arg-type]
@@ -268,3 +274,36 @@ def posterior_hyperparameters(
268274
effective_suff_stat_value=posterior_effective_suff_stat_value,
269275
effective_sample_size=posterior_effective_sample_size,
270276
)
277+
278+
@property
279+
def posterior_predictive(self) -> ParametricFamily:
280+
def conjugate_log_partition(
281+
parametrization: ExponentialConjugateHyperparameters,
282+
) -> NumberParameter:
283+
conjugate_value = self.conjugate_prior_family._log_partition(
284+
parametrization.transform_to_base_parametrization().theta
285+
)
286+
return np.exp(conjugate_value)
287+
288+
def posterior_density(parametrization: Parametrization, x: NumberParameter) -> Number:
289+
parametrization = cast(ExponentialConjugateHyperparameters, parametrization)
290+
return cast(
291+
np.float32,
292+
self._normalization(x)
293+
* conjugate_log_partition(parametrization)
294+
/ conjugate_log_partition(
295+
self.posterior_hyperparameters(
296+
parametrizaiton=parametrization, sample=[self._sufficient(x)]
297+
)
298+
),
299+
)
300+
301+
family = ParametricFamily(
302+
name=f"PosteriorPredictive{self.name}",
303+
distr_type=UnivariateContinuous,
304+
distr_characteristics={CharacteristicName.PDF: posterior_density},
305+
distr_parametrizations=["posterior"],
306+
support_by_parametrization=lambda _: ContinuousSupport(),
307+
)
308+
parametrization(family=family, name="posterior")(ExponentialConjugateHyperparameters)
309+
return family

0 commit comments

Comments
 (0)