What’s New or Different

Differences from NumPy 1.17+

Deprecated

Generator is deprecated. You should be using numpy.random.Generator.

  • randomgen’s Generator continues to expose legacy methods random_sample() , randint() , random_integers() , rand() , randn() , and tomaxint(). Note: These should not be used, and their modern replacements are preferred:

  • randomgen’s bit generators remain seedable and the convenience function seed() is exposed as part of Generator. Additionally, the convenience property state() is available to get or set the state of the underlying bit generator.

  • numpy.random.Generator.multivariate_hypergeometric() was added after Generator was merged into NumPy and will not be ported over.

  • numpy.random.Generator.shuffle() and numpy.random.Generator.permutation() support axis keyword to operator along an axis other than 0.

  • integers() supports the keyword argument use_masked to switch between masked generation of bounded integers and Lemire’s superior method.

Differences from NumPy before 1.17

In [1]: from randomgen import Generator, Xoroshiro128

In [2]: import numpy.random

In [3]: rg = Generator(Xoroshiro128(mode="sequence"))

In [4]: %timeit rg.standard_normal(100000)
   ...: %timeit numpy.random.standard_normal(100000)
   ...: 
890 us +- 18.4 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
2.66 ms +- 94.6 us per loop (mean +- std. dev. of 7 runs, 100 loops each)
In [5]: %timeit rg.standard_exponential(100000)
   ...: %timeit numpy.random.standard_exponential(100000)
   ...: 
443 us +- 13.1 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
2.01 ms +- 35.7 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
In [6]: %timeit rg.standard_gamma(3.0, 100000)
   ...: %timeit numpy.random.standard_gamma(3.0, 100000)
   ...: 
2.67 ms +- 115 us per loop (mean +- std. dev. of 7 runs, 100 loops each)
5.36 ms +- 184 us per loop (mean +- std. dev. of 7 runs, 100 loops each)
  • The Box-Muller used to produce NumPy’s normals is no longer available.

  • All bit generators functions to produce doubles, uint64s and uint32s via CTypes (ctypes()) and CFFI (cffi()). This allows the bit generators to be used in numba or in other low-level applications

  • The bit generators can be used in downstream projects via Cython.

  • Optional dtype argument that accepts np.float32 or np.float64 to produce either single or double prevision uniform random variables for select core distributions

In [7]: rg.seed(0)
Out[7]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [8]: rg.random(3, dtype='d')
Out[8]: array([0.52785087, 0.70822489, 0.66049255])

In [9]: rg.seed(0)
Out[9]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [10]: rg.random(3, dtype='f')
Out[10]: array([0.8648406 , 0.52785087, 0.9834049 ], dtype=float32)
  • Optional out argument that allows existing arrays to be filled for select core distributions

    This allows multithreading to fill large arrays in chunks using suitable PRNGs in parallel.

In [11]: existing = np.zeros(4)

In [12]: rg.random(out=existing[:2])
Out[12]: array([0.66049255, 0.07582601])

In [13]: print(existing)
[0.66049255 0.07582601 0.         0.        ]
  • integers() supports broadcasting inputs.

  • integers() supports drawing from open (default, [low, high)) or closed ([low, high]) intervals using the keyword argument endpoint. Closed intervals are simpler to use when the distribution may include the maximum value of a given integer type.

In [14]: rg.seed(1234)
Out[14]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [15]: rg.integers(0, np.iinfo(np.int64).max+1)
Out[15]: 26097719062389013

In [16]: rg.seed(1234)
Out[16]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [17]: rg.integers(0, np.iinfo(np.int64).max, endpoint=True)
Out[17]: 26097719062389013
  • The closed interval is particularly helpful when using arrays since it avoids object-dtype arrays when sampling from the full range.

In [18]: rg.seed(1234)
Out[18]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [19]: lower = np.zeros((2, 1), dtype=np.uint64)

In [20]: upper = np.array([10, np.iinfo(np.uint64).max+1], dtype=object)

In [21]: upper
Out[21]: array([10, 18446744073709551616], dtype=object)

In [22]: rg.integers(lower, upper, dtype=np.uint64)
Out[22]: 
array([[                  5, 4570805141130348385],
       [                  2, 4398458246985300510]], dtype=uint64)

In [23]: rg.seed(1234)
Out[23]: <randomgen.generator.Generator(Xoroshiro128) object at 0x7fb4a5603220>

In [24]: upper = np.array([10, np.iinfo(np.uint64).max], dtype=np.uint64)

In [25]: upper
Out[25]: array([                  10, 18446744073709551615], dtype=uint64)

In [26]: rg.integers(lower, upper, endpoint=True, dtype=np.uint64)
Out[26]: 
array([[                  5, 4570805141130348385],
       [                  2, 4398458246985300510]], dtype=uint64)
  • Support for Lemire’s method of generating uniform integers on an arbitrary interval by setting use_masked=True in (integers()).

In [27]: %timeit rg.integers(0, 1535, size=100000, use_masked=False)
   ....: %timeit numpy.random.randint(0, 1535, size=100000)
   ....: 
370 us +- 12.7 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
979 us +- 35.3 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
In [28]: rg.multinomial([10, 100], np.ones(6) / 6.)
Out[28]: 
array([[ 1,  2,  2,  2,  2,  1],
       [18,  9, 23, 20, 16, 14]])
  • choice() is much faster when sampling small amounts from large arrays

In [29]: x = np.arange(1000000)

In [30]: %timeit rg.choice(x, 10)
39.7 us +- 795 ns per loop (mean +- std. dev. of 7 runs, 10000 loops each)
  • choice() supports the axis keyword to work with multidimensional arrays.

In [31]: x = np.reshape(np.arange(20), (2, 10))

In [32]: rg.choice(x, 2, axis=1)
Out[32]: 
array([[ 1,  8],
       [11, 18]])
  • For changes since the previous release, see the Change Log