Random Choice#

In this section we explore how to make random choices using Python. Additionally, we make use of arrays, and see how appending and summing over Boolean arrays help us to keep track of our results.

To start, suppose we have a list of choices that are equally likely to occur and we want to choose one.

In numpy, the function np.random.choice() will output exactly one item from the input sequence, selecting from it randomly and uniformly - or with equal opportunity.

To illustrate, suppose we toss a coin and want to know the outcome. Since we expect a random output of heads or tails, we create a list titled coin with those options and call the np.random.choice function on coin to give us exactly one result from the list.

But first – we import numpy.

Coin Toss#

import numpy as np

coin = ['heads', 'tails']

flip = np.random.choice(coin)

flip
'heads'

We will see the np.random.choice() function used in various ways throughout this textbook. In this section, we focus on the basic arguments of this function.

The random choice function does not have a fixed output and running it multiple times will eventually produce a different result.

In fact, if we want to run this experiment more than once it might be useful to keep track of the results in an array.

Investigation with Arrays#

We can store information in arrays as seen in Chapter 4.3. Below we create an array that contains our first experiment result – our first flip – and append our next outcome.

flip_array = np.array([flip])

flip_array
array(['heads'], dtype='<U5')

Let’s toss the coin again, choosing randomly from our list of possible outcomes.

flip = np.random.choice(coin)

flip
'tails'

And now let’s add this outcome to our list flip_array, using the append method.

This method takes as input an array and elements to be appended, and returns a new array whose elements are those of the input array extended by the input elements.

np.append(flip_array, flip)
array(['heads', 'tails'], dtype='<U5')

Since elements are added to a copy of the input array, append does not change the input array. For example, flip_array gives us the original array with one coin flip result.

flip_array
array(['heads'], dtype='<U5')

To remedy this, we must use assignment. We can either rename our new list first or assign it a new name entirely.

flip_array = np.append(flip_array,'tails')

flip_array
array(['heads', 'tails'], dtype='<U5')

Appending items to lists and arrays is an important tool when working in Python. However, the random choice function allows an additional argument that corresponds to repeating the experiment, with results returned as an array. In fact we can repeat the coin flip experiment as many times as we want. Here we repeat 7 times:

outcomes = np.random.choice(coin, 7)

outcomes
array(['heads', 'tails', 'heads', 'heads', 'tails', 'heads', 'tails'],
      dtype='<U5')

Boolean Arrays#

Since our experiment is small, we can easily count how many ‘heads’ or ‘tails’ we have. If we have a large experiment it might be tedious, even erroneous, to count by hand. We can instead find all instances where our outcomes array is equal to “heads” and sum over these instances with the help of a Boolean array. A Boolean array is a special array that contains the binary values of True and False or the integers \(1\) and \(0\), respectively. Such arrays are often the result of using comparison operations, but can also be constructed manually. For example, the expression outcomes == 'heads', performs an elementwise comparison of the array outcomes with the string 'heads', and returns an array of binary values reflecting that comparision. That is, each element in outcomes is compared to 'heads' and the truth value of each comparison is returned in an array.

outcomes == 'heads'
array([ True, False,  True,  True, False,  True, False])

With this, we can quickly and easily count the number of “heads” in our outcomes array - by summing over the above Boolean array.

For arithmetic operations, True is treated as 1 and False is treated as 0; and so, the sum of a Boolean array counts all instances of True, and disregards all instances of False, giving exactly the number of “heads” in this example.

sum(outcomes == 'heads')
4

We can do the same with “tails”:

sum(outcomes == 'tails')
3

Since summing over a Boolean array counts all instances of True, another way to count the number of “tails” is with the expression outcomes != 'heads', and summing over this instead.

Here the Boolean array we create contains instances of True wherever our coin flip landed on “tails”, and False when “heads” was the result of our flip.

outcomes != 'heads'
array([False,  True, False, False,  True, False,  True])

Summing over this array also counts the number of tails!

sum(outcomes != 'heads')
3

Thus we have these methods of utilizing ways to store data - lists, arrays, etc - to then organize, track, mimic, and count repeated experiments.

The next sections delve deeper into foundational programming techniques that provide more tools on how we can manipulate our data.