From 582a0e708752c877820d260570f383fa3fd35a84 Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Sat, 14 Dec 2024 09:57:16 +0100 Subject: [PATCH] Implementing `add()` method for NormalDist it closes #79 --- CHANGELOG.md | 3 +++ README.md | 37 ++++++++++++++++++++++++++++++------- src/NormalDist.php | 25 +++++++++++++++++++++++++ tests/NormalDistTest.php | 22 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab93dd..55c7d96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 1.1.2 - 2024-12-14 +- Implementing `add()` method for NormalDist + ## 1.1.1 - 2024-12-13 - Implementing fromSample method for NormalDist diff --git a/README.md b/README.md index d6a3f53..33e145e 100644 --- a/README.md +++ b/README.md @@ -489,6 +489,7 @@ $normalDist = new NormalDist(float $mu = 0.0, float $sigma = 1.0); ### Methods #### Creating a normal distribution instance from sample data + The `fromSamples()` static method creates a normal distribution instance with mu and sigma parameters estimated from the sample data. Example: @@ -508,8 +509,8 @@ Calculates the **Probability Density Function** at a given value xxx: $normalDist->pdf(float $x): float ``` -**Input**: The value `$x` at which to evaluate the PDF. -**Output**: The relative likelihood of `$x` in the distribution. +- Input: the value `$x` at which to evaluate the PDF. +- Output: the relative likelihood of `$x` in the distribution. Example: @@ -527,8 +528,9 @@ Calculates the **Cumulative Distribution Function** at a given value `$x`: ```php $normalDist->cdf(float $x): float ``` -**Input**: The value `$x` at which to evaluate the CDF. -**Output**: The probability that a random variable `$x` is less than or equal to `$x`. +- Input: the value `$x` at which to evaluate the CDF. +- Output: the probability that a random variable `$x` is less than or equal to `$x`. + Example: ```php @@ -536,9 +538,7 @@ $normalDist = new NormalDist(10.0, 2.0); echo $normalDist->cdf(12.0); // Output: 0.8413447460685429 ``` ------- - -### Use case example +Calculating both, CDF and PDF: ```php $normalDist = new NormalDist(10.0, 2.0); @@ -554,6 +554,29 @@ echo "CDF at x = 12: $cdf\n"; // Output: 0.8413447460685429 ------ +#### Combining a normal distribution via `add()` method + +The `add()` method allows you to combine a NormalDist instance with either a constant or another NormalDist object. +This operation supports mathematical transformations and the combination of distributions. + +The use cases are: +- Shifting a distribution: add a constant to shift the mean, useful in translating data. +- Combining distributions: combine independent or jointly normally distributed variables, commonly used in statistics and probability. + +```php +$birth_weights = NormalDist::fromSamples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5]); +$drug_effects = new NormalDist(0.4, 0.15); +$combined = $birth_weights->add($drug_effects); + +$combined->getMeanRounded(1); // 3.1 +$combined->getSigmaRounded(1); // 0.5 + +$birth_weights->getMeanRounded(5); // 2.71667 +$birth_weights->getSigmaRounded(5); // 0.50761 +``` + +------ + ### References for NormalDist This class is inspired by Python’s `statistics.NormalDist` and provides similar functionality for PHP users. diff --git a/src/NormalDist.php b/src/NormalDist.php index f1781ca..60ed114 100644 --- a/src/NormalDist.php +++ b/src/NormalDist.php @@ -111,5 +111,30 @@ public function cdfRounded(float $x, int $precision = 3): float } + /** + * Adds a constant or another NormalDist instance to this distribution. + * + * If the argument is: + * - A constant (float): Adjusts the mean (mu), leaving sigma unchanged. + * - A NormalDist instance: Combines the means and variances. + * + * @param float|NormalDist $x2 The value or NormalDist to add. + * @return NormalDist A new NormalDist instance with the updated parameters. + * @throws InvalidDataInputException If the argument is not a float or NormalDist. + */ + public function add(float|NormalDist $x2): NormalDist + { + if ($x2 instanceof NormalDist) { + // Add the means and combine the variances (using the Pythagorean theorem) + $newMu = $this->mu + $x2->mu; + $newSigma = hypot($this->sigma, $x2->sigma); + // sqrt(sigma1^2 + sigma2^2) + return new NormalDist($newMu, $newSigma); + } + // Add a constant to the mean, sigma remains unchanged + return new NormalDist($this->mu + $x2, $this->sigma); + } + + } diff --git a/tests/NormalDistTest.php b/tests/NormalDistTest.php index 485d47d..50112e6 100644 --- a/tests/NormalDistTest.php +++ b/tests/NormalDistTest.php @@ -42,3 +42,25 @@ $normalDist->getSigmaRounded(5), )->toEqual(0.50761); }); + + +it(' add to Normal Dist', function (): void { + $birth_weights = NormalDist::fromSamples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5]); + $drug_effects = new NormalDist(0.4, 0.15); + $combined = $birth_weights->add($drug_effects); + expect( + $combined->getMeanRounded(1), + )->toEqual(3.1); + expect( + $combined->getSigmaRounded(1), + )->toEqual(0.5); + + expect( + $birth_weights->getMeanRounded(5), + )->toEqual(2.71667); + expect( + $birth_weights->getSigmaRounded(5), + )->toEqual(0.50761); + + +});