Path: blob/master/src/sage/probability/random_variable.py
8815 views
r"""1Random variables and probability spaces23This introduces a class of random variables, with the focus on4discrete random variables (i.e. on a discrete probability space).5This avoids the problem of defining a measure space and measurable6functions.7"""89#*****************************************************************************10# Copyright (C) 2007 David Kohel <[email protected]>11#12# Distributed under the terms of the GNU General Public License (GPL)13#14# http://www.gnu.org/licenses/15#*****************************************************************************1617from sage.structure.parent_base import ParentWithBase18from sage.misc.functional import sqrt, log19from sage.rings.real_mpfr import (RealField, is_RealField)20from sage.rings.rational_field import is_RationalField21from sage.sets.set import Set2223################################################################################24################################################################################2526def is_ProbabilitySpace(S):27return isinstance(S, ProbabilitySpace_generic)2829def is_DiscreteProbabilitySpace(S):30return isinstance(S, DiscreteProbabilitySpace)3132def is_RandomVariable(X):33return isinstance(X, RandomVariable_generic)3435def is_DiscreteRandomVariable(X):36return isinstance(X, DiscreteRandomVariable)3738################################################################################39################################################################################4041# We could inherit from a functions class here but use ParentWithBase4243class RandomVariable_generic(ParentWithBase):44"""45A random variable.46"""47def __init__(self, X, RR):48if not is_ProbabilitySpace(X):49raise TypeError, "Argument X (= %s) must be a probability space" % X50ParentWithBase.__init__(self, X)51self._codomain = RR5253def probability_space(self):54return self.base()5556def domain(self):57return self.base()5859def codomain(self):60return self._codomain6162def field(self):63return self._codomain6465class DiscreteRandomVariable(RandomVariable_generic):66"""67A random variable on a discrete probability space.68"""69def __init__(self, X, f, codomain = None, check = False):70r"""71Create free binary string monoid on `n` generators.7273INPUT: x: A probability space f: A dictionary such that X[x] =74value for x in X is the discrete function on X75"""76if not is_DiscreteProbabilitySpace(X):77raise TypeError, "Argument X (= %s) must be a discrete probability space" % X78if check:79raise NotImplementedError, "Not implemented"80if codomain is None:81RR = RealField()82else:83RR = codomain84RandomVariable_generic.__init__(self, X, RR)85self._function = f8687def __call__(self,x):88"""89Return the value of the random variable at x.90"""91RR = self.field()92try:93return RR(self._function[x])94except KeyError:95# Need some condition for x being a valid domain element:96# raise IndexError, "Argument x (= %s) is not a valid domain element." % x97return RR(0)9899def __repr__(self):100return "Discrete random variable defined by %s" % self._function101102def function(self):103"""104The function defining the random variable.105"""106return self._function107108def expectation(self):109r"""110The expectation of the discrete random variable, namely111`\sum_{x \in S} p(x) X[x]`, where `X` = self and112`S` is the probability space of `X`.113"""114E = 0115Omega = self.probability_space()116for x in self._function.keys():117E += Omega(x) * self(x)118return E119120def translation_expectation(self, map):121r"""122The expectation of the discrete random variable, namely123`\sum_{x \in S} p(x) X[e(x)]`, where `X` = self,124`S` is the probability space of `X`, and125`e` = map.126"""127E = 0128Omega = self.probability_space()129for x in Omega._function.keys():130E += Omega(x) * self(map(x))131return E132133def variance(self):134r"""135The variance of the discrete random variable.136137Let `S` be the probability space of `X` = self,138with probability function `p`, and `E(X)` be the139expectation of `X`. Then the variance of `X` is:140141.. math::142143\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2144"""145Omega = self.probability_space()146mu = self.expectation()147var = 0148for x in self._function.keys():149var += Omega(x) * (self(x) - mu)**2150return var151152def translation_variance(self, map):153r"""154The variance of the discrete random variable `X \circ e`,155where `X` = self, and `e` = map.156157Let `S` be the probability space of `X` = self,158with probability function `p`, and `E(X)` be the159expectation of `X`. Then the variance of `X` is:160161.. math::162163\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2164"""165Omega = self.probability_space()166mu = self.translation_expectation(map)167var = 0168for x in Omega._function.keys():169var += Omega(x) * (self(map(x)) - mu)**2170return var171172def covariance(self, other):173r"""174The covariance of the discrete random variable X = self with Y =175other.176177Let `S` be the probability space of `X` = self,178with probability function `p`, and `E(X)` be the179expectation of `X`. Then the variance of `X` is:180181.. math::182183\text{cov}(X,Y) = E((X-E(X)*(Y-E(Y)) = \sum_{x \in S} p(x) (X(x) - E(X))(Y(x) - E(Y))184"""185Omega = self.probability_space()186if Omega != other.probability_space():187raise ValueError, \188"Argument other (= %s) must be defined on the same probability space." % other189muX = self.expectation()190muY = other.expectation()191cov = 0192for x in self._function.keys():193cov += Omega(x)*(self(x) - muX)*(other(x) - muY)194return cov195196def translation_covariance(self, other, map):197r"""198The covariance of the probability space X = self with image of Y =199other under the given map of the probability space.200201Let `S` be the probability space of `X` = self,202with probability function `p`, and `E(X)` be the203expectation of `X`. Then the variance of `X` is:204205.. math::206207\text{cov}(X,Y) = E((X-E(X)*(Y-E(Y)) = \sum_{x \in S} p(x) (X(x) - E(X))(Y(x) - E(Y))208"""209Omega = self.probability_space()210if Omega != other.probability_space():211raise ValueError, \212"Argument other (= %s) must be defined on the same probability space." % other213muX = self.expectation()214muY = other.translation_expectation(map)215cov = 0216for x in Omega._function.keys():217cov += Omega(x)*(self(x) - muX)*(other(map(x)) - muY)218return cov219220def standard_deviation(self):221r"""222The standard deviation of the discrete random variable.223224Let `S` be the probability space of `X` = self,225with probability function `p`, and `E(X)` be the226expectation of `X`. Then the standard deviation of227`X` is defined to be228229.. math::230231\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))**2}232"""233return sqrt(self.variance())234235def translation_standard_deviation(self, map):236r"""237The standard deviation of the translated discrete random variable238`X \circ e`, where `X` = self and `e` =239map.240241Let `S` be the probability space of `X` = self,242with probability function `p`, and `E(X)` be the243expectation of `X`. Then the standard deviation of244`X` is defined to be245246.. math::247248\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))**2}249"""250return sqrt(self.translation_variance(map))251252def correlation(self, other):253"""254The correlation of the probability space X = self with Y = other.255"""256cov = self.covariance(other)257sigX = self.standard_deviation()258sigY = other.standard_deviation()259if sigX == 0 or sigY == 0:260raise ValueError, \261"Correlation not defined if standard deviations are not both nonzero."262return cov/(sigX*sigY)263264def translation_correlation(self, other, map):265"""266The correlation of the probability space X = self with image of Y =267other under map.268"""269cov = self.translation_covariance(other, map)270sigX = self.standard_deviation()271sigY = other.translation_standard_deviation(map)272if sigX == 0 or sigY == 0:273raise ValueError, \274"Correlation not defined if standard deviations are not both nonzero."275return cov/(sigX*sigY)276277################################################################################278################################################################################279280class ProbabilitySpace_generic(RandomVariable_generic):281r"""282A probability space.283"""284def __init__(self, domain, RR):285"""286A generic probability space on given domain space and codomain287ring.288"""289if isinstance(domain, list):290domain = tuple(domain)291if not isinstance(domain, tuple):292raise TypeError, \293"Argument domain (= %s) must be a list, tuple, or set containing." % domain294self._domain = domain295RandomVariable_generic.__init__(self, self, RR)296297def domain(self):298return self._domain299300class DiscreteProbabilitySpace(ProbabilitySpace_generic,DiscreteRandomVariable):301r"""302The discrete probability space303"""304def __init__(self, X, P, codomain = None, check = False):305r"""306Create the discrete probability space with probabilities on the307space X given by the dictionary P with values in the field308real_field.309310EXAMPLES::311312sage: S = [ i for i in range(16) ]313sage: P = {}314sage: for i in range(15): P[i] = 2^(-i-1)315sage: P[15] = 2^-16316sage: X = DiscreteProbabilitySpace(S,P)317sage: X.domain()318(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)319sage: X.set()320{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}321sage: X.entropy()3221.9997253418323324A probability space can be defined on any list of elements.325326EXAMPLES::327328sage: AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'329sage: S = [ AZ[i] for i in range(26) ]330sage: P = { 'A':1/2, 'B':1/4, 'C':1/4 }331sage: X = DiscreteProbabilitySpace(S,P)332sage: X333Discrete probability space defined by {'A': 1/2, 'C': 1/4, 'B': 1/4}334sage: X.entropy()3351.5336"""337if codomain is None:338codomain = RealField()339if not is_RealField(codomain) and not is_RationalField(codomain):340raise TypeError, "Argument codomain (= %s) must be the reals or rationals" % codomain341if check:342one = sum([ P[x] for x in P.keys() ])343if is_RationalField(codomain):344if not one == 1:345raise TypeError, "Argument P (= %s) does not define a probability function"346else:347if not Abs(one-1) < 2^(-codomain.precision()+1):348raise TypeError, "Argument P (= %s) does not define a probability function"349ProbabilitySpace_generic.__init__(self, X, codomain)350DiscreteRandomVariable.__init__(self, self, P, codomain, check)351352def __repr__(self):353return "Discrete probability space defined by %s" % self.function()354355def set(self):356r"""357The set of values of the probability space taking possibly nonzero358probability (a subset of the domain).359"""360return Set(self.function().keys())361362def entropy(self):363"""364The entropy of the probability space.365"""366def neg_xlog2x(p):367if p == 0:368return 0369else:370return -p*log(p,2)371p = self.function()372return sum([ neg_xlog2x(p[x]) for x in p.keys() ])373374375376