- [Instructor] In this video, we're going to talk
about simulation techniques with random number generation.
As you work in data science and you start working
in data in general, often one of the things that you want
to do is simulate data and random number generation
can be really handy for that
and it can also be handy for game playing as well.
For demonstration purposes here, we're going to simulate
rolling a six-sided die to get started.
And part of what we're going to want to talk
about is a concept called reproducibility.
Basically, how is it that we can ensure
that somebody executing our code
is going to be able to get the same results that we got.
Let's go ahead and introduce random number generation.
In order to do that, we're going to import
a module called random.
The random module as you might guess
provides capabilities for random number generation.
In order to use it, we need to import it first.
This is similar to what we did earlier
with the decimal module and the statistics module.
In this case, rather than importing a specific function
from the random module, we simply import the module itself
and the reason we chose that path is we're going to use
a couple of different functions from that module.
Let's go ahead now and try rolling a die a few times here.
We're going to use a for loop to do that
and we're going to say that we want to loop 10 times.
We've done a number of for loops like this earlier
and for each iteration of loop, we're going to print out
a randomly generated integer so we're going to use
the random modules randrange function to do that.
You might be able to guess that randrange
is kind of like range.
It produces a range of values,
but in the case of random number generation,
it produces one value in that range.
If I say one and seven, what I'm going to get back
every time I call randrange with these two arguments
is a number in the range one through six.
That is starting from one, up to but not including seven,
and that's going to be an integer value that's returned.
Let's go ahead and display these on one line
like we've done a number of times.
You can see here that we get a certain set of values.
Not all of the values in the range were produced.
I got a couple of sixes, a few fives,
a few ones, and a three.
Looks like I'm missing all the twos and fours at this point,
but if I recall that snippet and execute it again,
I'm going to get different results.
This time we have a two and a four,
actually we have several twos,
and we got a little bit better distribution of values
the second time we executed that statement.
Each time I execute that loop, it's going to give me
a new set of values.
However, there is a capability for forcing the random
number generator to give me the same sequence of values
every single time,
which would be important for reproducibility,
and again, that is a key concept as you start working
with data and you're doing studies and you want
other people to be able to reproduce your results.
There are a number of cases throughout later lessons
where you're going to need to seed a random number generator
to ensure that you get the same sequence of values each time
and we'll talk more about that momentarily.
In this video, one of the things I want to do is show
you the script,
fig04_01.py
which is going to take what we did here
with random number generation
and we're going to roll a die six million times.
Now, if we roll a die six million times
and it's a well balanced die, we should get approximately
one million of each face.
Similarly, if it's a good random number generator,
we should get approximately one million
of each face as well.
Previously, when we've executed scripts
we did that from the command line
not in IPython interactive mode, but it turns out you can
run scripts from interactive mode as well by using
the run command.
Let's go ahead and take a look at that.
If I execute the first of these scripts here,
which is the key one for this example.
You can see that it's hanging a little bit.
It's actually calculating six million rolls at the moment.
In a few moments, there we go, it'll display the results,
so you see the six different faces
and you see that each one of those faces
occurred approximately one million times.
Let's run it again.
In a moment, the results will be displayed.
You may notice if you're coming from another programming
language that because Python is interpreted,
it may not execute certain things as quickly
as complied languages do.
But it did still come back relatively quickly
and though we got different results this time,
it is random, we got still approximately
one million of each face.
That demonstrates how to run a script
in the context of IPython.
Let's switch over to the script code for a moment here.
For this example, since we haven't gone in-depth
into somethings like lists yet, where we could potentially
use a list to keep track of each die face.
What we're going to do in this example is define
six separate variables that represent the six different
faces of the die and we'll keep track of how many times
we roll each face by using an if elif else statement
nested in a for loop.
Here we have a for loop that's going to iterate
six million times.
Notice the use of underscore in a numeric literal here.
This can be used to improve the readability
of your literal values.
It appears that my editor is not understanding
the fact that this is actually the number six million,
so let me just show you that if I remove those for a moment,
now it's colored all the digits correctly, in that case.
That's a bug in this particular editor.
But in any case, we're going to iterate six million times
and each time through we're going to use that
randrange call we just demonstrated to get one face value
then we're going to check if the face
is a one, two, three, four, five, or six.
And for whichever one of those cases is true,
we will add one to the appropriate counter.
If you look down below, once we've iterated
six million times we then have some print statements
that are going to produce the table that you saw.
First, we're displaying a formatted string that
has the literal characters for the word face
and then a placeholder in which we display the string
frequency right aligned in a field of 13 characters.
Right justified, right aligned in a field of 13 characters,
which gives us the two column format.
For the subsequent lines, we display the value one,
right aligned in a field of four.
Then the value two, right aligned in a field of four.
For the numbers from one through six,
and for each of the frequencies, we also display those
such that they'll appear right aligned under frequency,
so each of these is also displayed in a right aligned
field of 13 characters.
That's what produced the output that you saw
in my interactive IPython session here.
I did promise you that we would talk a little bit more
about this reproducibility issue.
It turns about that the random module has built
into it the capability of doing
what we call seeding the random number generator.
There is a seed function which when you call
it with the same value,
is going to restart the random number generation
from that particular seed value.
Basically, it's not true random numbers
that you're getting but rather pseudo-random numbers
that are produced by a complex calculation
underneath the hood.
That complex calculation by default starts
with a seed based on the system clock
in most implementations.
But if you seed it with a fixed value, then you can get
the same sequence of values each time.
Let's demonstrate that capability.
Let's call random.seed and we'll give it the value 32.
Let's recall the for loop that we did up above.
For anything that we do from this point forward
is going to start with the sequence
seeded at the number 32.
If I execute this, I'll get 10 values
and they'll be different from what we had up above
because these started from different seed point.
If I execute the same loop again,
I'm going to get different values
because it's going to continue from wherever we left off
in the preceding randrange call.
So we do in fact get different values here down below,
so you're not seeing the reproducibility yet.
The way you see the reproducibility is by recalling
that snippet that seeds the random number generator.
Now, we're starting over from the same point we started
at back in snippet number six.
And now if I recall that for loop,
you can see that the values produced here are identical
to the values produced back in snippet number seven.
If you want to produce
random data for simulation purposes and you need the ability
for somebody to get the same set of random
values for testing purposes,
you can seed the random number generator
to a specific value, then produce all your random numbers,
then somebody else coming along
and running your same code with the same seed
should get the exact same results.