@@ -221,6 +221,158 @@ def moment(rv, size, mu, sigma, xi):
221
221
return mode
222
222
223
223
224
+ # Generalized Pareto Distribution
225
+ class GenParetoRV (RandomVariable ):
226
+ name : str = "Generalized Pareto Distribution"
227
+ ndim_supp : int = 0
228
+ ndims_params : List [int ] = [0 , 0 , 0 ]
229
+ dtype : str = "floatX"
230
+ _print_name : Tuple [str , str ] = ("Generalized Pareto Distribution" , "\\ operatorname{GP}" )
231
+
232
+ def __call__ (self , mu = 0.0 , sigma = 1.0 , xi = 1.0 , size = None , ** kwargs ) -> TensorVariable :
233
+ return super ().__call__ (mu , sigma , xi , size = size , ** kwargs )
234
+
235
+ @classmethod
236
+ def rng_fn (
237
+ cls ,
238
+ rng : Union [np .random .RandomState , np .random .Generator ],
239
+ mu : np .ndarray ,
240
+ sigma : np .ndarray ,
241
+ xi : np .ndarray ,
242
+ size : Tuple [int , ...],
243
+ ) -> np .ndarray :
244
+ # using scipy's parameterization
245
+ return stats .genpareto .rvs (c = xi , loc = mu , scale = sigma , random_state = rng , size = size )
246
+
247
+
248
+ gp = GenParetoRV ()
249
+
250
+
251
+ class GenPareto (Continuous ):
252
+ r"""
253
+ The Generalized Pareto Distribution
254
+
255
+ The pdf of this distribution is
256
+
257
+ .. math::
258
+
259
+ f(x \mid \mu, \sigma, \xi) = \frac{1}{\sigma} (1 + \xi z)^{-1/\xi-1}
260
+
261
+ where
262
+
263
+ .. math::
264
+
265
+ z = \frac{x - \mu}{\sigma}
266
+
267
+ and is defined on the set:
268
+
269
+ .. math::
270
+
271
+ \left\{x: x \geq \mu \right\} if \xi \geq 0, or \\
272
+ \left\{x: \mu \leq x \leq \mu - \sigma/\xi \right\} if \xi < 0.
273
+
274
+ .. plot::
275
+
276
+ import matplotlib.pyplot as plt
277
+ import numpy as np
278
+ import scipy.stats as st
279
+ import arviz as az
280
+ plt.style.use('arviz-darkgrid')
281
+ x = np.linspace(-2, 10, 200)
282
+ mus = [0., 0., 0., 0., 1., ]
283
+ sigmas = [1., 1., 1.,2., 1., ]
284
+ xis = [1., 0., 5., 1., 1., ]
285
+ for mu, sigma, xi in zip(mus, sigmas, xis):
286
+ pdf = st.genpareto.pdf(x, c=xi, loc=mu, scale=sigma)
287
+ plt.plot(x, pdf, label=rf'$\mu$ = {mu}, $\sigma$ = {sigma}, $\xi$={xi}')
288
+ plt.xlabel('x', fontsize=12)
289
+ plt.ylabel('f(x)', fontsize=12)
290
+ plt.legend(loc=1)
291
+ plt.show()
292
+
293
+
294
+ ======== =========================================================================
295
+ Support * :math:`x \geq \mu`, when :math:`\xi \geq 0`
296
+ * :math:`\mu \leq x \leq \mu - \sigma/\xi` when :math:`\xi < 0`
297
+ Mean * :math:`\mu + \frac{\sigma}{1-\xi}`, when :math:`\xi < 1`
298
+ Variance * :math:`\frac{\sigma^2}{(1-\xi)^2 (1-2\xi)}`, when :math:`\xi < 0.5`
299
+ ======== =========================================================================
300
+
301
+ Parameters
302
+ ----------
303
+ mu : float
304
+ Location parameter.
305
+ sigma : float
306
+ Scale parameter (sigma > 0).
307
+ xi : float
308
+ Shape parameter
309
+
310
+ """
311
+
312
+ rv_op = gp
313
+
314
+ @classmethod
315
+ def dist (cls , mu = 0 , sigma = 1 , xi = 0 , ** kwargs ):
316
+ mu = pt .as_tensor_variable (floatX (mu ))
317
+ sigma = pt .as_tensor_variable (floatX (sigma ))
318
+ xi = pt .as_tensor_variable (floatX (xi ))
319
+
320
+ return super ().dist ([mu , sigma , xi ], ** kwargs )
321
+
322
+ def logp (value , mu , sigma , xi ):
323
+ """
324
+ Calculate log-probability of Generalized Pareto distribution
325
+ at specified value.
326
+
327
+ Parameters
328
+ ----------
329
+ value: numeric
330
+ Value(s) for which log-probability is calculated. If the log probabilities for multiple
331
+ values are desired the values must be provided in a numpy array or Pytensor tensor
332
+
333
+ Returns
334
+ -------
335
+ TensorVariable
336
+ """
337
+ scaled = (value - mu ) / sigma
338
+ p = (1 / sigma ) * (1 + xi * scaled ) ** (- 1 / xi - 1 )
339
+ logprob = pt .switch (pt .gt (scaled , 0.0 ), pt .log (p ), - np .inf )
340
+ return check_parameters (logprob , sigma > 0 , msg = "sigma > 0" )
341
+
342
+ def logcdf (value , mu , sigma , xi ):
343
+ """
344
+ Compute the log of the cumulative distribution function for Generalized Pareto
345
+ distribution at the specified value.
346
+
347
+ Parameters
348
+ ----------
349
+ value: numeric or np.ndarray or `TensorVariable`
350
+ Value(s) for which log CDF is calculated. If the log CDF for
351
+ multiple values are desired the values must be provided in a numpy
352
+ array or `TensorVariable`.
353
+
354
+ Returns
355
+ -------
356
+ TensorVariable
357
+ """
358
+ scaled = (value - mu ) / sigma
359
+ logc_expression = 1 - (1 + xi * scaled ) ** (- 1 / xi )
360
+
361
+ logc = pt .switch (sigma > 0 , pt .log (logc_expression ), - np .inf )
362
+
363
+ return check_parameters (logc , sigma > 0 , msg = "sigma > 0" )
364
+
365
+ def moment (rv , size , mu , sigma , xi ):
366
+ r"""
367
+ Mean is defined when :math:`\xi < 1`
368
+ """
369
+ mean_expression = mu + sigma / (1 - xi )
370
+ mean = pt .switch (xi < 1 , mean_expression , np .inf )
371
+ if not rv_size_is_none (size ):
372
+ mean = pt .full (size , mean )
373
+ return check_parameters (mean , xi < 1 , msg = "xi < 1" )
374
+
375
+
224
376
class Chi :
225
377
r"""
226
378
:math:`\chi` log-likelihood.
0 commit comments