From 4790b11d2f3efb6fe9d5d16dd35190bb50e70b89 Mon Sep 17 00:00:00 2001 From: Basil Labib Date: Sat, 30 Oct 2021 20:40:09 +0530 Subject: [PATCH 1/3] Implement weibull distribution class; added functions for mean, stdev, pdf, and cdf --- .gitignore | 2 ++ probdists/Weibulldistribution.py | 39 ++++++++++++++++++++++++++++++++ probdists/__init__.py | 1 + test.py | 1 + 4 files changed, 43 insertions(+) create mode 100644 probdists/Weibulldistribution.py 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..1ed3e16 --- /dev/null +++ b/probdists/Weibulldistribution.py @@ -0,0 +1,39 @@ +import math +import numpy as np +from matplotlib import pyplot as plt +from .Generaldistribution import Distribution + + +class Weibull(Distribution): + def __init__(self, lmbda, k): + self.lmbda = lmbda + self.k = k + + Distribution.__init__(self.calculate_mean(), self.calculate_stdev()) + + def calculate_mean(self): + gamma_factor = math.gamma(1 + (1 / self.k)) + return self.lmbda * gamma_factor + + def calculate_stdev(self): + return self.lmbda * (math.log(2)) ** (1 / self.k) + + def calculate_pdf(self, x): + 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 out + + def calculate_cdf(self, x): + if x < 0: + out = 0 + else: + out = 1 - math.exp(-(x / self.lmbda) ** self.k) + return out + + def __repr__(self): + 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..8d79477 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): From c64a704bc5f351398453ce14c2d22720be1e5ab2 Mon Sep 17 00:00:00 2001 From: Basil Labib Date: Sat, 30 Oct 2021 20:45:23 +0530 Subject: [PATCH 2/3] Implement plot_pdf in weibull distribution class --- probdists/Weibulldistribution.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/probdists/Weibulldistribution.py b/probdists/Weibulldistribution.py index 1ed3e16..8c8966b 100644 --- a/probdists/Weibulldistribution.py +++ b/probdists/Weibulldistribution.py @@ -34,6 +34,20 @@ def calculate_cdf(self, x): out = 1 - math.exp(-(x / self.lmbda) ** self.k) return out + def plot_pdf(self, samples=250): + 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): return f"lambda: {self.lmbda}, k: {self.k}, mean: {self.mean}, \ standard deviation: {self.stdev}" From e47710e1d031ce6f3dd290f8f127197fa3376a3b Mon Sep 17 00:00:00 2001 From: Basil Labib Date: Sat, 30 Oct 2021 21:24:04 +0530 Subject: [PATCH 3/3] Add docs and tests --- probdists/Weibulldistribution.py | 88 ++++++++++++++++++++++++++++---- test.py | 36 ++++++++++++- 2 files changed, 113 insertions(+), 11 deletions(-) diff --git a/probdists/Weibulldistribution.py b/probdists/Weibulldistribution.py index 8c8966b..5bb1312 100644 --- a/probdists/Weibulldistribution.py +++ b/probdists/Weibulldistribution.py @@ -5,36 +5,98 @@ class Weibull(Distribution): - def __init__(self, lmbda, k): + """ 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 - Distribution.__init__(self.calculate_mean(), self.calculate_stdev()) + Args: + round_to (int): Round the mean value. [Default value: 2 floating point] - def calculate_mean(self): + Returns: + float: mean of the distribution + """ gamma_factor = math.gamma(1 + (1 / self.k)) - return self.lmbda * gamma_factor + 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 - def calculate_stdev(self): - return self.lmbda * (math.log(2)) ** (1 / self.k) + Args: + round_to (int): Round the mean value. [Default value: 2 floating point] - def calculate_pdf(self, x): + 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 out + 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] - def calculate_cdf(self, x): + Returns: + float: cumulative density function output + """ if x < 0: out = 0 else: out = 1 - math.exp(-(x / self.lmbda) ** self.k) - return out + 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) @@ -49,5 +111,11 @@ def plot_pdf(self, samples=250): 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/test.py b/test.py index 8d79477..2c8f8bb 100644 --- a/test.py +++ b/test.py @@ -239,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() @@ -408,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()