Skip to content

Commit

Permalink
Merge pull request #75 from Hi-Folks/feat/75-normaldist
Browse files Browse the repository at this point in the history
Add NormalDist Class with pdf and cdf Methods
  • Loading branch information
roberto-butti authored Dec 10, 2024
2 parents e626ec1 + 1b6feb1 commit 35de12b
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 2 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Changelog

## 1.0.2 - WIP

## 1.0.2 - 2024-12-10
- NormalDist class, with `cdf()` and `pdf()`
- Fix deprecations for PHP 8.4

## 1.0.1 - 2024-11-21
Expand Down
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,92 @@ Array
*/

```
## `NormalDist` class

The `NormalDist` class provides an easy way to work with normal distributions in PHP. It allows you to calculate probabilities and densities for a given mean (μ\muμ) and standard deviation (σ\sigmaσ).

### Key features

- Define a normal distribution with mean (μ\muμ) and standard deviation (σ\sigmaσ).
- Calculate the **Probability Density Function (PDF)** to evaluate the relative likelihood of a value.
- Calculate the **Cumulative Distribution Function (CDF)** to determine the probability of a value or lower.

------

### Class constructor

```php
$normalDist = new NormalDist(float $mu = 0.0, float $sigma = 1.0);
```

- `$mu`: The mean (default = `0.0`).
- `$sigma`: The standard deviation (default = `1.0`).
- Throws an exception if `$sigma` is non-positive.

------

### Methods

#### 1. `pdf($x)`

Calculates the **Probability Density Function** at a given value xxx:

```php
$normalDist->pdf(float $x): float
```

**Input**: The value `$x` at which to evaluate the PDF.
**Output**: The relative likelihood of `$x` in the distribution.

Example:

```php
$normalDist = new NormalDist(10.0, 2.0);
echo $normalDist->pdf(12.0); // Output: 0.12098536225957168
```

------

#### 2. `cdf($x)`

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`.
Example:

```php
$normalDist = new NormalDist(10.0, 2.0);
echo $normalDist->cdf(12.0); // Output: 0.8413447460685429
```

------

### Use case example

```php
$normalDist = new NormalDist(10.0, 2.0);

// Calculate PDF at x = 12
$pdf = $normalDist->pdf(12.0);
echo "PDF at x = 12: $pdf\n"; // Output: 0.12098536225957168

// Calculate CDF at x = 12
$cdf = $normalDist->cdf(12.0);
echo "CDF at x = 12: $cdf\n"; // Output: 0.8413447460685429
```

------

### References for NormalDist

This class is inspired by Python’s `statistics.NormalDist` and provides similar functionality for PHP users.



## Testing

```bash
Expand Down
82 changes: 82 additions & 0 deletions src/NormalDist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace HiFolks\Statistics;

use HiFolks\Statistics\Exception\InvalidDataInputException;

class NormalDist
{
// Mean

private readonly float $sigma; // Standard deviation

// Constructor to initialize mu and sigma
public function __construct(private readonly float $mu = 0.0, float $sigma = 1.0)
{
if ($sigma < 0) {
throw new InvalidDataInputException('Standard deviation (sigma) cannot be negative.');
}
$this->sigma = $sigma;
}

// Getter for mean (read-only)
public function getMean(): float
{
return $this->mu;
}

// Getter for standard deviation (read-only)
public function getSigma(): float
{
return $this->sigma;
}

// A utility function to calculate the probability density function (PDF)
public function pdf(float $x): float
{
$coeff = 1 / (sqrt(2 * M_PI) * $this->sigma);
$exponent = -($x - $this->mu) ** 2 / (2 * $this->sigma ** 2);

return $coeff * exp($exponent);
}

public function pdfRounded(float $x, int $precision = 3): float
{
return round($this->pdf($x), $precision);
}

// Approximate the error function (erf)
private function erf(float $z): float
{
$t = 1 / (1 + 0.5 * abs($z));
$tau = $t * exp(-$z * $z
- 1.26551223
+ 1.00002368 * $t
+ 0.37409196 * $t ** 2
+ 0.09678418 * $t ** 3
- 0.18628806 * $t ** 4
+ 0.27886807 * $t ** 5
- 1.13520398 * $t ** 6
+ 1.48851587 * $t ** 7
- 0.82215223 * $t ** 8
+ 0.17087277 * $t ** 9);
return $z >= 0 ? 1 - $tau : $tau - 1;
}


// A utility function to calculate the cumulative density function (CDF)
public function cdf(float $x): float
{
$z = ($x - $this->mu) / ($this->sigma * sqrt(2));

return 0.5 * (1 + $this->erf($z));
}

public function cdfRounded(float $x, int $precision = 3): float
{
return round($this->cdf($x), $precision);
}



}
30 changes: 30 additions & 0 deletions tests/NormalDistTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use HiFolks\Statistics\NormalDist;

it(' init normal dist', function (): void {
$nd = new NormalDist(1060, 195);
expect(
$nd->getMean(),
)->toEqual(1060);
expect(
$nd->getSigma(),
)->toEqual(195);

});
it('can calculate normal dist cdf', function (): void {
$nd = new NormalDist(1060, 195);
expect(
round($nd->cdf(1200 + 0.5) - $nd->cdf(1100 - 0.5), 3),
)->toEqual(0.184);
});

it('can calculate normal dist pdf', function (): void {
$nd = new NormalDist(10, 2);
expect(
$nd->pdfRounded(12, 3),
)->toEqual(0.121);
expect(
$nd->pdfRounded(12, 2),
)->toEqual(0.12);
});

0 comments on commit 35de12b

Please sign in to comment.