Wiki
Clone wikiLea / LeappSnippets
Table of Content
- Creating a probability distribution
- Cloning a distribution
- Adding distributions
- Displaying probabilities
- Extracting individual probabilities
- Evaluating conditions
- Calculating probability distribution indicators
- Generating random samples
- Calculating a cartesian product
- Applying a function
- Applying an instance method
- Getting an instance attribute
- Evaluating conditional probabilities
- Indexing / slicing
- Misc
Creating a probability distribution
lea> die1 = ?(1,2,3,4,5,6) lea> die1 1 : 1/6 2 : 1/6 3 : 1/6 4 : 1/6 5 : 1/6 6 : 1/6
or, equivalently,
lea> die1 = ?([1,2,3,4,5,6]) lea> die1 = ?(range(1,7)) lea> die1 = ?(range(6)) + 1 lea> die1 = 1 + ?(range(6)) lea> die1 = ?(6-i for i in range(6)) lea> valuesTuple = (1,2,3,4,5,6) lea> die1 = ?(valuesTuple) lea> valuesIter = (6-i for i in range(6)) lea> die1 = ?(valuesIter) lea> die1 = ?{1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1} lea> die1 = ?{1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6}
Examples with strings:
lea> fairWeather = ?('sunny','cloudy','raining') lea> fairWeather cloudy : 1/3 raining : 1/3 sunny : 1/3 lea> weather = ?{'sunny': 68%, 'cloudy': 7%, 'raining': 25%} lea> weather cloudy : 7/100 raining : 25/100 sunny : 68/100
Since Python strings are iterable sequences, a letter frequency counter is made easy:
lea> ?('ALEA JACTA EST') : 2/14 A : 4/14 C : 1/14 E : 2/14 J : 1/14 L : 1/14 S : 1/14 T : 2/14
Note: to define a "singleton" distribution (certain value), append a coma (standard Python trick):
lea> ?('ALEA JACTA EST',) ALEA JACTA EST : 1
Boolean random variables:
lea> flip = ?:(1/2) lea> flip False : 1/2 True : 1/2
equivalent to
lea> flip = ?:(50%) lea> flip = ?:(0.5) lea> flip = ?(False,True) lea> flip = ?{False: 1/2, True: 1/2} lea> flip = ?{False: 50%, True: 50%} lea> flip = ?{False: 0.5, True: 0.5}
and
lea> bflip = ?:(1/4) lea> bflip False : 3/4 True : 1/4
equivalent to
lea> bflip = ?:(25%) lea> bflip = ?:(0.25) lea> bflip = ?{False: 3/4, True: 1/4} ...
Cloning a distribution
(in order to have independent random variable)
lea> die2 = ?die1
Adding distributions
lea> dice = die1 + die2 lea> dice 2 : 1/36 3 : 2/36 4 : 3/36 5 : 4/36 6 : 5/36 7 : 6/36 8 : 5/36 9 : 4/36 10 : 3/36 11 : 2/36 12 : 1/36
or, equivalently (well, if no conditional probability involved - see below!),
lea> dice = die1 + ?die1 lea> dice = sum((die1,die2)) lea> dice = sum(?die1 for i in range(2)) lea> dice = ?[2]die1
Displaying probabilities
lea> :. dice 2 : 0.027778 3 : 0.055556 4 : 0.083333 5 : 0.111111 6 : 0.138889 7 : 0.166667 8 : 0.138889 9 : 0.111111 10 : 0.083333 11 : 0.055556 12 : 0.027778 lea> :% dice 2 : 2.8 % 3 : 5.6 % 4 : 8.3 % 5 : 11.1 % 6 : 13.9 % 7 : 16.7 % 8 : 13.9 % 9 : 11.1 % 10 : 8.3 % 11 : 5.6 % 12 : 2.8 % lea> :% bflip False : 75.0 % True : 25.0 %
Extracting individual probabilities
lea> dice@7 1/6 lea> :. dice@7 0.16666666666666666 lea> :% dice@7 16.666667 % lea> (dice <= 6) @True 5/12 lea> :% (dice <= 6) @True 41.666667 % lea> bflip@True 1/4 lea> :. bflip@True 0.25
Note that @True
can be shortcut as @
:
lea> :% (dice <= 6) @ 41.666667 % lea> :. bflip@ 0.25
Evaluating conditions
lea> die1 == 2 False : 5/6 True : 1/6 lea> die1 <= 2 False : 2/3 True : 1/3 lea> :% die1 <= 2 False : 66.7 % True : 33.3 % lea> (2 <= die1) & (die1 < 4) False : 2/3 True : 1/3 lea> ~((2 <= die1) & (die1 < 4)) False : 1/3 True : 2/3 lea> (2 > die1) | (die1 >= 4) False : 1/3 True : 2/3 lea> (2 <= die1) & (die2 < 4) False : 7/12 True : 5/12 lea> (2 <= die1) & (dice < 4) False : 35/36 True : 1/36 lea> ?[50]die1 == 60 False : 808281277464764060643139600393722578321/808281277464764060643139600456536293376 True : 62813715055/808281277464764060643139600456536293376 lea> :. ?[50]die1 == 60 False : 1.000000 True : 0.000000
Calculating probability distribution indicators
lea> dice.mean 7.0 lea> dice.stdev 2.41522945769824 lea> dice.entropy 3.2744019192887714
Generating random samples
lea> dice $ 7 lea> dice $ 5 lea> dice $(20) (5, 4, 7, 10, 6, 9, 8, 6, 10, 4, 7, 6, 7, 6, 3, 10, 7, 5, 9, 6) lea> flip $(20) (False, True, True, False, True, True, False, False, False, True, False, True, True, True, False, True, False, False, True, True) lea> bflip $(20) (False, False, True, False, False, False, False, False, False, True, False, False, True, False, False, True, False, False, True, True)
Note that dice $(20)
generates something equivalent to the the results of any of the following expressions
lea> tuple(dice$ for i in range(20)) lea> tuple(die1$ + die2$ for i in range(20))
Controlling the frequencies in a random sample:
lea> ?(dice $(36000)) 2 : 931/36000 3 : 2000/36000 4 : 3065/36000 5 : 3859/36000 6 : 5088/36000 7 : 6010/36000 8 : 5010/36000 9 : 3964/36000 10 : 3030/36000 11 : 2047/36000 12 : 996/36000 lea> :% ?(dice $(36000)) 2 : 2.7 % 3 : 5.5 % 4 : 8.6 % 5 : 10.6 % 6 : 13.6 % 7 : 17.0 % 8 : 13.9 % 9 : 11.3 % 10 : 8.2 % 11 : 5.5 % 12 : 3.0 %
The return of Caesar, the latin parrot...
lea> latinParrot = ?('ALEA JACTA EST') lea> ''.join(latinParrot $(30)) 'TA AECETAAATA AE ETJ AASLAAE'
Calculating a cartesian product
lea> ?*(die1,die2) (1, 1) : 1/36 (1, 2) : 1/36 (1, 3) : 1/36 (1, 4) : 1/36 (1, 5) : 1/36 (1, 6) : 1/36 (2, 1) : 1/36 ... (6, 5) : 1/36 (6, 6) : 1/36 lea> ?*(die1,die2,die1+die2) (1, 1, 2) : 1/36 (1, 2, 3) : 1/36 (1, 3, 4) : 1/36 ... (6, 5, 11) : 1/36 (6, 6, 12) : 1/36
Applying a function
Putting a ?
in front of a function applied on Lea argument(s) builds a new Lea distribution, by applying the function on each inner values:
lea> 'die1 = ' + ?str(die1) die1 = 1 : 1/6 die1 = 2 : 1/6 die1 = 3 : 1/6 die1 = 4 : 1/6 die1 = 5 : 1/6 die1 = 6 : 1/6
Note the difference if the ?
is omitted:
lea> 'die1 = ' + str(die1) 'die1 = 1 : 1/6\n2 : 1/6\n3 : 1/6\n4 : 1/6\n5 : 1/6\n6 : 1/6'
?
prefix, the str
function is applied on the whole distribution, instead of individual values : the result is a standard Python string, not a Lea distribution.
User-defined functions
lea> def f(x,y): ... return '%02d!' % (x+y) lea> ?f(die1,die2) 02! : 1/36 03! : 2/36 04! : 3/36 05! : 4/36 06! : 5/36 07! : 6/36 08! : 5/36 09! : 4/36 10! : 3/36 11! : 2/36 12! : 1/36
Applying an instance method
lea> die1.to_bytes(2,"big") b'\x00\x01' : 1/6 b'\x00\x02' : 1/6 b'\x00\x03' : 1/6 b'\x00\x04' : 1/6 b'\x00\x05' : 1/6 b'\x00\x06' : 1/6
Getting an instance attribute
lea> complexDice = die1 + die2*1j lea> complexDice (5+2j) : 1/36 (1+1j) : 1/36 (2+1j) : 1/36 ... (6+3j) : 1/36 (6+5j) : 1/36 lea> complexDice.imag 1.0 : 1/6 2.0 : 1/6 3.0 : 1/6 4.0 : 1/6 5.0 : 1/6 6.0 : 1/6
Evaluating conditional probabilities
What follows the exclamation mark is a given fact, expressed as a condition expression. The expression before the exclamation mark is a distribution that is evaluated assuming that the given condition is certainly true.
lea> dice = die1 + die2 lea> dice ! dice < 5 2 : 1/6 3 : 2/6 4 : 3/6 lea> dice ! die1+die2 < 5 2 : 1/6 3 : 2/6 4 : 3/6 lea> dice ! (4 <= dice) & (dice < 7) 4 : 3/12 5 : 4/12 6 : 5/12 lea> dice ! (die1 <= 3) & (die2 <= 3) 2 : 1/9 3 : 2/9 4 : 3/9 5 : 2/9 6 : 1/9 lea> (5 <= dice) ! (die1 <= 3) & (die2 <= 3) False : 2/3 True : 1/3 lea> ?*(die1,die2) ! dice == 5 (1, 4) : 1/4 (2, 3) : 1/4 (3, 2) : 1/4 (4, 1) : 1/4 lea> ?*(die1,die2,dice) ! dice <= 5 (1, 1, 2) : 1/10 (1, 2, 3) : 1/10 (1, 3, 4) : 1/10 (1, 4, 5) : 1/10 (2, 1, 3) : 1/10 (2, 2, 4) : 1/10 (2, 3, 5) : 1/10 (3, 1, 4) : 1/10 (3, 2, 5) : 1/10 (4, 1, 5) : 1/10
Indexing / slicing
Provided that the values in the distribution are indexable (e.g. strings, tuples), indexing made on a Lea instance is propagated in the inner values, obeying Python index numbering:
lea> name = ?('Gino', 'Guy', 'Jack', 'Lea', 'Leon', 'Loth', 'Lucienne', 'Pierre', 'Piotr', 'Rachel') lea> name[0] G : 2/10 J : 1/10 L : 4/10 P : 2/10 R : 1/10 lea> name[1] a : 2/10 e : 2/10 i : 3/10 o : 1/10 u : 2/10 lea> name[-1] a : 1/10 e : 2/10 h : 1/10 k : 1/10 l : 1/10 n : 1/10 o : 1/10 r : 1/10 y : 1/10 lea> name[0] + name[-1] Go : 1/10 Gy : 1/10 Jk : 1/10 La : 1/10 Le : 1/10 Lh : 1/10 Ln : 1/10 Pe : 1/10 Pr : 1/10 Rl : 1/10
Slicing is also feasible:
lea> name[1:3] ac : 2/10 ea : 1/10 eo : 1/10 ie : 1/10 in : 1/10 io : 1/10 ot : 1/10 uc : 1/10 uy : 1/10 lea> 'T'+name[1:] ! name[0]=='L' Tea : 1/4 Teon : 1/4 Toth : 1/4 Tucienne : 1/4
Misc
Playing cards
lea> cards = ?('A23456789TJQK') + ?('♥♣♦♠') lea> cards 2♠ : 1/52 2♣ : 1/52 2♥ : 1/52 2♦ : 1/52 3♠ : 1/52 3♣ : 1/52 3♥ : 1/52 3♦ : 1/52 4♠ : 1/52 4♣ : 1/52 4♥ : 1/52 4♦ : 1/52 5♠ : 1/52 5♣ : 1/52 5♥ : 1/52 5♦ : 1/52 6♠ : 1/52 6♣ : 1/52 6♥ : 1/52 6♦ : 1/52 7♠ : 1/52 7♣ : 1/52 7♥ : 1/52 7♦ : 1/52 8♠ : 1/52 8♣ : 1/52 8♥ : 1/52 8♦ : 1/52 9♠ : 1/52 9♣ : 1/52 9♥ : 1/52 9♦ : 1/52 A♠ : 1/52 A♣ : 1/52 A♥ : 1/52 A♦ : 1/52 J♠ : 1/52 J♣ : 1/52 J♥ : 1/52 J♦ : 1/52 K♠ : 1/52 K♣ : 1/52 K♥ : 1/52 K♦ : 1/52 Q♠ : 1/52 Q♣ : 1/52 Q♥ : 1/52 Q♦ : 1/52 T♠ : 1/52 T♣ : 1/52 T♥ : 1/52 T♦ : 1/52 lea> cards[0] 2 : 1/13 3 : 1/13 4 : 1/13 5 : 1/13 6 : 1/13 7 : 1/13 8 : 1/13 9 : 1/13 A : 1/13 J : 1/13 K : 1/13 Q : 1/13 T : 1/13 lea> cards[1] ♠ : 1/4 ♣ : 1/4 ♥ : 1/4 ♦ : 1/4 lea> cards $ '8♣' lea> cards $_() ('K♣', '4♠', '7♥', 'T♥', 'A♥', '6♣', '6♦', '9♠', '5♣', 'Q♥', 'T♣', 'K♠', '4♥', 'T♦', '8♣', 'A♦', 'J♣', 'A♠', 'J♥', '3♠', '4♦', 'K♦', '8♥', '7♣', '8♦', '6♥', 'T♠', '5♥', '3♥', '9♦', 'J♦', '3♣', '2♥', '9♣', '7♠', 'Q♣', '5♦', '4♣', 'A♣', '9♥', '2♦', '6♠', 'K♥', '2♠', 'Q♦', '5♠', '7♦', 'J♠', 'Q♠', '8♠', '2♣', '3♦') lea> cards $_(13) ('9♠', '4♦', 'K♠', '9♦', '6♦', 'A♦', '3♥', '8♣', 'T♥', '5♦', '7♦', '9♣', 'Q♥') lea> ' '.join(cards $_(13)) '8♦ 7♦ 5♦ K♦ 6♠ K♠ T♥ 2♦ 3♠ 9♣ 7♥ 2♠ T♣' lea> ?(cards$(52000)) 2♠ : 1018/52000 2♣ : 993/52000 2♥ : 1001/52000 2♦ : 974/52000 3♠ : 952/52000 3♣ : 1047/52000 3♥ : 1056/52000 3♦ : 978/52000 4♠ : 1057/52000 4♣ : 995/52000 4♥ : 941/52000 4♦ : 1052/52000 5♠ : 972/52000 5♣ : 971/52000 5♥ : 954/52000 5♦ : 985/52000 6♠ : 1043/52000 6♣ : 979/52000 6♥ : 972/52000 6♦ : 970/52000 7♠ : 996/52000 7♣ : 1002/52000 7♥ : 1052/52000 7♦ : 1031/52000 8♠ : 991/52000 8♣ : 995/52000 8♥ : 1016/52000 8♦ : 1016/52000 9♠ : 990/52000 9♣ : 959/52000 9♥ : 1015/52000 9♦ : 989/52000 A♠ : 1030/52000 A♣ : 1004/52000 A♥ : 993/52000 A♦ : 1019/52000 J♠ : 1019/52000 J♣ : 963/52000 J♥ : 1024/52000 J♦ : 1046/52000 K♠ : 953/52000 K♣ : 984/52000 K♥ : 994/52000 K♦ : 1075/52000 Q♠ : 1042/52000 Q♣ : 967/52000 Q♥ : 935/52000 Q♦ : 977/52000 T♠ : 1029/52000 T♣ : 994/52000 T♥ : 1004/52000 T♦ : 986/52000
Nice dice...
lea> diePic = ?('⚀⚁⚂⚃⚄⚅') lea> diePic ⚀ : 1/6 ⚁ : 1/6 ⚂ : 1/6 ⚃ : 1/6 ⚄ : 1/6 ⚅ : 1/6 lea> ?[2]diePic ⚀⚀ : 1/36 ⚀⚁ : 1/36 ⚀⚂ : 1/36 ⚀⚃ : 1/36 ⚀⚄ : 1/36 ⚀⚅ : 1/36 ⚁⚀ : 1/36 ⚁⚁ : 1/36 ⚁⚂ : 1/36 ⚁⚃ : 1/36 ⚁⚄ : 1/36 ⚁⚅ : 1/36 ⚂⚀ : 1/36 ⚂⚁ : 1/36 ⚂⚂ : 1/36 ⚂⚃ : 1/36 ⚂⚄ : 1/36 ⚂⚅ : 1/36 ⚃⚀ : 1/36 ⚃⚁ : 1/36 ⚃⚂ : 1/36 ⚃⚃ : 1/36 ⚃⚄ : 1/36 ⚃⚅ : 1/36 ⚄⚀ : 1/36 ⚄⚁ : 1/36 ⚄⚂ : 1/36 ⚄⚃ : 1/36 ⚄⚄ : 1/36 ⚄⚅ : 1/36 ⚅⚀ : 1/36 ⚅⚁ : 1/36 ⚅⚂ : 1/36 ⚅⚃ : 1/36 ⚅⚄ : 1/36 ⚅⚅ : 1/36 lea> ''.join(diePic?(60)) '⚄⚃⚃⚅⚁⚂⚁⚁⚂⚅⚀⚃⚁⚂⚄⚀⚀⚃⚃⚁⚃⚀⚂⚃⚄⚁⚅⚄⚂⚄⚀⚄⚃⚀⚃⚂⚂⚀⚁⚀⚃⚃⚅⚄⚂⚅⚃⚅⚅⚀⚁⚅⚂⚁⚄⚁⚄⚃⚀⚂'
Bit counter
variant 1 : from integer to string
lea> flip1 = ?(0,1) lea> flip2 = ?flip1 lea> flip1 + flip2 0 : 1/4 1 : 2/4 2 : 1/4 lea> 'flip1 = ' + ?str(flip1) + ', flip2 = ' + ?str(flip2) + ' => flip1+flip2 = ' + ?str(flip1+flip2) flip1 = 0, flip2 = 0 => flip1+flip2 = 0 : 1/4 flip1 = 0, flip2 = 1 => flip1+flip2 = 1 : 1/4 flip1 = 1, flip2 = 0 => flip1+flip2 = 1 : 1/4 flip1 = 1, flip2 = 1 => flip1+flip2 = 2 : 1/4
variant 2 : from string to integer
lea> c = ?('01') lea> c4 = ?[4]c lea> c4 0000 : 1/16 0001 : 1/16 0010 : 1/16 0011 : 1/16 0100 : 1/16 0101 : 1/16 0110 : 1/16 0111 : 1/16 1000 : 1/16 1001 : 1/16 1010 : 1/16 1011 : 1/16 1100 : 1/16 1101 : 1/16 1110 : 1/16 1111 : 1/16 lea> f = lambda s: sum(int(d) for d in s) lea> count = ?f(c4) lea> count 0 : 1/16 1 : 4/16 2 : 6/16 3 : 4/16 4 : 1/16 lea> ?*(c4,count) ('0000', 0) : 1/16 ('0001', 1) : 1/16 ('0010', 1) : 1/16 ('0011', 2) : 1/16 ('0100', 1) : 1/16 ('0101', 2) : 1/16 ('0110', 2) : 1/16 ('0111', 3) : 1/16 ('1000', 1) : 1/16 ('1001', 2) : 1/16 ('1010', 2) : 1/16 ('1011', 3) : 1/16 ('1100', 2) : 1/16 ('1101', 3) : 1/16 ('1110', 3) : 1/16 ('1111', 4) : 1/16 lea> c4 + ' -> ' + ?str(count) 0000 -> 0 : 1/16 0001 -> 1 : 1/16 0010 -> 1 : 1/16 0011 -> 2 : 1/16 0100 -> 1 : 1/16 0101 -> 2 : 1/16 0110 -> 2 : 1/16 0111 -> 3 : 1/16 1000 -> 1 : 1/16 1001 -> 2 : 1/16 1010 -> 2 : 1/16 1011 -> 3 : 1/16 1100 -> 2 : 1/16 1101 -> 3 : 1/16 1110 -> 3 : 1/16 1111 -> 4 : 1/16
Binary choices
lea> sendEMailToDREarlyNovember = ?:(99.9%) lea> :% sendEMailToDREarlyNovember False : 0.1 % True : 99.9 % lea> 'I will ' + ?{'':99.9% ,'not ':0.1%} + 'send an e-mail to D. R. early November.' I will not send an e-mail to D. R. early November. : 1/1000 I will send an e-mail to D. R. early November. : 999/1000
Updated