# Mathematical Modules in Python: Random

This post is part of a series called Mathematical Modules in Python.
Mathematical Modules in Python: Math and Cmath
Mathematical Modules in Python: Decimal and Fractions

Randomness is all around us. When you flip a coin or roll a die, you can never be sure of the outcome. This unpredictability has a lot of applications, like determining the winners of a lucky draw or generating test cases for an experiment with random values produced based on an algorithm.

Keeping this usefulness in mind, Python has provided us with the random module. You can use it in games to spawn enemies randomly or to shuffle the elements in a list.

 Types of Functions Example Functions Initialize and use the random number generator seed(), random() Random integers in a range randrange(), randint() Random items from a sequence choice(), shuffle(), sample() Random floats with standard distributions triangular(), uniform(), normalvariate() Random items from a weighted list choice(), choices(), sample()

## How Does Random Work?

Nearly all of the functions in this module depend on the basic random() function, which will generate a random float greater than or equal to zero and less than one. Python uses the Mersenne Twister to generate the floats. It produces 53-bit precision floats with a period of 219937-1. It is actually the most widely used general-purpose pseudo-random number generator.

#### Initialize the Random Number Generator With seed()

Sometimes, you want the random number generator to reproduce the sequence of numbers it created the first time. This can be achieved by providing the same seed value both times to the generator using the seed(s, version) function. If the s parameter is omitted, the generator will use the current system time to generate the numbers. Here is an example:

Keep in mind that unlike a coin flip, the module generates pseudo-random numbers which are completely deterministic, so it is not suitable for cryptographic purposes.

## Generating Random Integers

#### Generate Integers in a Range With randrange() and randint()

The module has two different functions for generating random integers. You can use randrange(a) to generate a random whole number smaller than a

Similarly, you can use randrange(a, b[,step]) to generate a random number from range(a, b, step). For example, using random.randrange(0, 100, 3) will only return those numbers between 0 and 100 which are also divisible by 3.

If you know both the lower and upper limits between which you want to generate the numbers, you can use a simpler and more intuitive function called randint(a, b). It is simply an alias for randrange(a, b+1).

## Functions for Sequences

#### Chose a Random Element From a List With choice()

To select a random element from a given non-empty sequence, you can use the choice(seq) function. With randint(), you are limited to a selection of numbers from a given range. The choice(seq) function allows you to choose a number from any sequence you want.

Another good thing about this function is that it is not limited to just numbers. It can select any type of element randomly from a sequence. For example, the name of the winner of a lucky draw among five different people, provided as a string, can be determined using this function easily.

#### Shuffle a Sequence With shuffle()

If you want to shuffle a sequence instead of selecting a random element from it, you can use the shuffle(seq) function. This will result in an in place shuffling of the sequence. For a sequence with just 10 elements, there can be a total of 10! = 3,628,800 different arrangements. With a larger sequence, the number of possible permutations will be even higher—this implies that the function can never generate all the permutations of a large sequence.

#### Sample Multiple Times With sample()

Let's say you have to pick 50 students from a group of 100 students to go on a trip.

At this point, you may be tempted to use the choice(seq) function. The problem is that you will have to call it about 50 times in the best case scenario where it does not choose the same student again.

A better solution is to use the sample(seq, k) function. It will return a list of k unique elements from the given sequence. The original sequence is left unchanged. The elements in the resulting list will be in selection order. If k is greater than the number of elements in the sequence itself, a ValueError will be raised.

As you can see, shuffle(seq) modified the original list, but sample(seq, k) kept it intact.

## Generating Random Floats With Standard Distributions

In this section, you will learn about functions that can be used to generate random numbers based on specific real-value distributions. The parameters of most of these functions are named after the corresponding variable in that distribution's actual equation.

When you just want a number between 0 and 1, you can use the random() function. If you want the number to be in a specific range, you can use the uniform(a, b) function with a and b as the lower and higher limits respectively.

#### Generating Random Floats With Probability Distributions

Let's say you need to generate a random number between low and high such that it has a higher probability of lying in the vicinity of another number mode. You can do this with the triangular(low, high, mode) function. The low and high values will be 0 and 1 by default. Similarly, the mode value defaults to the mid-point of the low and high values, resulting in a symmetrical distribution.

There are a lot of other functions as well to generate random numbers based on different distributions. As an example, you can use normalvariate(mu, sigma) to generate a random number based on a normal distribution, with mu as the mean and sigma as the standard deviation.

## Random Items With Weighted Probabilities

As we just saw, it is possible to generate random numbers with a uniform distribution as well as a triangular or normal distribution. Even in a finite range like 0 to 100, an infinite number of floats can be generated. What if there is a finite set of elements and you want to add more weight to some specific values while selecting a random number? This situation is common in lottery systems where numbers with little reward are given a high weighting.

#### Choosing From a Weighted List With choice(seq)

If it is acceptable for your application to have weights that are integer values, you can create a list of elements whose frequency depends on their weight. You can then use the choice(seq) function to select an element from this weighted list randomly. Here is an example showing the selection of a prize amount randomly.

In my case, it took ten trials to get a $2 prize chosen from the list. The chances of getting a$100 prize would be much lower.

#### Choosing From a Weighted List With random.choices()

Python also has a function called random.choices(population, weights=None, *, cum_weights=None, k=1) that allows you to natively pick values from a weighted distribution instead of implementing something similar on our own, as we just did. It accepts four arguments, but only the first one is required. Just passing a single list of values to the function will give you back one item from the list.

As you can see below, our weighted probability code could easily be rewritten to get a list of values using the random.choices() function.

Values are selected with equal probability if you don't provide weightings. The choices() function will repeat some of the returned values in the final selected sample. You should note that this is different from the sample() function we discussed earlier, which returns a list of unique values from the given length. Passing a value of k higher than the population length will result in a ValueError with sample() but works with choices(). Here is an example:

The choices() function is useful for simulating things like a coin toss or a dice throw because there is a possibility of repetition. On the other hand, sample() is useful for things like picking people randomly for different teams as the same person cannot be picked for two teams.

The sample() function was updated in version 3.9 to accept an additional counts parameter, which is simply a list that specifies how many times specific values are repeated in a population. You can use this parameter to simulate weighted distribution.

This is useful in situations where you have to pick something randomly (e.g. fruits from a basket) and then distribute them. Using sample() means that there is no possibility of selecting more bananas than the total amount present in the basket. The counts parameter allows us to avoid creating an actual list of 50 apples, 100 guavas, etc.

Keeping all these subtle differences between the functions in mind will help you write code that doesn't show unexpected behavior.

## Final Thoughts

This module can be useful in a lot of situations, like shuffling the questions in an assignment or generating random usernames or passwords for your users by using the shuffle() function. You can also generate random numbers uniformly, as well as giving weighting to numbers in a specific range. In our next tutorial, we will be using the functions from this module to generate random data for statistical analysis.

Do you have some interesting applications of random number generators in mind that can be useful to fellow readers? Let us know on the forum.