Posted by Daniel Lyons
Wed, 07 Nov 2007 07:03:00 GMT
About a week ago I volunteered for the synagogue at Casino Night. I was basically a gopher bringing people coffee, moving ice and plasticware from point A to point B. It felt good though, the antithesis of my work.
I did take two breaks, one to play roulette for a few minutes. I like roulette because it’s very raw. There aren’t a lot of arbitrary rules to remember while you’re trying to compute the probability. In my opinion, one of the best bets in the whole casino can be found there, the color bet: red or black. Of course you can see with your eyes that you’re still a sucker; there are two uncolored slots. You know the odds are close to 50% but just not quite. You’re still a fool if you bet on it, and over time you’re probably going to go broke.
While I was playing and thinking about this I was thinking about what the curriculum for being a casino worker is. They have schools for this stuff; surely they have curricula. I supposed it would include all the rules, plus a bunch of social things like how to suppress your “tells,” how to encourage someone to keep betting, how to be cute or handsome and perhaps even politeness. The dealer (name another industry with this profession, quick) was certainly cute and polite. I lost a couple chips and she said “better luck next time.” I was betting on red, like any wannabe mathematician.
I wonder if they teach any probability? I wonder if they talk about luck. It seems to me if I wanted to hire a bunch of casino workers, I’d like them to know as little about probability as possible. If they know probability, they might admit something they shouldn’t, like discourage a sucker bet. Or they might not be able to pretend to be “fun” if that’s something they’re supposed to do. Do they teach how to spot, say, card counting? If they do, how can they avoid probability? Or is the whole luck thing a charade, false affect to induce irrational behavior by luring customers into safe-feeling but false frames of mind? Or do they even think this far into the game?
My friends think my bets are weird. I like to arrange negative bets, bets against myself, so that if something bad happens, someone will pay me. I recently made a bet that someone on Craigslist wouldn’t write me back after seeing my picture. The wager was that, if she wrote me, I would pay these friends $20; if she did not, they would pay me $1. So I’ve got $2 coming in and the assurance that I’m really good at making predictions. If I had lost, then I would have paid $40 out but presumably had the pleasure of going on a date. I don’t see what’s so hard to understand about using small wagers like these to smooth over the bumps in life. (Normally it would have been a meal for a meal kind of bet, but this was the only way to get Jenny to make a bet with me since she’s broke. Sucker bet!)
I could have wagered $100 against $5 and that probably would have been just as safe. At any rate, I lack the devotion to gambling to learn the correct terminology for these kinds of bets.
Tags gambling, probability, roulette | 3 comments
Posted by Daniel Lyons
Thu, 22 Feb 2007 09:04:00 GMT
I’m reading a cool book called Understanding Probability. Pretty early on in chapter 2 there is a chart that looks something like this:
| n |
Kn – np |
fn |
| 10 |
1.0 |
0.6000 |
| 25 |
1.5 |
0.5600 |
| 50 |
2.0 |
0.5400 |
and so forth. In this case, the experiment is flipping a coin, n is the number of repetitions of the experiment, Kn is the number of times we get heads, p is the probability of getting heads (0.5), and fn is the relative frequency of getting heads. Obviously, this chart represents one particular set of trials. The author encouraged writing code so I busted out some OCaml on paper in the car, and implemented it from the hotel room a few hours ago.
type face = H | T
That’s just the coin type.
module ProbabilityLab =
struct
let run_experiment experiment times =
Array.init times (fun i -> experiment ())
Here I’m just applying some function over and over again with no parameter to run the experiment, and using that to fill in an array. The experiment gets invoked once for each time we want to do a trial. An array comes out. Simple.
let count_value value result =
float_of_int (Array.fold_right
(fun x y -> y + if x = value then 1 else 0)
result
0)
let count_total result =
float_of_int (Array.length result)
let relative_frequency value result =
count_value value result /. count_total result
These are some utility routines. count_value just counts up the number of times a particular value occurs in an array. count_total gives the length of the array. relative_frequency computes fn for a particular value. Notice that each of these takes the result array as the last parameter and returns a float.
let expected_actual_difference probability value result =
let actual = count_value value result in
let expected = (probability *. count_total result) in
expected -. actual
expected_actual_difference is for the K
n – fp. We’ll use it to see how many more heads we get than half: if the random number generator was completely unrandom and produced heads and then tails always, then this number would fluctuate between zero and either one or negative one.
let collect_summaries summaries result =
List.map (fun f -> f result) summaries
end;;
The last thing in my ProbabilityLab module in a function which takes a list of functions and applies each of them to the result in turn. It’s the opposite of the way you normally map; instead of one function of a simple parameter being invoked across a list, we’re going to invoke each function in the list across the same complex piece of data. This will simplify the table production later.
A simple coin flipping module:
module Coin =
struct
let flip () = match Random.int 2 with
| 0 -> H
| _ -> T
let flip_unfair () = match Random.int 6 with
| 0 -> H
| _ -> T
end;;
As you can see, it just implements two functions: flip and flip_unfair, which represent an unweighted coin and a coin that leans heavily towards tails, only getting heads about 1/6th of the time.
As an example, we can now run a simple experiment such as:
# ProbabilityLab.run_experiment Coin.flip 10;;
- : face array = [|H; T; H; H; H; T; H; T; T; T|]
That’s the experiment result we’re going to have to work with.
let coin_flip_experiment coin times =
begin
Random.self_init ();
let result = ProbabilityLab.run_experiment coin times in
ProbabilityLab.collect_summaries [
ProbabilityLab.count_total;
ProbabilityLab.expected_actual_difference 0.5 H;
ProbabilityLab.relative_frequency H]
result
end;;
This function performs a coin flipping experiment. It takes one of the coins as a parameter (meaning, flip or flip_unfair) and a number of times to flip the coin. It creates the result using the run_experiment function in the ProbabilityLab module and then collects three summaries. The first summary is just n. The second is the number of heads we got beyond 50% (the expected amount), kn – np. The third is the computed relative frequency of obtaining heads with this experiment. Note that they’re all curried function calls that are expecting one more parameter—the result array.
Clearly, coin_flip_experiment does the bulk of the work. But now we need to see what it takes to drive it:
let process () =
let coins = [Coin.flip; Coin.flip_unfair] in
let trials = [ 10; 25; 50; 100; 250; 500;
1000; 2500; 5000; 7500; 10000; 15000;
20000; 25000; 30000] in
List.map (fun coin ->
List.map (fun trial -> coin_flip_experiment coin trial) trials)
coins
;;
Simple. A nested map across the coins and the numbers of trials we want. Here’s the output, unbeautified, for one run on my computer:
# process ();;
- : float list list list =
[[[10.; 0.; 0.5]; [25.; -1.5; 0.56]; [50.; -1.; 0.52]; [100.; -4.; 0.54];
[250.; -2.; 0.508]; [500.; 2.; 0.496]; [1000.; 21.; 0.479];
[2500.; 6.; 0.4976]; [5000.; -20.; 0.504]; [7500.; 30.; 0.496];
[10000.; 23.; 0.4977]; [15000.; 78.; 0.4948]; [20000.; 60.; 0.497];
[25000.; 139.; 0.49444]; [30000.; -53.; 0.501766666666666694]];
[[10.; 4.; 0.1]; [25.; 9.5; 0.12]; [50.; 18.; 0.14]; [100.; 35.; 0.15];
[250.; 88.; 0.148]; [500.; 180.; 0.14]; [1000.; 321.; 0.179];
[2500.; 861.; 0.1556]; [5000.; 1668.; 0.1664];
[7500.; 2516.; 0.164533333333333337]; [10000.; 3268.; 0.1732];
[15000.; 5033.; 0.164466666666666678]; [20000.; 6705.; 0.16475];
[25000.; 8413.; 0.16348]; [30000.; 9916.; 0.169466666666666654]]]
Tags ocaml, probability, programming | 1 comment