Random sampling (
Numpy’s random number routines produce pseudo random numbers using
combinations of a
BitGenerator to create sequences and a
to use those sequences to sample from different statistical distributions:
BitGenerators: Objects that generate random numbers. These are typically unsigned integer words filled with sequences of either 32 or 64 random bits.
Generators: Objects that transform sequences of random bits from a BitGenerator into sequences of numbers that follow a specific probability distribution (such as uniform, Normal or Binomial) within a specified interval.
Since Numpy version 1.17.0 the Generator can be initialized with a
number of different BitGenerators. It exposes many different probability
distributions. See NEP 19 for context on the updated random Numpy number
routines. The legacy
RandomState random number routines are still
available, but limited to a single BitGenerator. See What’s New or Different
for a complete list of improvements and differences from the legacy
default_rng to get a new instance of a
Generator, then call its
methods to obtain samples from different distributions. By default,
Generator uses bits provided by
PCG64 which has better statistical
properties than the legacy
MT19937 used in
# Do this (new version) from numpy.random import default_rng rng = default_rng() vals = rng.standard_normal(10) more_vals = rng.standard_normal(10) # instead of this (legacy version) from numpy import random vals = random.standard_normal(10) more_vals = random.standard_normal(10)
Generator can be used as a replacement for
RandomState. Both class
instances hold an internal
BitGenerator instance to provide the bit
stream, it is accessible as
gen.bit_generator. Some long-overdue API
cleanup means that legacy and compatibility methods have been removed from
See What’s New or Different for more information.
Something like the following code can be used to support both
Generator, with the understanding that the interfaces are slightly
try: rng_integers = rng.integers except AttributeError: rng_integers = rng.randint a = rng_integers(1000)
Seeds can be passed to any of the BitGenerators. The provided value is mixed
SeedSequence to spread a possible sequence of seeds across a wider
range of initialization states for the BitGenerator. Here
PCG64 is used and
is wrapped with a
from numpy.random import Generator, PCG64 rng = Generator(PCG64(12345)) rng.standard_normal()
>>> import numpy as np >>> rng = np.random.default_rng(12345) >>> print(rng) Generator(PCG64) >>> rfloat = rng.random() >>> rfloat 0.22733602246716966 >>> type(rfloat) <class 'float'>
>>> import numpy as np >>> rng = np.random.default_rng(12345) >>> rints = rng.integers(low=0, high=10, size=3) >>> rints array([6, 2, 7]) >>> type(rints) <class 'numpy.int64'>
The new infrastructure takes a different approach to producing random numbers
RandomState object. Random number generation is separated into
two components, a bit generator and a random generator.
BitGenerator has a limited set of responsibilities. It manages state
and provides functions to produce random doubles and random unsigned 32- and
random generator takes the
bit generator-provided stream and transforms them into more useful
distributions, e.g., simulated normal random values. This structure allows
alternative bit generators to be used with little code duplication.
Generator is the user-facing object that is nearly identical to the
RandomState. It accepts a bit generator instance as an argument.
The default is currently
PCG64 but this may change in future versions.
As a convenience NumPy provides the
default_rng function to hide these
>>> from numpy.random import default_rng >>> rng = default_rng(12345) >>> print(rng) Generator(PCG64) >>> print(rng.random()) 0.22733602246716966
>>> from numpy.random import Generator, PCG64 >>> rng = Generator(PCG64(12345)) >>> print(rng) Generator(PCG64)
>>> from numpy.random import Generator, MT19937 >>> rng = Generator(MT19937(12345)) >>> print(rng) Generator(MT19937)
What’s New or Different#
The Box-Muller method used to produce NumPy’s normals is no longer available
Generator. It is not possible to reproduce the exact random
values using Generator for the normal distribution or any other
distribution that relies on the normal such as the
RandomState.standard_t. If you require bitwise backward compatible
The Generator’s normal, exponential and gamma functions use 256-step Ziggurat methods which are 2-10 times faster than NumPy’s Box-Muller or inverse CDF implementations.
dtypeargument that accepts
np.float64to produce either single or double precision uniform random variables for select distributions
outargument that allows existing arrays to be filled for select distributions
The bit generators can be used in downstream projects via Cython.
Generator.integersis now the canonical way to generate integer random numbers from a discrete uniform distribution. The
randnmethods are only available through the legacy
endpointkeyword can be used to specify open or closed intervals. This replaces both
randintand the deprecated
Generator.randomis now the canonical way to generate floating-point random numbers, which replaces
RandomState.random_sample, RandomState.sample, and RandomState.ranf. This is consistent with Python’s
All BitGenerators in numpy use
SeedSequenceto convert seeds into initialized states.
See What’s New or Different for a complete list of improvements and
differences from the traditional
The included generators can be used in parallel, distributed applications in a number of ways:
Users with a very large amount of parallelism will want to consult Upgrading PCG64 with PCG64DXSM.
- Parallel Applications
- Multithreaded Generation
- What’s New or Different
- Comparing Performance
- C API for random
- Examples of using Numba, Cython, CFFI
Original Source of the Generator and BitGenerators#
This package was developed independently of NumPy and was integrated in version 1.17.0. The original repo is at https://github.com/bashtage/randomgen.