mp_distr.py
· 1.8 KiB · Python
Originalformat
import numpy as np
from numpy.typing import ArrayLike
class MarchenkoPastur:
"""Definition of a Marchenko-Pastur distribution"""
def __init__(self, ratio: float, sigma: float = 1.0):
"""
Parameters
----------
ratio : float
The ratio between the number of variables (columns) and the size of the sample (rows) contained in the data matrix.
For numerical stability, it should be less than 1.
sigma : float
The standard deviation of the distribution of values, by default, 1.0.
Raises
------
ValueError
If ratio or sigma are not strictly positive.
"""
if ratio <= 0.0:
raise ValueError("The ratio must be strictly positive, but found %s <= 0.0!" % ratio)
self.ratio = ratio
if sigma <= 0.0:
raise ValueError("The standard deviation must be strictly positive, but found %s <= 0.0!" % sigma)
self.sigma = sigma
# Compute the limits of the distribution
self.l_bottom = self.sigma**2 * (1.0 - np.sqrt(self.ratio))**2
self.l_upper = self.sigma**2 * (1.0 + np.sqrt(self.ratio))**2
def pdf(self, x: float | ArrayLike) -> float | ArrayLike:
"""
Return the value of the probability distribution function.
Parameters
----------
x : float | ArrayLike
The value(s) at which to compute the PDF.
Returns
-------
float | ArrayLike
The value(s) of the PDF
"""
if not np.isscalar(x):
return np.vectorize(self.pdf, otypes=[float])(x)
if x == 0.0:
return 0.0
num = np.sqrt(max(self.l_upper - x, 0.0) * max(x - self.l_bottom, 0.0))
den = 2.0 * np.pi * self.sigma**2 * self.ratio * x
return float(num / den)
| 1 | import numpy as np |
| 2 | |
| 3 | from numpy.typing import ArrayLike |
| 4 | |
| 5 | class MarchenkoPastur: |
| 6 | """Definition of a Marchenko-Pastur distribution""" |
| 7 | |
| 8 | def __init__(self, ratio: float, sigma: float = 1.0): |
| 9 | """ |
| 10 | Parameters |
| 11 | ---------- |
| 12 | ratio : float |
| 13 | The ratio between the number of variables (columns) and the size of the sample (rows) contained in the data matrix. |
| 14 | For numerical stability, it should be less than 1. |
| 15 | sigma : float |
| 16 | The standard deviation of the distribution of values, by default, 1.0. |
| 17 | |
| 18 | Raises |
| 19 | ------ |
| 20 | ValueError |
| 21 | If ratio or sigma are not strictly positive. |
| 22 | """ |
| 23 | if ratio <= 0.0: |
| 24 | raise ValueError("The ratio must be strictly positive, but found %s <= 0.0!" % ratio) |
| 25 | self.ratio = ratio |
| 26 | if sigma <= 0.0: |
| 27 | raise ValueError("The standard deviation must be strictly positive, but found %s <= 0.0!" % sigma) |
| 28 | self.sigma = sigma |
| 29 | |
| 30 | # Compute the limits of the distribution |
| 31 | self.l_bottom = self.sigma**2 * (1.0 - np.sqrt(self.ratio))**2 |
| 32 | self.l_upper = self.sigma**2 * (1.0 + np.sqrt(self.ratio))**2 |
| 33 | |
| 34 | def pdf(self, x: float | ArrayLike) -> float | ArrayLike: |
| 35 | """ |
| 36 | Return the value of the probability distribution function. |
| 37 | |
| 38 | Parameters |
| 39 | ---------- |
| 40 | x : float | ArrayLike |
| 41 | The value(s) at which to compute the PDF. |
| 42 | |
| 43 | Returns |
| 44 | ------- |
| 45 | float | ArrayLike |
| 46 | The value(s) of the PDF |
| 47 | """ |
| 48 | if not np.isscalar(x): |
| 49 | return np.vectorize(self.pdf, otypes=[float])(x) |
| 50 | |
| 51 | if x == 0.0: |
| 52 | return 0.0 |
| 53 | |
| 54 | num = np.sqrt(max(self.l_upper - x, 0.0) * max(x - self.l_bottom, 0.0)) |
| 55 | den = 2.0 * np.pi * self.sigma**2 * self.ratio * x |
| 56 | |
| 57 | return float(num / den) |