try:
import numpy as np
import scipy.special as ss
from typing import Union, Tuple, Dict, List
import math as m
from univariate._base import Base
except Exception as e:
print(f"some modules are missing {e}")
[docs]class BoundedInterval(Base):
"""
Description:
Base class for probability tags.
"""
def __init__(self):
if type(self) is BoundedInterval:
raise TypeError('base class cannot be instantiated.')
[docs]class Arcsine(BoundedInterval):
"""
This class contains methods concerning Arcsine Distirbution [#]_.
.. math::
\\text{Arcsine}(x)={\\frac{1}{\\pi \\sqrt{x(1-x)}}}
Args:
x(float): random variable between 0 and 1
Reference:
.. [#] Wikipedia contributors. (2020, October 30). Arcsine distribution. https://en.wikipedia.org/w/index.php?title=Arcsine_distribution&oldid=986131091
"""
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variables
Raises:
ValueError: when there exist a value less than 0 or greater than 1
TypeError: when parameter is not of type float | List[float] | numpy.ndarray
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x <= 0) | (x >= 1)):
raise ValueError(
f'random variable should have values between [0,1].')
return 1/(m.pi * np.sqrt(x*(1-x)))
if type(x) is float:
if x < 0 or x > 1:
raise ValueError(
f'random variable should have values between [0,1].')
return 1/m.pi*m.sqrt(x * (1-x))
raise TypeError(
'parameter x is expected to be of type float | List[float] | numpy.ndarray')
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point
Raises:
ValueError: when there exist a value less than 0 or greater than 1
TypeError: when parameter is not of type float | List[float] | numpy.ndarray
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x <= 0) | (x >= 1)):
raise ValueError(
f'values can only be evaluated in the domain [0,1]')
return 1/(m.pi)*np.arcsin(np.sqrt(x))
if type(x) is float:
if x <= 0 or x >= 1:
raise ValueError(
f'values can only be evaluated in the domain [0,1]')
return 1/m.pi * m.asin(m.sqrt(x))
raise TypeError(
'parameter x is expected to be of type float | List[float] | numpy.ndarray')
[docs] def mean(self) -> float:
"""
Returns:
mean of Arcsine distribution.
"""
return 0.5
[docs] def mode(self) -> Tuple[float, float]:
"""
Returns:
mode of Arcsine distribution
"""
return (0, 1)
[docs] def var(self) -> float:
"""
Returns:
variance of Arcsine distribution
"""
return 0.125
[docs] def std(self) -> float:
"""
Returns:
standard deviation of Arcsine distribution
"""
return m.sqrt(0.125)
[docs] def skewness(self) -> float:
"""
Returns:
skewness of Arcsine distribution
"""
return 0.0
[docs] def kurtosis(self) -> float:
"""
Returns:
kurtosis of Arcsine distribution
"""
return 1.5
[docs] def entropy(self) -> float:
"""
Returns:
entropy of Arcsine distribution
"""
return m.log(m.pi/4)
[docs] def summary(self) -> Dict[str, Union[float, Tuple[float, float]]]:
"""
Returns:
Dictionary of Arcsine distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Beta(BoundedInterval):
"""
This class contains methods concerning Beta Distirbution [#]_.
.. math::
\\text{Beta}(x; \\alpha, \\beta) = \\frac{x^{\\alpha-1}(1-x)^{\\beta-1}}{\\text{B}(\\alpha, \\beta)}
Args:
alpha(float): shape parameter where alpha > 0
beta(float): shape parameter where beta > 0
x(float): random variable where x is between 0 and 1
Reference:
.. [#] Wikipedia contributors. (2021, January 8). Beta distribution. https://en.wikipedia.org/w/index.php?title=Beta_distribution&oldid=999043368
"""
def __init__(self, alpha: float, beta: float):
if alpha < 0:
raise ValueError(
f'alpha parameter(shape) should be a positive number. Entered value:{alpha}')
if beta < 0:
raise ValueError(
f'beta parameter(shape) should be a positive number. Entered value:{beta}')
self.alpha = alpha
self.beta = beta
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value x <= 0 or x <= 1
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a = self.alpha
b = self.beta
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x <= 0) | (x >= 1)):
raise ValueError(
'random variables should only be between 0 and 1')
return (np.power(x, a-1)*np.power(1-x, b-1))/ss.beta(a, b)
if x <= 0 or x >= 1:
raise ValueError('random variables should only be between 0 and 1')
return (pow(x, a-1)*pow(1-x, b-1))/ss.beta(a, b)
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
a = self.alpha
b = self.beta
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
return ss.betainc(a, b, x)
return ss.betainc(a, b, x)
[docs] def mean(self) -> str:
"""
Returns: Mean of the Beta distribution.
"""
return "currently unsupported."
[docs] def mode(self) -> str:
"""
Returns: Mode of the Beta distribution.
"""
return "currently unsupported"
[docs] def var(self) -> str:
"""
Returns: Variance of the Beta distribution.
"""
return "currently unsupported"
[docs] def std(self) -> str:
"""
Returns: Variance of the Beta distribution.
"""
return "currently unsupported"
[docs] def skewness(self) -> float:
"""
Returns: Skewness of the Beta distribution.
"""
alpha = self.alpha
beta = self.beta
return (2*(beta-alpha)*m.sqrt(alpha+beta+1))/((alpha+beta+2)*m.sqrt(alpha*beta))
[docs] def kurtosis(self) -> float:
"""
Returns: Kurtosis of the Beta distribution.
"""
alpha = self.alpha
beta = self.beta
temp_up = 6*((alpha-beta)**2*(alpha+beta+1)-alpha*beta*(alpha+beta+2))
return temp_up/(alpha*beta*(alpha+beta+2)*(alpha+beta+3))
[docs] def entropy(self) -> float:
"""
Returns: differential entropy of the Beta distribution.
Reference: Park, S.Y. & Bera, A.K.(2009). Maximum entropy autoregressive conditional heteroskedasticity model. Elsivier.
link: http://wise.xmu.edu.cn/uploadfiles/paper-masterdownload/2009519932327055475115776.pdf
"""
alpha = self.alpha
beta = self.beta
return m.log(ss.beta(alpha, beta))-(alpha-1)*(ss.digamma(alpha)-ss.digamma(alpha+beta))-(beta-1)*(ss.digamma(beta)-ss.digamma(alpha+beta))
[docs] def summary(self) -> Dict[str, Union[float, str]]:
"""
Returns:
Dictionary of Beta distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class BetaRectangular(BoundedInterval):
"""
This class contains methods concerning Beta-rectangular Distirbution.
Thus it is a bounded distribution that allows for outliers to have a greater chance of occurring than does the beta distribution [#]_ .
.. math::
\\text{BetaRectangulat}(x,\\alpha ,\\beta ,\\theta )={\\begin{cases}{\\frac{\\theta \\Gamma (\\alpha +\\beta )}{\\Gamma (\\alpha )\\Gamma (\\beta )}}{\\frac{(x-a)^{{\\alpha -1}}(b-x)^{{\\beta -1}}}{(b-a)^{{\\alpha +\\beta +1}}}}+{\\frac{1-\\theta }{b-a}}&{\mathrm{for}}\ a\leq x\leq b,\\\[8pt]0&{\\mathrm{for}}\ x<a\{\\mathrm{or}}\ x>b\\end{cases}}
Args:
alpha(float): shape parameter
beta (float): shape parameter
theta(float): mixture parameter where 0 < theta < 1
min(float): lower bound
max(float): upper bound
x(float): random variable where alpha <= x<= beta
Reference:
.. [#] Wikipedia contributors. (2020, December 7). Beta rectangular distribution. https://en.wikipedia.org/w/index.php?title=Beta_rectangular_distribution&oldid=992814814
"""
def __init__(self, alpha: float, beta: float, theta: float, min: float, max: float, randvar: float):
if alpha < 0 or beta < 0:
raise ValueError(
'alpha and beta parameter should not be less that 0. Entered values: alpha: {alpha}, beta: {beta}}')
if theta < 0 or theta > 1:
raise ValueError(
'random variable should only be in between 0 and 1. Entered value: {theta}')
if randvar < min and randvar > max:
raise ValueError(
f'random variable should be between alpha and beta shape parameters. Entered value:{randvar}')
self.alpha = alpha
self.beta = beta
self.theta = theta
self.min = min
self.max = max
self.randvar = randvar
[docs] def pdf(self, x: [List[float], np.ndarray, float]) -> Union[float,
np.ndarray]: ...
[docs] def mean(self) -> float:
"""
Returns: Mean of the Beta-rectangular distribution.
"""
alpha = self.alpha
beta = self.beta
theta = self.theta
a = self.min
b = self.max
return a+(b-a)*((theta*alpha)/(alpha+beta)+(1-theta)/2)
[docs] def var(self) -> float:
"""
Returns: Variance of the Beta-rectangular distribution.
"""
alpha = self.alpha
beta = self.beta
theta = self.theta
a = self.min
b = self.max
k = alpha+beta
return (b-a)**2*((theta*alpha*(alpha+1))/(k*(k+1))+(1-theta)/3-(k+theta*(alpha-beta))**2/(4*k**2))
[docs] def std(self) -> float:
"""
Returns: Standard deviation of the Beta-rectangular distribution.
"""
return m.sqrt(self.var())
[docs] def summary(self) -> Dict[str, Union[float, Tuple[float]]]:
"""
Summary statistic regarding the Beta-rectangular distribution which contains the following parts of the distribution:
(mean, median, mode, var, std, skewness, kurtosis).
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Bernoulli(BoundedInterval):
"""
This class contains methods concerning Continuous Bernoulli Distirbution.
The continuous Bernoulli distribution arises in deep learning and computer vision,
specifically in the context of variational autoencoders, for modeling the
pixel intensities of natural images [#]_ [#]_ [#]_ [#]_.
.. math:: C(\\lambda)\\lambda^{x}(1-\\lambda)^{1-x}
where
.. math:: C(\\lambda)= \\begin{cases}2&{\\text{if }\\lambda =\\frac {1}{2}} \\ \\frac{2\\tanh^{-1}(1-2\\lambda )}{1-2\\lambda }&{\\text{ otherwise}}\\end{cases}
Args:
shape(float): parameter
x(float): random variable where x is between 0 and 1
Reference:
.. [#] Wikipedia contributors. (2020, November 2). Continuous Bernoulli distribution. https://en.wikipedia.org/w/index.php?title=Continuous_Bernoulli_distribution&oldid=986761458
.. [#] Kingma, D. P., & Welling, M. (2013). Auto-encoding variational bayes. arXiv preprint arXiv:1312.6114.
.. [#] Kingma, D. P., & Welling, M. (2014, April). Stochastic gradient VB and the variational auto-encoder.In Second International Conference on Learning Representations, ICLR (Vol. 19).
.. [#] Ganem, G & Cunningham, J.P. (2019). The continouous Bernoulli: fixing a pervasive error in variational autoencoders. https://arxiv.org/pdf/1907.06845.pdf
"""
def __init__(self, shape: float):
if shape < 0 or shape > 1:
raise ValueError(
'shape parameter a should only be in between 0 and 1.')
self.shape = shape
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value less than 0 or greater than 1
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
shape = self.shape
def __C(shape: float) -> float:
return (2*m.atanh(1-2*shape)) / (1-2*shape) if shape != 0.5 else 2.0
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x <= 0)|(x >= 1)):
raise ValueError('random variable must be between 0 and 1')
return __C(self.shape) * np.power(shape, x)*np.power(1-shape, 1-x)
if x <= 0 or x >= 1:
raise ValueError('random variable must be between 0 and 1')
return __C(self.shape)*pow(shape, x)*pow(1-shape, 1 - x)
[docs] def cdf(self, x: Union[List[float], np.ndarray]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray]): data point(s) of interest
Raises:
ValueError: when there exist a value <= 0 or >= 1
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
shape = self.shape
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x <= 0)|(x >= 1)):
raise ValueError('values must be between 0 and 1')
return (np.power(shape, x)*np.power(1-shape, 1-x) + shape - 1)/(1-2*shape) if shape != 0.5 else x
return (shape**x*pow(1-shape, 1-x)+shape-1)/(2*shape-1) if shape != 0.5 else x
[docs] def mean(self) -> float:
"""
Returns: Mean of the Continuous Bernoulli distribution.
"""
shape = self.shape
if shape == 0.5:
return 0.5
return shape/(2*shape-1)+(1/(2*np.arctanh(1-2*shape)))
[docs] def var(self) -> float:
"""
Returns: Variance of the Continuous Bernoulli distribution.
"""
shape = self.shape
if shape == 0.5:
return 0.08333333333333333
return shape/((2*shape-1)**2)+1/(2*np.arctanh(1-2*shape))**2
[docs] def std(self) -> float:
"""
Returns: Standard deviation of the Continuous Bernoulli distribution
"""
return m.sqrt(self.var())
[docs] def summary(self) -> Dict[str, Union[float, Tuple[float]]]:
"""
Returns:
Dictionary of Continuous Bernoulli distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Bates(BoundedInterval):
"""
This class contains methods concerning Bates Distirbution. Also referred to as the regular mean distribution.
Note that the Bates distribution is a probability distribution of the mean of a number of statistically indipendent uniformly
distirbuted random variables on the unit interval. This is often confused with the Irwin-Hall distribution which is
the distribution of the sum (not the mean) of n independent random variables. The two distributions are simply versions of
each other as they only differ in scale [#]_.
Args:
a(float): lower bound parameter
b(float): upper bound parameter where b > a
n(int): where n >= 1
randvar(float): random variable where a <= x <= b
Reference:
.. [#] Wikipedia contributors. (2021, January 8). Bates distribution. https://en.wikipedia.org/w/index.php?title=Bates_distribution&oldid=999042206
"""
def __init__(self, a: float, b: float, n: int, randvar: float):
if randvar < 0 or randvar > 1:
raise ValueError(
f'random variable should only be in between 0 and 1. Entered value: {randvar}')
if a > b:
raise ValueError(
'lower bound (a) should not be greater than upper bound (b).')
if type(n) is not int:
raise TypeError('parameter n should be an integer type.')
self.a = a
self.b = b
self.n = n
self.randvar = randvar
[docs] def cdf(self, x: Union[List[float], np.ndarray] = None) -> Union[float, np.ndarray]:
"""
Args:
x (List[float], numpy.ndarray): random variable or list of random variables
Returns:
either cumulative distribution evaluation for some point or plot of Bates distribution.
"""
return "currently unsupported"
[docs] def mean(self) -> float:
"""
Returns: Mean of the Bates distribution.
"""
return 0.5*(self.a+self.b)
[docs] def var(self) -> float:
"""
Returns: Variance of the Bates distribution.
"""
return 1/(12*self.n)*pow(self.b-self.a, 2)
[docs] def std(self) -> float:
"""
Returns: Standard devtiation of the Bates distribution
"""
return m.sqrt(1/(12*self.n)*pow(self.b-self.a, 2))
[docs] def skewness(self) -> float:
"""
Returns: Skewness of the Bates distribution.
"""
return -6/(5*self.n)
[docs] def kurtosis(self) -> float:
"""
Returns: Kurtosis of the Bates distribution.
"""
return 0.0
[docs] def summary(self) -> Dict[str, Union[float, Tuple[float]]]:
"""
Summary statistic regarding the Bates distribution which contains the following parts of the distribution:
(mean, median, mode, var, std, skewness, kurtosis).
Returns:
Dict[str, Union[float, Tuple[float]]]: [description]
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Triangular(BoundedInterval):
"""
This class contains methods concerning Triangular Distirbution [#]_.
Args:
a(float): lower limit parameter
b(float): upper limit parameter where a < b
c(float): mode parameter where a <= c <= b
randvar(float): random variable where a <= x <= b
Reference:
.. [#] Wikipedia contributors. (2020, December 19). Triangular distribution. https://en.wikipedia.org/w/index.php?title=Triangular_distribution&oldid=995101682
"""
def __init__(self, a: float, b: float, c: float):
if a > b:
raise ValueError(
'lower limit(a) should be less than upper limit(b).')
if a > c and c > b:
raise ValueError(
'lower limit(a) should be less than or equal to mode(c) where c is less than or equal to upper limit(b).')
self.a = a
self.b = b
self.c = c
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value of a > x or x > b
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a, b, c = self.a, self.b, self.c
def __generator(a: float, b: float, c: float, x: float) -> float:
if x < a:
return 0.0
if a <= x and x < c:
return (2*(x-a))/((b-a)*(c-a))
if x == c:
return 2/(b-a)
if c < x and x <= b:
return 2*(b-x)/((b-a)*((b-c)))
if b < x:
return 0.0
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((a > x) | (x > b)):
raise ValueError(
'all random variables are expected to be between a and b parameters')
return np.vectorize(__generator)(a, b, c, x)
if a > x or x > b:
raise ValueError(
'all random variables are expected to be between a and b parameters')
return __generator(a, b, c, x)
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation fo cdf at x
"""
a, b, c = self.a, self.b, self.c
def __generator(a: float, b: float, c: float, x: float) -> float:
if x <= a:
return 0.0
if a < x and x <= c:
return pow(x-a, 2)/((b-a)*(c-a))
if c < x and x < b:
return 1 - pow(b-x, 2)/((b-c)*(b-c))
if b <= x:
return 1.0
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
return np.vectorize(__generator)(a, b, c, x)
return __generator(a, b, c, x)
[docs] def mean(self) -> float:
"""
Returns: Mean of the Triangular distribution.
"""
return (self.a+self.b+self.c)/3
[docs] def mode(self) -> float:
"""
Returns: Mode of the Triangular distribution.
"""
return self.c
[docs] def var(self) -> float:
"""
Returns: Variance of the Triangular distribution.
"""
a = self.a
b = self.b
c = self.c
return (1/18)*(pow(a, 2)+pow(b, 2)+pow(c, 2)-a*b-a*c-b*c)
[docs] def std(self) -> float:
"""
Returns: Standard deviation of the Triangular distribution.
"""
return m.sqrt(self.var())
[docs] def skewness(self) -> float:
"""
Returns: Skewness of the Triangular distribution.
"""
a = self.a
b = self.b
c = self.c
return m.sqrt(2)*(a+b-2*c) * ((2*a-b-c)*(a-2*b+c)) / \
(5*pow(a**2+b**2+c**2-a*b-a*c-b*c, 3/2))
[docs] def kurtosis(self) -> float:
"""
Returns: Kurtosis of the Triangular distribution.
"""
return -3/5
[docs] def entropy(self) -> float:
"""
Returns: differential entropy of the Triangular distribution.
Reference: Park, S.Y. & Bera, A.K.(2009). Maximum entropy autoregressive conditional heteroskedasticity model. Elsivier.
link: http://wise.xmu.edu.cn/uploadfiles/paper-masterdownload/2009519932327055475115776.pdf
"""
return 0.5 + m.log((self.b-self.a)*0.5)
[docs] def summary(self) -> Dict[str, float]:
"""
Returns:
Dictionary of Triangular distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class LogitNormal(BoundedInterval):
"""
This class contains methods concerning Logit Normal Distirbution [#]_.
.. math::
\\text{LogitNormal}(x;\\mu,\\sigma) = \\frac{1}{\\sigma \\sqrt{2\\pi} \\cdot x(1-x)} \\exp{\\Big(-\\frac{(logit(x)-\\mu)^2}{2\\sigma^2} \\Big)}
Args:
sq_scale (float): squared scale parameter
location(float): location parameter
x(float): random variable where x is between 0 and 1
Reference:
.. [#] Wikipedia contributors. (2020, December 9). Logit-normal distribution. https://en.wikipedia.org/w/index.php?title=Logit-normal_distribution&oldid=993237113
"""
def __init__(self, sq_scale: float, location: float):
self.sq_scale = sq_scale
self.location = location
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value below 0 and greater than 1
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
mu = self.location
sig = self.sq_scale
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x < 0) | (x > 1)):
raise ValueError(
'random variable should only be in between 0 and 1')
return (1/(sig*m.sqrt(2*m.pi))) * np.exp(-(np.power(ss.logit(x)-mu, 2)/(2*pow(sig, 2)))) * 1/(x*(1-x))
if x < 0 or x > 1:
raise ValueError(
'random variable should only be in between 0 and 1')
return (1/(sig*m.sqrt(2*m.pi))) * m.exp(-pow(ss.logit(x)-mu, 2)/(2*pow(sig, 2))) * 1/(x*(1-x))
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
mu = self.location
sig = self.sq_scale
def __generator(mu: float, sig: float, x: Union[float, np.ndarray]) -> Union[float, np.ndarray]:
return 0.5 * (1+ss.erf((ss.logit(x)-mu)/m.sqrt(2*pow(sig, 2))))
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
return __generator(mu, sig, x)
return __generator(mu, sig, x)
[docs] def mean(self) -> str:
"""
Returns: Mean of the Logit Normal distribution.
"""
return "no analytical solution"
[docs] def mode(self) -> str:
"""
Returns: Mode of the Logit Normal distribution.
"""
return "no analytical solution"
[docs] def var(self) -> str:
"""
Returns: Variance of the Logit Normal distribution.
"""
return "no analytical solution"
[docs] def std(self) -> str:
"""
Returns: Standard deviation of the Logit Normal distribution.
"""
return "no analytical solution"
[docs] def entropy(self) -> str:
"""
Returns: differential entropy of Logit Normal distribution.
Reference: Park, S.Y. & Bera, A.K.(2009). Maximum entropy autoregressive conditional heteroskedasticity model. Elsivier.
link: http://wise.xmu.edu.cn/uploadfiles/paper-masterdownload/2009519932327055475115776.pdf
"""
return "unsupported"
[docs] def summary(self) -> Dict[str, str]:
"""
Returns:
Dictionary of Logit Normal distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Trapezoidal(BoundedInterval):
"""
This class contains methods concerning Trapezoidal Distirbution [#]_.
Args:
a(float): lower bound parameter where a < d
b(float): level start parameter where a <= b < c
c(float): level end parameter where b < c <= d
d(float): upper bound parameter where c <= d
randvar(float): random variable where a <= x <= d
Reference:
.. [#] Wikipedia contributors. (2020, April 11). Trapezoidal distribution. https://en.wikipedia.org/w/index.php?title=Trapezoidal_distribution&oldid=950241388
"""
def __init__(self, a: float, b: float, c: float, d: float):
if a > d:
raise ValueError(
'lower bound(a) should be less than upper bound(d).')
if a > b or b >= c:
raise ValueError(
'lower bound(a) should be less then or equal to level start (b) where (b) is less than level end(c).')
if b >= c or c > d:
raise ValueError(
'level start(b) should be less then level end(c) where (c) is less then or equal to upper bound (d).')
if c > d:
raise ValueError(
'level end(c) should be less than or equal to upper bound(d)')
self.a = a
self.b = b
self.c = c
self.d = d
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a, b, c, d = self.a, self.b, self.c, self.d
def __generator(a: float, b: float, c: float, d: float, x: float) -> float:
if a <= x and x < b:
return 2/(d+c-a-b) * (x-a)/(b-a)
if b <= x and x < c:
return 2/(d+c-a-b)
if c <= x and x <= d:
return (2/(d+c-a-b))*(d-x)/(d-c)
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
return np.vectorize(__generator)(a, b, c, d, x)
return __generator(a, b, c, d, x)
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
a, b, c, d = self.a, self.b, self.c, self.d
def __generator(a: float, b: float, c: float, d: float, x: float) -> float:
if a <= x and x < b:
return (x-a)**2/((b-a)*(d+c-a-b))
if b <= x and x < c:
return (2*x-a-b)/(d+c-a-b)
if c <= x and x <= d:
return 1 - (d-x)**2/((d+c-a-b)*(d-c))
if isinstance(x, (np.ndarray, List)):
if not type(x) is np.ndarray:
x = np.array(x)
return np.vectorize(__generator)(a, b, c, d, x)
return __generator(a, b, c, d, x)
[docs] def mean(self) -> float:
"""
Returns: Mean of the Trapezoidal distribution.
"""
a = self.a
b = self.b
c = self.c
d = self.d
return 1/(3*(d+c-b-a)) * ((d**3 - c**3)/(d-c) - (b**3 - a**3)/(b-a))
[docs] def var(self) -> float:
"""
Returns: Variance of the Trapezoidal distribution. Currently Unsupported.
"""
a = self.a
b = self.b
c = self.c
d = self.d
mean = 1/(3*(d+c-b-a)) * ((d**3 - c**3)/(d-c) - (b**3 - a**3)/(b-a))
return 1/(6*(d+c-b-a)) * ((d**4 - c**4)/(d-c) - (b**4 - a**4)/(b-a)) - pow(mean, 2)
[docs] def summary(self) -> Dict[str, Union[float, Tuple[float]]]:
"""
Returns:
Dictionary of Trapezoidal distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class WignerSemiCircle(BoundedInterval):
"""This class contains methods concerning the Wigner Semi Circle [#]_.
.. math::
\\text{WignerSemiCircle}(x;r) = \\frac{2}{ \\pi r^2} \\sqrt{r^2 - x^2}
Args:
radius (float): raduis parameter :math:`r > 0`
x (float): random variable
Reference:
.. [#] Wikipedia Contributors (2021). Wigner semicircle distribution. https://en.wikipedia.org/wiki/Wigner_semicircle_distribution.
"""
def __init__(self, radius:float):
if radius <= 0:
raise ValueError('')
self.radius = radius
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variables
Raises:
ValueError: when there exist a value of x < -rad or x > rad
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
rad = self.radius
x0 = 2/(m.pi*rad**2)
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
# checks x <= R; x >= -R
if np.any((x < -rad) | (x > rad)):
raise ValueError(f'random variable is expected to be defined within [-{rad},{rad}]')
return x0 * np.sqrt(rad**2 - np.power(x,2))
if x < -rad or x > rad:
raise ValueError(f'random variable is expected to be defined within [-{rad},{rad}]')
return x0*m.sqrt(rad**2 - x**2)
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Raises:
ValueError: when there exist a value of x < -rad or x > rad
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
rad = self.radius
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
# checks x <= R; x >= -R
if np.any((x < -rad) | (x > rad)):
raise ValueError(
f'data points are expected to be defined within [-{rad},{rad}]')
return 0.5 + (x*np.sqrt(rad**2 - x**2))/(m.pi*rad**2) + np.arcsin(1/rad)/m.pi
if x < -rad or x > rad:
raise ValueError(
f'data points are expected to be defined within [-{rad},{rad}]')
return 0.5 + (x*m.sqrt(rad**2 - x**2))/(m.pi*rad**2) + m.asin(1/rad)/m.pi
[docs] def mean(self)->float:
return 0.0
[docs] def mode(self) -> float:
return 0.0
[docs] def var(self) -> float:
return pow(self.radius, 4)
[docs] def std(self)-> float:
return pow(self.radius, 2)
[docs] def skewness(self)-> float:
return 0.0
[docs] def kurtorsis(self) -> float:
return -1.0
[docs] def entropy(self) -> float:
return m.log(m.pi* self.radius) * -0.5
[docs] def summary(self) -> Dict[str, float]:
"""
Returns:
Dictionary of WignerSemiCircle distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
# class IrwinHall(BoundedInterval): ...
[docs]class Kumaraswamy(BoundedInterval):
"""This class contains methods concerning the Kumaraswamy distribution [#]_ .
.. math::
\\text{Kumaraswamy}(x;a,b) = abx^{a-1}(1-x^a)^{b-1}
Args:
a (float): a parameter :math:`a > 0`
b (float): b parameter :math:`b > 0`
x (float): random variables :math:`x \\in (0,1)`
Reference:
.. [#] Wikipedia Contributors (2021). Kumaraswamy distribution. https://en.wikipedia.org/wiki/Kumaraswamy_distribution.
"""
def __init__(self, a:float, b:float):
if a <= 0 or b <= 0:
raise ValueError('parameters are expected to have positive values')
self.a, self.b = a,b
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value of x <= 0 or x>= 1
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a,b = self.a, self.b
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x<=0) | (x >= 1)):
raise ValueError('random variables are expected to be within (0,1)')
else:
if x <= 0 or x >= 1:
raise ValueError('random variables are expected to be within (0,1)')
return a*b*x**(a-1)*(1-x**a)**(b-1)
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Raises:
ValueError: when there exist a value of x <= 0 or x >= 1
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
a,b = self.a, self.b
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x<=0) | (x >= 1)):
raise ValueError('data points are expected to be within (0,1)')
else:
if x <= 0 or x >= 1:
raise ValueError('data points are expected to be within (0,1)')
return 1 - (1-x**a)**b
[docs] def mean(self) -> float:
a,b = self.a, self.b
return b*ss.gamma(1+1/a)*ss.gamma(b)/ss.gamma(1+1/a+b)
[docs] def mode(self) -> Union[float,str]:
a, b = self.a, self.b
if a >= 1 and b >= 1:
return pow((a-1)/(a*b-1), 1/a)
return 'Undefined'
[docs] def var(self) -> float: ...
[docs] def std(self) -> float: ...
[docs] def skewness(self) -> float: ...
[docs] def kurtosis(self) -> float: ...
[docs] def entropy(self) -> float: ...
[docs] def summary(self) -> Dict[str, Union[float, str]]:
"""
Returns:
Dictionary of Kumaraswamy distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class Reciprocal(BoundedInterval):
"""This class contains methods concerning Reciprocal distribution [#]_.
.. math::
\\text{Reciprocal}(x;a,b) = \\frac{1}{x \\ln \\Big( \\frac{b}{a}\\Big)}
Args:
a (float): a parameter :math:`a > 0`
b (float): b prameter :math:`b > 0`
x (float): random variable
Reference:
.. [#] Wikipedia Contributors (2021). Reciprocal distribution. https://en.wikipedia.org/wiki/Reciprocal_distribution.
"""
def __init__(self, a:float, b:float):
if a < 0 or b < 0:
raise ValueError('parameters are expected to be greater than 0')
if a >= b:
raise ValueError('parameter a is expected to be less than b')
self.a, self.b = a,b
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a,b = self.a, self.b
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
return 1/(x*m.log(b/a))
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
a,b = self.a, self.b
x0 = (m.log(b/a))
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
return np.log(x/a)/x0
return m.log(x/a)/x0
[docs] def mean(self) -> float:
a,b = self.a, self.b
return (b-a)/m.log(b/a)
[docs] def variance(self) -> float:
a,b = self.a, self.b
x0 = (b**2 - a**2)/(2*m.log(b/a))
x1 = pow((b-a)/m.log(b/a),2)
return x0 - x1
[docs] def std(self) -> float:
return m.sqrt(self.var())
[docs] def summary(self) -> Dict[str, float]:
"""
Returns:
Dictionary of Reciprocal distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
# value checking on cdf
[docs]class RaisedCosine(BoundedInterval):
"""This class contains methods concerning the Raised Cosine distribution [#]_.
.. math::
\\text{RaisedCosine}(x;\\mu, s) = \\frac{1}{2s} \\Big[ 1 + \\cos \\Big( \\frac{x-\\mu}{s} \\pi \\Big) \\Big]
Args:
mu (float): mu parameter :math:`\\mu \\in \\mathbb{R}`
s (float): s parameter :math:`s > 0`
x (float): random variables
References:
.. [#] Wikipedia Contributors (2020). Raised cosine distribution. https://en.wikipedia.org/wiki/Raised_cosine_distribution.
"""
def __init__(self, mu:float, s:float):
if s < 0:
raise ValueError('parameter s is expected to be s <= 0')
self.mu, self.s = mu, s
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value of x < mu - s or x > mu + s
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
mu, s = self.mu, self.s
l_bound, u_bound = mu-s, mu+s
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x< l_bound) | (x>u_bound)):
raise ValueError(f'random variables are expected to be in [{l_bound},{u_bound}]')
else:
if x < l_bound or x > u_bound:
raise ValueError(f'random variables are expected to be in [{l_bound},{u_bound}]')
return (1/2*s)*(1 + np.cos(m.pi*(x-mu)/s))
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Returns:
Union[float, numpy.ndarray]: evaluation of cdf at x
"""
mu, s = self.mu, self.s
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
return 0.5*(1 + (x-mu)/s + 1/m.pi*np.sin(m.pi*(x-mu)/s))
[docs] def mean(self) -> float:
return self.mu
[docs] def mode(self) -> float:
return self.mu
[docs] def var(self) -> float:
return self.s**2*(1/3 + 2/m.pi)
[docs] def std(self) -> float:
return m.sqrt(self.s**2*(1/3 + 2/m.pi))
[docs] def skewness(self) -> float:
return 0.0
[docs] def kurtosis(self) -> float:
# 6*(90-m.pi**4)/(5*(m.pi**2 - 6)**2)
return -0.5937628755982794
[docs] def summary(self) -> Dict[str, float]:
"""
Returns:
Dictionary of Raised Cosine distirbution moments. This includes standard deviation.
"""
return {
'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
}
[docs]class UQuadratic(BoundedInterval):
"""This class contains methods concerning U-Quadratic Distribution [#]_.
.. math:: \\text{UQuadratic}(x;a,b) = a \\Big(x- \\frac{a+b}{2}\\Big)^2
Args:
a (float): parameter a
b (float): parameter b
x (float): random variables :math:`x \\in [a,b]`
Reference:
.. [#] Wikipedia Contributors (2021). U-quadratic distribution. https://en.wikipedia.org/wiki/U-quadratic_distribution.
"""
def __init__(self, a:float, b:float):
if a >= b:
raise ValueError('parameter a is expected to be less than b')
self.a, self.b = a,b
[docs] def pdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): random variable(s)
Raises:
ValueError: when there exist a value of x less than a or greater than b
Returns:
Union[float, numpy.ndarray]: evaluation of pdf at x
"""
a,b = self.a, self.b
midpoint = (a+b)/2
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x<a) | (x>b)):
raise ValueError(f'random variables are expected to be within [{a},{b}].')
else:
if x < a or x >b:
raise ValueError(f'random variables are expected to be within [{a},{b}].')
return a*(x - midpoint)**2
[docs] def cdf(self, x: Union[List[float], np.ndarray, float]) -> Union[float, np.ndarray]:
"""
Args:
x (Union[List[float], numpy.ndarray, float]): data point(s) of interest
Raises:
ValueError: when there exist a value of x < a or x > b
Returns:
Union[float, numpy.ndarray]: cdf evaluation at x
"""
a,b = self.a, self.b
midpoint = (a+b)/2
if isinstance(x, (List, np.ndarray)):
if not type(x) is np.ndarray:
x = np.array(x)
if np.any((x<a) | (x>b)):
raise ValueError(f'data points are expected to be within [{a}, {b}]')
else:
if x < a or x >b:
raise ValueError(f'data points are expected to be within [{a}, {b}]')
return a/3*((x-midpoint)**3 - (midpoint-a)**3)
[docs] def mean(self) -> float:
return (self.a + self.b) / 2
[docs] def mode(self) -> Tuple[float, float]:
return (self.a, self.b)
[docs] def var(self) -> float:
return 3/20*pow(self.b - self.a, 2)
[docs] def std(self) -> float:
return m.sqrt(3/20*pow(self.b - self.a, 2))
[docs] def skewness(self) -> float:
return 0.0
[docs] def kurtosis(self) -> float:
return 3/112*pow(self.b - self.a, 4)
# class PERT(BoundedInterval): ...
# class BaldingNichols(BoundedInterval): ...