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