|
| 1 | +import unittest |
| 2 | + |
| 3 | +import numpy as np |
| 4 | + |
| 5 | +from bluemath_tk.distributions._base_distributions import FitResult |
| 6 | +from bluemath_tk.distributions.gpd import GPD |
| 7 | + |
| 8 | + |
| 9 | +class TestGPD(unittest.TestCase): |
| 10 | + def setUp(self): |
| 11 | + self.x = np.random.rand(1000) * 2 |
| 12 | + self.p = np.random.rand(1000) |
| 13 | + self.loc = 0.0 |
| 14 | + self.scale = 1.0 |
| 15 | + self.shape_frechet = 0.1 # GPD (Frechet) |
| 16 | + self.shape_weibull = -0.1 # GPD (Weibull) |
| 17 | + self.shape_gumbel = 0.0 # Gumbel case |
| 18 | + |
| 19 | + def test_pdf(self): |
| 20 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 21 | + custom_pdf = GPD.pdf(self.x, self.loc, self.scale, shape) |
| 22 | + self.assertIsInstance(custom_pdf, np.ndarray) |
| 23 | + self.assertEqual(custom_pdf.shape[0], 1000) |
| 24 | + |
| 25 | + def test_cdf(self): |
| 26 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 27 | + custom_cdf = GPD.cdf(self.x, self.loc, self.scale, shape) |
| 28 | + self.assertIsInstance(custom_cdf, np.ndarray) |
| 29 | + self.assertEqual(custom_cdf.shape[0], 1000) |
| 30 | + |
| 31 | + def test_sf(self): |
| 32 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 33 | + custom_sf = GPD.sf(self.x, self.loc, self.scale, shape) |
| 34 | + self.assertIsInstance(custom_sf, np.ndarray) |
| 35 | + self.assertEqual(custom_sf.shape[0], 1000) |
| 36 | + |
| 37 | + def test_qf(self): |
| 38 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 39 | + custom_qf = GPD.qf(self.p, self.loc, self.scale, shape) |
| 40 | + self.assertIsInstance(custom_qf, np.ndarray) |
| 41 | + self.assertEqual(custom_qf.shape[0], 1000) |
| 42 | + |
| 43 | + def test_nll(self): |
| 44 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 45 | + nll = GPD.nll(self.x, self.loc, self.scale, shape) |
| 46 | + self.assertIsInstance(nll, float) |
| 47 | + |
| 48 | + def test_random(self): |
| 49 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 50 | + random_values = GPD.random(1000, self.loc, self.scale, shape) |
| 51 | + self.assertIsInstance(random_values, np.ndarray) |
| 52 | + self.assertEqual(random_values.shape[0], 1000) |
| 53 | + |
| 54 | + def test_mean(self): |
| 55 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 56 | + mean = GPD.mean(self.loc, self.scale, shape) |
| 57 | + self.assertIsInstance(mean, float) |
| 58 | + |
| 59 | + def test_median(self): |
| 60 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 61 | + median = GPD.median(self.loc, self.scale, shape) |
| 62 | + self.assertIsInstance(median, float) |
| 63 | + |
| 64 | + def test_variance(self): |
| 65 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 66 | + variance = GPD.variance(self.loc, self.scale, shape) |
| 67 | + self.assertIsInstance(variance, float) |
| 68 | + |
| 69 | + def test_std(self): |
| 70 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 71 | + std = GPD.std(self.loc, self.scale, shape) |
| 72 | + self.assertIsInstance(std, float) |
| 73 | + |
| 74 | + def test_stats(self): |
| 75 | + for shape in [self.shape_frechet, self.shape_weibull, self.shape_gumbel]: |
| 76 | + stats = GPD.stats(self.loc, self.scale, shape) |
| 77 | + self.assertIsInstance(stats, dict) |
| 78 | + self.assertIn("mean", stats) |
| 79 | + self.assertIn("median", stats) |
| 80 | + self.assertIn("variance", stats) |
| 81 | + self.assertIn("std", stats) |
| 82 | + |
| 83 | + def test_invalid_scale(self): |
| 84 | + with self.assertRaises(ValueError): |
| 85 | + GPD.pdf(self.x, self.loc, 0.0, self.shape_frechet) |
| 86 | + with self.assertRaises(ValueError): |
| 87 | + GPD.cdf(self.x, self.loc, 0.0, self.shape_frechet) |
| 88 | + with self.assertRaises(ValueError): |
| 89 | + GPD.sf(self.x, self.loc, 0.0, self.shape_frechet) |
| 90 | + with self.assertRaises(ValueError): |
| 91 | + GPD.qf(self.p, self.loc, 0.0, self.shape_frechet) |
| 92 | + with self.assertRaises(ValueError): |
| 93 | + GPD.random(1000, self.loc, 0.0, self.shape_frechet) |
| 94 | + with self.assertRaises(ValueError): |
| 95 | + GPD.mean(self.loc, 0.0, self.shape_frechet) |
| 96 | + with self.assertRaises(ValueError): |
| 97 | + GPD.median(self.loc, 0.0, self.shape_frechet) |
| 98 | + with self.assertRaises(ValueError): |
| 99 | + GPD.variance(self.loc, 0.0, self.shape_frechet) |
| 100 | + with self.assertRaises(ValueError): |
| 101 | + GPD.std(self.loc, 0.0, self.shape_frechet) |
| 102 | + with self.assertRaises(ValueError): |
| 103 | + GPD.stats(self.loc, 0.0, self.shape_frechet) |
| 104 | + |
| 105 | + def test_fit(self): |
| 106 | + # Generate data using specific parameters |
| 107 | + loc, scale, shape = 0.5, 1.5, 0.2 |
| 108 | + data = GPD.random(1000, loc, scale, shape, random_state=42) |
| 109 | + |
| 110 | + # Fit the GPD distribution to the data |
| 111 | + # loc is fixed at 0.0 |
| 112 | + fit_result = GPD.fit(data - loc, f0 = 0.0) |
| 113 | + |
| 114 | + # Check the fit result |
| 115 | + self.assertIsInstance(fit_result, FitResult) |
| 116 | + self.assertTrue(fit_result.success) |
| 117 | + self.assertEqual(len(fit_result.params), 3) # loc, scale, shape |
| 118 | + self.assertGreater(fit_result.params[1], 0) # Scale must be > 0 |
| 119 | + self.assertIsInstance(fit_result.nll, float) |
| 120 | + |
| 121 | + # Verify that the fitted parameters are close to the original ones |
| 122 | + self.assertAlmostEqual(fit_result.params[1], scale, delta=0.2) |
| 123 | + self.assertAlmostEqual(fit_result.params[2], shape, delta=0.1) |
| 124 | + |
| 125 | + |
| 126 | +if __name__ == "__main__": |
| 127 | + unittest.main() |
0 commit comments