diff --git a/.gitignore b/.gitignore index 12d6303..0b3baad 100644 --- a/.gitignore +++ b/.gitignore @@ -143,3 +143,5 @@ cython_debug/ *~ *.swp *.swo + +.vscode/ diff --git a/probdists/Weibulldistribution.py b/probdists/Weibulldistribution.py new file mode 100644 index 0000000..5bb1312 --- /dev/null +++ b/probdists/Weibulldistribution.py @@ -0,0 +1,121 @@ +import math +import numpy as np +from matplotlib import pyplot as plt +from .Generaldistribution import Distribution + + +class Weibull(Distribution): + """ Weibull distribution class for calculating and + visualizing a Weibull distribution. + + Attributes: + + mean (float): the mean value of the distribution + stdev (float): the standard deviation of the distribution + + data (list of floats): extracted from the data file + + lmbda (float): scale parameter of the distribution + (missing an 'a' to prevent name clash with Python keyword) + k (float): shape parameter of the distribution + + """ + def __init__(self, lmbda=1, k=1.5): + self.lmbda = lmbda + self.k = k + self.calculate_mean() + self.calculate_stdev() + + def calculate_mean(self, round_to=2): + """ Method to calculate the mean + + Args: + round_to (int): Round the mean value. [Default value: 2 floating point] + + Returns: + float: mean of the distribution + """ + gamma_factor = math.gamma(1 + (1 / self.k)) + self.mean = self.lmbda * gamma_factor + return round(self.mean, round_to) + + def calculate_stdev(self, round_to=2): + """ Method to calculate the standard deviation + + Args: + round_to (int): Round the mean value. [Default value: 2 floating point] + + Returns: + float: standard deviation of the distribution + """ + first = math.gamma(1 + (2 / self.k)) + second = math.gamma(1 + (1 / self.k)) ** 2 + self.stdev = math.sqrt(self.lmbda ** 2 * (first - second)) + return round(self.stdev, round_to) + + def calculate_pdf(self, x, round_to=2): + """ Probability density function calculator for the Weibull distribution. + + Args: + x (float): point for caluclating the probability density function + round_to (int): Round the mean value. [Default value: 2 floating point] + + Returns: + float: probability density function + """ + if x < 0: + out = 0 + else: + exp_factor = math.exp(-(x / self.lmbda) ** self.k) + out = (self.k / self.lmbda) * exp_factor * \ + (x / self.lmbda) ** (self.k - 1) + return round(out, round_to) + + def calculate_cdf(self, x, round_to=2): + """ + Cumulative density function calculator for the Weibull distribution. + Args: + x (float): point for calculating the cumulative density function + round_to (int): Round the mean value. [Default value: 2 floating point] + + Returns: + float: cumulative density function output + """ + if x < 0: + out = 0 + else: + out = 1 - math.exp(-(x / self.lmbda) ** self.k) + return round(out, round_to) + + def plot_pdf(self, samples=250): + """ Method to plot the pdf of the Weibull distribution. + + Args: + samples (int): number of discrete data points + + Returns: + list: y values for the pdf plot + + """ + x = np.linspace(0, 2.5, num=samples) + y = np.zeros_like(x) + + for index, value in enumerate(x): + y[index] = self.calculate_pdf(value) + + plt.plot(x, y, label=f"lambda={self.lmbda}; k={self.k}") + plt.legend() + plt.title(f"Probability Distribution Function for Weibull \ + Distribution lambda={self.lmbda} k={self.k}") + plt.show() + return y + + def __repr__(self): + """ Method to output the characteristics of the Weibull instace. + Args: + None + Returns: + string: characteristics of the Weibull + """ + return f"lambda: {self.lmbda}, k: {self.k}, mean: {self.mean}, \ + standard deviation: {self.stdev}" diff --git a/probdists/__init__.py b/probdists/__init__.py index 664a26b..1b80e84 100644 --- a/probdists/__init__.py +++ b/probdists/__init__.py @@ -6,3 +6,4 @@ from .Bernoullidistribution import Bernoulli from .Uniformdistribution import Uniform from .Triangulardistribution import Triangular, TriangularValueException +from .Weibulldistribution import Weibull diff --git a/test.py b/test.py index 240b84d..2c8f8bb 100644 --- a/test.py +++ b/test.py @@ -8,6 +8,7 @@ from probdists import Bernoulli from probdists import Uniform from probdists import Triangular, TriangularValueException +from probdists import Weibull class TestGeneraldistribution(unittest.TestCase): @@ -238,7 +239,6 @@ def test_cdf(self): self.assertEqual(self.uniform.calculate_cdf(4), 0.75, 'calculate_cdf function does not give expected result') - class TestGammaClass(unittest.TestCase): def setUp(self): self.gamma = Gamma() @@ -407,5 +407,40 @@ def test_cdf(self): self.assertEqual(self.triangle.calculate_cdf(12), 1) +class TestWeibullClass(unittest.TestCase): + def setUp(self): + self.weibull = Weibull() + + def test_initialization(self): + self.assertEqual(self.weibull.k, 1.5, 'incorrect k') + self.assertEqual(self.weibull.lmbda, 1, 'incorrect lambda') + + def test_meancalculation(self): + self.weibull.calculate_mean() + self.assertEqual(round(self.weibull.mean, 5), 0.90275, + 'calculated mean not as expected') + + def test_stdevcalculation(self): + self.weibull.calculate_stdev() + self.assertEqual(round(self.weibull.stdev, 5), 0.61294, + 'calculated stdev not as expected') + + def test_pdf(self): + self.assertEqual(self.weibull.calculate_pdf(0.5, 5), 0.74478, + 'unexpected pdf value') + self.weibull.calculate_mean() + self.weibull.calculate_stdev() + self.assertEqual(self.weibull.calculate_pdf(1, 5), 0.55182, + 'unexpected pdf value') + self.assertEqual(self.weibull.calculate_pdf(2.0, 5), 0.12538, + 'unexpected pdf') + + def test_cdf(self): + self.assertEqual(self.weibull.calculate_cdf(0.5, 5), 0.29781, + 'unexpected cdf value') + self.assertEqual(self.weibull.calculate_cdf(1.0, 5), 0.63212, + 'unexpected cdf value') + + if __name__ == '__main__': unittest.main()