Random numbers are used to simulate uncertain events Some problems in science and technology are desrcribed by INF1100 Lectures, Chapter 8: ”exact” mathematics, leading to ”precise” results Random Numbers and Simple Games Examples: throwing a ball, an oscillating system Some problems appear physically uncertain Hans Petter Langtangen Examples: rolling a die, molecular motion Can we roll a die on a computer? Simula Research Laboratory Yes, by using random numbers to mimic the uncertainty of University of Oslo, Dept. of Informatics the experiment October 30, 2011 Random numbers make it possible to simulate physical systems with uncertainty, in input data or the process Random numbers are essential for programming games Drawing random numbers Distribution of random numbers Python has a random module for drawing random numbers random.random() draws random numbers in [0 , 1): random.random() generates random numbers that are uniformly >>> import random distributed in the interval [0 , 1) >>> random.random() random.uniform(a, b) generates random numbers uniformly 0.81550546885338104 >>> random.random() distributed in [ a , b ) 0.44913326809029852 >>> random.random() ”Uniformly distributed” means that if we generate a large set 0.88320653116367454 of numbers, no part of [ a , b ) gets more numbers than others The sequence of random numbers is produced by a deterministic algorithm – the numbers just appear random Distribution of random numbers visualized A histogram is used to find and visualize a distribution Histogram: divide [0 , 1) into n small subintervals, generate N N = 500 # no of samples numbers, count how many numbers that fall in each subinterval x = range(N) y = [random.uniform(-1,1) for i in x] (and divide the counts by N ) – plot the count variation and see if from scitools.std import plot the curve is flat plot(x, y, ’+’, axis=[0,N-1,-1.2,1.2]) from scitools.std import compute_histogram, plot 1 import random N = 100000 numbers = [random.random() for i in range(N)] x, y = compute_histogram(samples, nbins=20) 0.5 plot(x, y) 1000000 samples of uniform numbers on (0,1) 1.2 0 1 0.8 -0.5 0.6 0.4 -1 0.2 0 50 100 150 200 250 300 350 400 450 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
Vectorized drawing of random numbers Drawing integers random.random() generates one number at a time numpy has a random module that efficiently generates a (large) Quite often we want to draw an integer from [ a , b ] and not a number of random numbers at a time: real number from numpy import random r = random.random() # one no between 0 and 1 Python’s random module and numpy.random have functions for r = random.random(size=10000) # array with 10000 numbers drawing uniformly distributed integers: r = random.uniform(-1, 10) # one no between -1 and 10 r = random.uniform(-1, 10, size=10000) # array import random r = random.randint(a, b) # a, a+1, ..., b Vectorized drawing is important for speeding up programs! import numpy as np Possible problem: two random modules, one Python ”built-in” r = np.random.randint(a, b+1, N) # b+1 is not included and one in numpy r = np.random.random_integers(a, b, N) # b is included Suggestion: use random (Python) and numpy.random : random.uniform(-1, 1) # scalar number numpy.random.uniform(-1, 1, 100000) # vectorized Example: throwing a die Example: throwing a die; vectorized version Any no of eyes, 1-6, is equally probable when you throw a die import sys, numpy as np What is the chance of getting a 6? N = int(sys.argv[1]) We make a program that simulates the process: eyes = np.random.randint(1, 7, N) success = eyes == 6 # True/False array import random six = np.sum(success) # treats True as 1, False as 0 N = 10000 print ’Got six %d times out of %d’ % (six, N) eyes = [random.randint(1, 6) for i in range(N)] six = 0 # counter for how many times we get 6 eyes for outcome in eyes: Important: use sum from numpy and not Python’s built-in sum if outcome == 6: six += 1 function! (The latter is slow, often making a vectorized version print ’Got six %d times out of %d’ % (six, N) slower than the scalar version.) Probability: six / N (exact: 1 / 6) This is called Monte Carlo simulation Fixing the seed fixes the random sequence Computing statistics: mean and standard deviation Debugging programs with random numbers is difficult because To describe a set of random numbers x i we are often the numbers produced vary each time we run the program interested in two things: For debugging it is important that a new run reproduces the the mean value sequence of random numbers in the last run n − 1 x m = 1 � x j This is possible by fixing the seed of the random module n j =0 random.seed(121) # int argument the ”mean deviation” from the mean value (standard The value of the seed determines the random sequence: deviation) >>> import random � >>> random.seed(2) n − 1 � 1 � � � >>> [’%.2f’ % random.random() for i in range(7)] x s = ( x j − x m ) 2 n [’0.96’, ’0.95’, ’0.06’, ’0.08’, ’0.84’, ’0.74’, ’0.67’] j =0 >>> [’%.2f’ % random.random() for i in range(7)] [’0.31’, ’0.61’, ’0.61’, ’0.58’, ’0.16’, ’0.43’, ’0.39’] numpy has functions for computing this: # x is an array of numbers >>> random.seed(2) # repeat the random sequence xm = mean(x) >>> [’%.2f’ % random.random() for i in range(7)] xs = std(x) [’0.96’, ’0.95’, ’0.06’, ’0.08’, ’0.84’, ’0.74’, ’0.67’] By default, the seed is based on the current time
Clustered random numbers Histogram of Gaussian/normal numbers Sometimes we want uniformly distributed random numbers, 1000000 samples of Gaussian/normal numbers on (0,1) 0.4 and sometimes not 0.35 Example: it is more likely have normal (mean) blood pressure than large deviations from the mean 0.3 We can use the Gaussian or normal distribution to get random 0.25 numbers clustered around a mean value: 0.2 import random r = random.normalvariate(m, s) 0.15 m : mean value, s : standard deviation 0.1 Vectorized drawing of N Gaussian/normal numbers: 0.05 import numpy as np samples = np.random.normal(m, s, N) 0 -5 -4 -3 -2 -1 0 1 2 3 4 5 This chapter: mostly uniformly distributed numbers Drawing random elements from a list Example: drawing cards from a deck (part 1) Make a deck of cards: # A: ace, J: jack, Q: queen, K: king There are different methods for picking an element from a list # C: clubs, D: diamonds, H: hearts, S: spades at random, but the main method applies choice(list) : def make_deck(): >>> awards = [’car’, ’computer’, ’ball’, ’pen’] ranks = [’A’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, >>> import random ’8’, ’9’, ’10’, ’J’, ’Q’, ’K’] >>> random.choice(awards) suits = [’C’, ’D’, ’H’, ’S’] ’car’ deck = [] for s in suits: Alternatively, we can compute a random index: for r in ranks: >>> index = random.randint(0, len(awards)-1) deck.append(s + r) >>> awards[index] random.shuffle(deck) ’pen’ return deck We can also shuffle the list randomly, and then pick any deck = make_deck() element: Draw a card at random: >>> random.shuffle(awards) >>> awards[0] deck = make_deck() ’computer’ card = deck[0] del deck[0] card = deck.pop(0) # return and remove element with index 0 Example: drawing cards from a deck (part 2) Example: drawing cards from a deck (part 3) Deal hands for a set of players: def deal(cards_per_hand, no_of_players): Draw a hand of n cards: deck = make_deck() hands = [] def deal_hand(n, deck): for i in range(no_of_players): hand = [deck[i] for i in range(n)] hand, deck = deal_hand(cards_per_hand, deck) del deck[:n] hands.append(hand) return hand, deck return hands deck is returned since the function changes the list players = deal(5, 4) ( deck is changed in-place so the change affects the deck object import pprint; pprint.pprint(players) in the calling code anyway, but returning changed arguments Resulting output: is a Python convention and good habit) [[’D4’, ’CQ’, ’H10’, ’DK’, ’CK’], [’D7’, ’D6’, ’SJ’, ’S4’, ’C5’], [’C3’, ’DQ’, ’S3’, ’C9’, ’DJ’], [’H6’, ’H9’, ’C6’, ’D5’, ’S6’]]
Recommend
More recommend