Source code for stochastic.processes.discrete.random_walk

"""Random walk process."""
import numpy as np

from stochastic.processes.base import BaseSequenceProcess
from stochastic.utils.validation import check_positive_integer


[docs]class RandomWalk(BaseSequenceProcess): """Random walk. .. image:: _static/random_walk.png :scale: 50% A random walk is a sequence of random steps taken from a set of step sizes with a probability distribution. By default this object defines the steps to be [-1, 1] with probability 1/2 for each possibility. :param steps: a vector of possible deltas to apply at each step. :param weights: a corresponding vector of weights associated with each step value. If not provided each step has equal weight/probability. """ def __init__(self, steps=None, weights=None, rng=None): super().__init__(rng=rng) self.steps = steps or [-1, 1] length = len(steps) if length < 1: raise ValueError("Steps must have at least one element.") if weights is None: self.weights = [1 for _ in steps] self.p = [1.0 / length for _ in steps] else: if len(weights) != length: raise ValueError("Steps and probabilities must have same length.") self.weights = weights total = sum(weights) self.p = [1.0 * w / total for w in weights] @property def p(self): """Step probabilities, normalized from :py:attr:`weights`.""" return self._p @p.setter def p(self, values): values = np.array(values, copy=True) self._p = values @property def steps(self): """Possible steps.""" return self._steps @steps.setter def steps(self, values): for value in values: if not isinstance(value, int) and not isinstance(value, float): raise TypeError("Step values must be numeric.") values = np.array(values, copy=True) self._steps = values @property def weights(self): """Step weights provided.""" return self._weights @weights.setter def weights(self, values): for value in values: if not isinstance(value, (int, float)): raise TypeError("Weight values must be numeric.") if value < 0: raise ValueError("Weight values must be nonnegative.") values = np.array(values, copy=True) self._weights = values def __str__(self): return "Random walk steps = {s} and weights = {w}".format( s=str(self.steps), w=str(self.weights) ) def __repr__(self): return "RandomWalk(steps={s}, weights={w})".format( s=str(self.steps), w=str(self.weights) ) def _sample_random_walk(self, n): """Generate a random walk.""" return np.array([0] + list(np.cumsum(self._sample_random_walk_increments(n))))
[docs] def sample(self, n): """Generate a sample random walk. :param int n: the number of steps to generate """ return self._sample_random_walk(n)
def _sample_random_walk_increments(self, n): """Generate a sample of random walk increments.""" check_positive_integer(n) return self.rng.choice(self.steps, p=self.p, size=n)
[docs] def sample_increments(self, n): """Generate a sample of random walk increments. :param int n: the number of increments to generate. """ return self._sample_random_walk_increments(n)