import jax.numpy as jnp
import jax
from jax import random
import tensorflow_probability.substrates.jax as tfp
= tfp.distributions
tfd import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format='retina'
=random.PRNGKey(0), p=0.6, shape=(10,)).astype(int).sum() random.bernoulli(key
WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
DeviceArray(7, dtype=int32)
Probability of getting X heads
from itertools import permutations
set(permutations(['H', 'H', 'H', 'T'], 4 ))
{('H', 'H', 'H', 'T'),
('H', 'H', 'T', 'H'),
('H', 'T', 'H', 'H'),
('T', 'H', 'H', 'H')}
from sympy.utilities.iterables import multiset_permutations
list(multiset_permutations([True, True, False], 3))
[[False, True, True], [True, False, True], [True, True, False]]
def print_permutations(n_heads=1, n_total=10):
= ['H']*n_heads
init 'T']*(n_total-n_heads))
init.extend([= list(multiset_permutations(init, n_total))
permutations return permutations, len(permutations)
= print_permutations() perm, l
perm
[['H', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T'],
['T', 'H', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T'],
['T', 'T', 'H', 'T', 'T', 'T', 'T', 'T', 'T', 'T'],
['T', 'T', 'T', 'H', 'T', 'T', 'T', 'T', 'T', 'T'],
['T', 'T', 'T', 'T', 'H', 'T', 'T', 'T', 'T', 'T'],
['T', 'T', 'T', 'T', 'T', 'H', 'T', 'T', 'T', 'T'],
['T', 'T', 'T', 'T', 'T', 'T', 'H', 'T', 'T', 'T'],
['T', 'T', 'T', 'T', 'T', 'T', 'T', 'H', 'T', 'T'],
['T', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'H', 'T'],
['T', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'H']]
l
10
= {}
num_sequences for n_heads in range(0, 11, 1):
= print_permutations(n_heads=n_heads, n_total=10) _, num_sequences[n_heads]
= pd.Series(num_sequences)
num_sequences num_sequences
0 1
1 10
2 45
3 120
4 210
5 252
6 210
7 120
8 45
9 10
10 1
dtype: int64
="Heads", ylabel="Permutations") num_sequences.plot(xlabel
from math import comb
10, 3) comb(
120
list(map(partial(comb, 10), range(0, 11)))) pd.Series(
0 1
1 10
2 45
3 120
4 210
5 252
6 210
7 120
8 45
9 10
10 1
dtype: int64
### Probability of given sequence
def prob_sequence(n_heads = 5, n_total = 10, p_head = 0.3):
return (p_head**n_heads)*(1-p_head)**(n_total-n_heads)
from functools import partial
0, 10, 0.3) prob_sequence(
0.02824752489999998
= partial(prob_sequence, n_total=10, p_head=0.3) prob_sequence_fixed_p
= prob_sequence_fixed_p(num_sequences.index)*num_sequences
probs probs
0 0.028248
1 0.121061
2 0.233474
3 0.266828
4 0.200121
5 0.102919
6 0.036757
7 0.009002
8 0.001447
9 0.000138
10 0.000006
dtype: float64
probs.plot()
import rich
rich.inspect(tfd.Binomial)
╭───── <class 'tensorflow_probability.substrates.jax.distributions.binomial.Binomial'> ─────╮ │ class Binomial(total_count, logits=None, probs=None, validate_args=False, │ │ allow_nan_stats=True, name=None): │ │ │ │ Binomial distribution. │ │ │ │ allow_nan_stats = <property object at 0x1a7594310> │ │ batch_shape = <property object at 0x1a7594400> │ │ dtype = <property object at 0x1a7594220> │ │ event_shape = <property object at 0x1a7594450> │ │ experimental_shard_axis_names = <property object at 0x1a75943b0> │ │ logits = <property object at 0x1a75f79a0> │ │ name = <property object at 0x1a75941d0> │ │ parameters = <property object at 0x1a7594270> │ │ probs = <property object at 0x1a75f79f0> │ │ reparameterization_type = <property object at 0x1a75942c0> │ │ total_count = <property object at 0x1a75f7950> │ │ trainable_variables = <property object at 0x115bf0f40> │ │ validate_args = <property object at 0x1a7594360> │ │ variables = <property object at 0x115bf0f90> │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯
from scipy.special import comb as scomb
from dataclasses import dataclass
@dataclass
class OurBinomial:
int = 10
total_count: float = 0.5
probs:
def __repr__(self):
return (
"Binomial distribution"
+ "\n"
+ "---------------------\n"
+ f"P(H) = {self.probs}\nTotal Count = {self.total_count}"
)
def mode(self):
return self.probs * self.total_count
def prob(self, observed_num_heads):
# (N choose K)*(p**n_h)*(1-p)**n_t
return (
self.total_count, observed_num_heads)
comb(* (self.probs**observed_num_heads)
* (1 - self.probs) ** (self.total_count - observed_num_heads)
)
def logprob(self, observed_num_heads):
return (
self.total_count, observed_num_heads))
jnp.log(comb(+ observed_num_heads * jnp.log(self.probs)
+ (self.total_count - observed_num_heads) * jnp.log(1 - self.probs)
)
= OurBinomial(probs=0.3)
c c
Binomial distribution
---------------------
P(H) = 0.3
Total Count = 10
c.total_count
10
= tfd.Binomial(total_count=10, probs=0.3) tfp_bin
tfp_bin.mode()
DeviceArray(3., dtype=float32)
c.mode()
3.0
2) tfp_bin.prob(
DeviceArray(0.23347428, dtype=float32)
10, 3) comb(
120
2) c.prob(
0.23347444049999988
2), tfp_bin.prob(2)) jnp.allclose(c.prob(
DeviceArray(True, dtype=bool)
2) tfp_bin.log_prob(
DeviceArray(-1.4546833, dtype=float32)
2) c.logprob(
DeviceArray(-1.4546828, dtype=float32)
= {}
binomial_dict # Divide hour in 10 intervals
10] = OurBinomial(total_count=10, probs=0.3).prob(5) binomial_dict[
binomial_dict
{10: 0.10291934519999994}
for interval in [10, 20, 60, 1000, 10000]:
= OurBinomial(total_count=interval, probs=3.0/interval).prob(5) binomial_dict[interval]
binomial_dict
{10: 0.10291934519999994,
20: 0.10284517954557212,
60: 0.10161579161609695,
1000: 0.10086908328293617,
10000: 0.10082385299843205}
=True) pd.Series(binomial_dict).plot(logx