Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/probability/random_variable.py
8815 views
1
r"""
2
Random variables and probability spaces
3
4
This introduces a class of random variables, with the focus on
5
discrete random variables (i.e. on a discrete probability space).
6
This avoids the problem of defining a measure space and measurable
7
functions.
8
"""
9
10
#*****************************************************************************
11
# Copyright (C) 2007 David Kohel <[email protected]>
12
#
13
# Distributed under the terms of the GNU General Public License (GPL)
14
#
15
# http://www.gnu.org/licenses/
16
#*****************************************************************************
17
18
from sage.structure.parent_base import ParentWithBase
19
from sage.misc.functional import sqrt, log
20
from sage.rings.real_mpfr import (RealField, is_RealField)
21
from sage.rings.rational_field import is_RationalField
22
from sage.sets.set import Set
23
24
################################################################################
25
################################################################################
26
27
def is_ProbabilitySpace(S):
28
return isinstance(S, ProbabilitySpace_generic)
29
30
def is_DiscreteProbabilitySpace(S):
31
return isinstance(S, DiscreteProbabilitySpace)
32
33
def is_RandomVariable(X):
34
return isinstance(X, RandomVariable_generic)
35
36
def is_DiscreteRandomVariable(X):
37
return isinstance(X, DiscreteRandomVariable)
38
39
################################################################################
40
################################################################################
41
42
# We could inherit from a functions class here but use ParentWithBase
43
44
class RandomVariable_generic(ParentWithBase):
45
"""
46
A random variable.
47
"""
48
def __init__(self, X, RR):
49
if not is_ProbabilitySpace(X):
50
raise TypeError, "Argument X (= %s) must be a probability space" % X
51
ParentWithBase.__init__(self, X)
52
self._codomain = RR
53
54
def probability_space(self):
55
return self.base()
56
57
def domain(self):
58
return self.base()
59
60
def codomain(self):
61
return self._codomain
62
63
def field(self):
64
return self._codomain
65
66
class DiscreteRandomVariable(RandomVariable_generic):
67
"""
68
A random variable on a discrete probability space.
69
"""
70
def __init__(self, X, f, codomain = None, check = False):
71
r"""
72
Create free binary string monoid on `n` generators.
73
74
INPUT: x: A probability space f: A dictionary such that X[x] =
75
value for x in X is the discrete function on X
76
"""
77
if not is_DiscreteProbabilitySpace(X):
78
raise TypeError, "Argument X (= %s) must be a discrete probability space" % X
79
if check:
80
raise NotImplementedError, "Not implemented"
81
if codomain is None:
82
RR = RealField()
83
else:
84
RR = codomain
85
RandomVariable_generic.__init__(self, X, RR)
86
self._function = f
87
88
def __call__(self,x):
89
"""
90
Return the value of the random variable at x.
91
"""
92
RR = self.field()
93
try:
94
return RR(self._function[x])
95
except KeyError:
96
# Need some condition for x being a valid domain element:
97
# raise IndexError, "Argument x (= %s) is not a valid domain element." % x
98
return RR(0)
99
100
def __repr__(self):
101
return "Discrete random variable defined by %s" % self._function
102
103
def function(self):
104
"""
105
The function defining the random variable.
106
"""
107
return self._function
108
109
def expectation(self):
110
r"""
111
The expectation of the discrete random variable, namely
112
`\sum_{x \in S} p(x) X[x]`, where `X` = self and
113
`S` is the probability space of `X`.
114
"""
115
E = 0
116
Omega = self.probability_space()
117
for x in self._function.keys():
118
E += Omega(x) * self(x)
119
return E
120
121
def translation_expectation(self, map):
122
r"""
123
The expectation of the discrete random variable, namely
124
`\sum_{x \in S} p(x) X[e(x)]`, where `X` = self,
125
`S` is the probability space of `X`, and
126
`e` = map.
127
"""
128
E = 0
129
Omega = self.probability_space()
130
for x in Omega._function.keys():
131
E += Omega(x) * self(map(x))
132
return E
133
134
def variance(self):
135
r"""
136
The variance of the discrete random variable.
137
138
Let `S` be the probability space of `X` = self,
139
with probability function `p`, and `E(X)` be the
140
expectation of `X`. Then the variance of `X` is:
141
142
.. math::
143
144
\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2
145
"""
146
Omega = self.probability_space()
147
mu = self.expectation()
148
var = 0
149
for x in self._function.keys():
150
var += Omega(x) * (self(x) - mu)**2
151
return var
152
153
def translation_variance(self, map):
154
r"""
155
The variance of the discrete random variable `X \circ e`,
156
where `X` = self, and `e` = map.
157
158
Let `S` be the probability space of `X` = self,
159
with probability function `p`, and `E(X)` be the
160
expectation of `X`. Then the variance of `X` is:
161
162
.. math::
163
164
\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2
165
"""
166
Omega = self.probability_space()
167
mu = self.translation_expectation(map)
168
var = 0
169
for x in Omega._function.keys():
170
var += Omega(x) * (self(map(x)) - mu)**2
171
return var
172
173
def covariance(self, other):
174
r"""
175
The covariance of the discrete random variable X = self with Y =
176
other.
177
178
Let `S` be the probability space of `X` = self,
179
with probability function `p`, and `E(X)` be the
180
expectation of `X`. Then the variance of `X` is:
181
182
.. math::
183
184
\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))
185
"""
186
Omega = self.probability_space()
187
if Omega != other.probability_space():
188
raise ValueError, \
189
"Argument other (= %s) must be defined on the same probability space." % other
190
muX = self.expectation()
191
muY = other.expectation()
192
cov = 0
193
for x in self._function.keys():
194
cov += Omega(x)*(self(x) - muX)*(other(x) - muY)
195
return cov
196
197
def translation_covariance(self, other, map):
198
r"""
199
The covariance of the probability space X = self with image of Y =
200
other under the given map of the probability space.
201
202
Let `S` be the probability space of `X` = self,
203
with probability function `p`, and `E(X)` be the
204
expectation of `X`. Then the variance of `X` is:
205
206
.. math::
207
208
\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))
209
"""
210
Omega = self.probability_space()
211
if Omega != other.probability_space():
212
raise ValueError, \
213
"Argument other (= %s) must be defined on the same probability space." % other
214
muX = self.expectation()
215
muY = other.translation_expectation(map)
216
cov = 0
217
for x in Omega._function.keys():
218
cov += Omega(x)*(self(x) - muX)*(other(map(x)) - muY)
219
return cov
220
221
def standard_deviation(self):
222
r"""
223
The standard deviation of the discrete random variable.
224
225
Let `S` be the probability space of `X` = self,
226
with probability function `p`, and `E(X)` be the
227
expectation of `X`. Then the standard deviation of
228
`X` is defined to be
229
230
.. math::
231
232
\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))**2}
233
"""
234
return sqrt(self.variance())
235
236
def translation_standard_deviation(self, map):
237
r"""
238
The standard deviation of the translated discrete random variable
239
`X \circ e`, where `X` = self and `e` =
240
map.
241
242
Let `S` be the probability space of `X` = self,
243
with probability function `p`, and `E(X)` be the
244
expectation of `X`. Then the standard deviation of
245
`X` is defined to be
246
247
.. math::
248
249
\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))**2}
250
"""
251
return sqrt(self.translation_variance(map))
252
253
def correlation(self, other):
254
"""
255
The correlation of the probability space X = self with Y = other.
256
"""
257
cov = self.covariance(other)
258
sigX = self.standard_deviation()
259
sigY = other.standard_deviation()
260
if sigX == 0 or sigY == 0:
261
raise ValueError, \
262
"Correlation not defined if standard deviations are not both nonzero."
263
return cov/(sigX*sigY)
264
265
def translation_correlation(self, other, map):
266
"""
267
The correlation of the probability space X = self with image of Y =
268
other under map.
269
"""
270
cov = self.translation_covariance(other, map)
271
sigX = self.standard_deviation()
272
sigY = other.translation_standard_deviation(map)
273
if sigX == 0 or sigY == 0:
274
raise ValueError, \
275
"Correlation not defined if standard deviations are not both nonzero."
276
return cov/(sigX*sigY)
277
278
################################################################################
279
################################################################################
280
281
class ProbabilitySpace_generic(RandomVariable_generic):
282
r"""
283
A probability space.
284
"""
285
def __init__(self, domain, RR):
286
"""
287
A generic probability space on given domain space and codomain
288
ring.
289
"""
290
if isinstance(domain, list):
291
domain = tuple(domain)
292
if not isinstance(domain, tuple):
293
raise TypeError, \
294
"Argument domain (= %s) must be a list, tuple, or set containing." % domain
295
self._domain = domain
296
RandomVariable_generic.__init__(self, self, RR)
297
298
def domain(self):
299
return self._domain
300
301
class DiscreteProbabilitySpace(ProbabilitySpace_generic,DiscreteRandomVariable):
302
r"""
303
The discrete probability space
304
"""
305
def __init__(self, X, P, codomain = None, check = False):
306
r"""
307
Create the discrete probability space with probabilities on the
308
space X given by the dictionary P with values in the field
309
real_field.
310
311
EXAMPLES::
312
313
sage: S = [ i for i in range(16) ]
314
sage: P = {}
315
sage: for i in range(15): P[i] = 2^(-i-1)
316
sage: P[15] = 2^-16
317
sage: X = DiscreteProbabilitySpace(S,P)
318
sage: X.domain()
319
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
320
sage: X.set()
321
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
322
sage: X.entropy()
323
1.9997253418
324
325
A probability space can be defined on any list of elements.
326
327
EXAMPLES::
328
329
sage: AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
330
sage: S = [ AZ[i] for i in range(26) ]
331
sage: P = { 'A':1/2, 'B':1/4, 'C':1/4 }
332
sage: X = DiscreteProbabilitySpace(S,P)
333
sage: X
334
Discrete probability space defined by {'A': 1/2, 'C': 1/4, 'B': 1/4}
335
sage: X.entropy()
336
1.5
337
"""
338
if codomain is None:
339
codomain = RealField()
340
if not is_RealField(codomain) and not is_RationalField(codomain):
341
raise TypeError, "Argument codomain (= %s) must be the reals or rationals" % codomain
342
if check:
343
one = sum([ P[x] for x in P.keys() ])
344
if is_RationalField(codomain):
345
if not one == 1:
346
raise TypeError, "Argument P (= %s) does not define a probability function"
347
else:
348
if not Abs(one-1) < 2^(-codomain.precision()+1):
349
raise TypeError, "Argument P (= %s) does not define a probability function"
350
ProbabilitySpace_generic.__init__(self, X, codomain)
351
DiscreteRandomVariable.__init__(self, self, P, codomain, check)
352
353
def __repr__(self):
354
return "Discrete probability space defined by %s" % self.function()
355
356
def set(self):
357
r"""
358
The set of values of the probability space taking possibly nonzero
359
probability (a subset of the domain).
360
"""
361
return Set(self.function().keys())
362
363
def entropy(self):
364
"""
365
The entropy of the probability space.
366
"""
367
def neg_xlog2x(p):
368
if p == 0:
369
return 0
370
else:
371
return -p*log(p,2)
372
p = self.function()
373
return sum([ neg_xlog2x(p[x]) for x in p.keys() ])
374
375
376