Source code for aleatory.processes.jump.gen_random_walk

"""
General Random Walk
"""

from aleatory.processes.base_analytical import SPAnalytical
from abc import ABC
from aleatory.utils.utils import (
    check_positive_integer,
    get_times,
)
from aleatory.utils.plotters import plot_paths_random_walk
import numpy as np


[docs]class GeneralRandomWalk(SPAnalytical, ABC): r""" General Random Walk =================== .. image:: ../_static/gen_random_walk_draw.png Notes ----- Let :math:`\{Z_i, i \geq 1\}` be a sequence of real-valued independent an identically distributed (i.i.d.) random variables defined on a probability space :math:`(\Omega, \mathcal{F}, \mathbb{P})`. Then, the stochastic process :math:`\{X_n , n\geq 0\}`, defined as :math:`X_0 =0`, and .. math:: X_n = \sum_{i=1}^n Z_i, \qquad \forall n\geq 1, is called random walk, or more precisely one-dimensional random walked based on :math:`\{Z_i, i \geq 1\}`. Constructor, Methods, and Attributes ------------------------------------ """
[docs] def __init__( self, step_dist=None, step_args=None, step_kwargs=None, normalised=False, rng=None, ): """ :parameter step_dist: an object representing the random variable :math:`Z_i` above (e.g.scipy.stats.norm) :parameter step_args: arguments (if any) to pass to the chosen step distribution :parameter step_kwargs: keyword arguments (if any) to pass to the chosen step distribution :parameter bool normalised: normalised or not :parameter numpy.random.Generator rng: a custom random number generator """ super().__init__(rng=rng) self.step_dist = step_dist self.step_args = step_args if step_args is not None else tuple() self.step_kwargs = step_kwargs if step_kwargs is not None else dict() self.mean = self.step_dist.mean() self.std = self.step_dist.std() self.normalised = normalised self.paths = None self.n = None self.N = None self.name = "General Random Walk" self.times = None
def __str__(self): return f"General Random Walk" def __repr__(self): return f"GeneralRandomWalk" def _sample_random_walk_steps(self, n): """Generate a sample of a general random walk increments""" check_positive_integer(n) steps = self.step_dist.rvs(size=n) if self.normalised: steps = (steps - self.mean) / self.std # steps = self.rng.choice(self.step_sizes, p=self.probs, size=n) return steps def _sample_random_walk(self, n): """Generate a sample from a general random walk""" self.T = n self.n = n self.times = get_times(self.T, self.n + 1) sample = np.array([0] + list(np.cumsum(self._sample_random_walk_steps(n)))) return sample def sample(self, n): sample = self._sample_random_walk(n) return sample def plot(self, *args, n, N, title=None, suptitle=None, **fig_kw): """ Simulates and plots paths/trajectories from the instanced stochastic process. Simple plot of times versus process values as lines and/or markers. :parameter int n: number of steps in each path :parameter int N: number of paths to simulate :parameter str title: string to customise plot title :return: """ self.simulate(n, N) chart_suptitle = suptitle if suptitle is not None else self.name figure = plot_paths_random_walk( *args, times=self.times, paths=self.paths, title=title, suptitle=chart_suptitle, **fig_kw, ) return figure def draw( self, n, N, marginal=True, envelope=False, mode="steps", title=None, suptitle=None, **fig_kw, ): """ Simulates and plots paths/trajectories from the instanced stochastic process. Produces different kind of visualisation illustrating the following elements: - times versus process values as lines - the expectation of the process across time - histogram showing the empirical marginal distribution :math:`X_T` (optional when ``marginal = True``) - probability density function of the marginal distribution :math:`X_T` (optional when ``marginal = True``) - envelope of confidence intervals across time (optional when ``envelope = True``) :param int n: number of steps in each path :param int N: number of paths to simulate :param bool marginal: defaults to True :param bool envelope: defaults to False :param str mode: defaults to 'steps' :param str title: to be used to customise plot title. If not passed, the title defaults to the name of the process. :return: """ return self._draw_3sigmastyle( n=n, N=N, marginal=marginal, envelope=envelope, title=title, suptitle=suptitle, mode=mode, **fig_kw, )
if __name__ == "__main__": import matplotlib.pyplot as plt from scipy.stats import norm, expon, binom qs = "https://raw.githubusercontent.com/quantgirluk/matplotlib-stylesheets/main/quant-pastel-light.mplstyle" plt.style.use(qs) p = GeneralRandomWalk(step_dist=norm, normalised=True) p.plot( n=10, N=20, figsize=(12, 7), title="Random Walk with Normalised Gaussian Steps", mode="steps+points", style=qs, ) p.draw( n=100, N=200, figsize=(12, 7), title="Random Walk with Normalised Gaussian Steps", style=qs, ) p = GeneralRandomWalk(step_dist=expon, normalised=True) p.plot( n=50, N=200, figsize=(12, 7), title="Random Walk with Normalised Exponential Steps", mode="steps+points", style=qs, ) # p.draw( # n=100, # N=200, # figsize=(12, 7), # title="Random Walk with Normalised Exponential Steps", # style=qs, # colormap="viridis", # ) # # p = GeneralRandomWalk(step_dist=binom(n=10, p=0.2), normalised=True) # p.plot( # n=10, # N=200, # figsize=(12, 7), # title="Random Walk Normalised Binomial Steps", # mode="steps+points", # style=qs, # ) # p.draw( # n=20, # N=200, # figsize=(12, 7), # title="Random Walk Normalised Binomial Steps", # style=qs, # colormap="magma", # )