Skip to main content
v2026.11,858 entries · CC-BY 4.0

numpy random choice: Syntax, Weights, and Reproducible Sampling

How numpy random choice works: Generator.choice vs legacy, replace=False, weights, seeds for reproducible sampling, and fixes for common ValueErrors.

Written and maintained by CASRAI Editorial Board

Last updated

numpy random choice draws one or more values at random from an array or from the integers 0 to n-1. In current NumPy you call it as Generator.choice on a generator created with np.random.default_rng(); the older np.random.choice still works but belongs to the frozen legacy API. This guide covers both, how weights change the sampler, how to make a draw reproducible, and the errors you are most likely to meet.

What it is used for in research

Researchers use random selection to draw a sample from a list of participants, records or files, to assign units to groups, to bootstrap or resample data, and to build simulated datasets for checking an analysis. For the statistical idea behind drawing a sample without replacement, see the guide to simple random sampling. For splitting a dataset into training and test sets, see train-test split in Python.

The NumPy manual states the signature as Generator.choice(a, size=None, replace=True, p=None, axis=0, shuffle=True). The arguments are:

  • a: an array-like, or an integer. An integer means np.arange(a).
  • size: the output shape. With the default None, a single value is returned.
  • replace: True by default, so the same element can be drawn more than once.
  • p: probabilities for each element of a. If omitted, every element is equally likely.
  • axis: the axis to sample along; the default 0 selects rows of a 2-D array.
  • shuffle: True by default. It only matters when replace=False, and setting it to False is a speedup.

Install or access

NumPy’s official install page gives these routes. With pip: pip install numpy. With conda: conda create -n my-env, then conda activate my-env, then conda install numpy. To keep a project isolated with a virtual environment: python -m venv my-env, then source my-env/bin/activate on macOS or Linux, or my-env\Scripts\activate on Windows, then install with pip.

Step-by-step task

Which API to use: Generator or legacy np.random.choice

Use the Generator API. The NumPy quick start says users create a Generator with default_rng and call its methods, and the legacy documentation says it recommends transitioning to Generator. The legacy numpy.random.choice(a, size=None, replace=True, p=None) differs in three documented ways: it has no axis argument, so it cannot sample rows of a 2-D array; it uses the C long dtype, which is 32-bit on Windows and 64-bit on most other 64-bit platforms; and module-level legacy functions run on a global RandomState instance, which the manual says is discouraged because results change as the code changes.

1. Create a generator and draw with replacement

  1. Import NumPy and create the generator:
    import numpy as np
    rng = np.random.default_rng()
  2. Draw three values from the integers 0 to 4:
    rng.choice(5, 3)

    The manual notes this is equivalent to rng.integers(0, 5, 3).

  3. Draw from your own array:
    names = ['pooh', 'rabbit', 'piglet', 'Christopher']
    rng.choice(names, 5)

2. Draw without replacement

Set replace=False so no element appears twice: rng.choice(5, 3, replace=False). The manual notes this is equivalent to rng.permutation(np.arange(5))[:3]. The sample size cannot exceed the population when replace=False. To pick whole rows from a 2-D array, pass the array as a; the default axis=0 returns rows, as in the manual’s example rng.choice([[0,1,2],[3,4,5],[6,7,8]], 2, replace=False), which returns 2 rows.

3. Draw with weights

Pass p, one probability per element of a: rng.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]). An element with probability 0 is never drawn. For strings, rng.choice(names, 5, p=[0.5, 0.1, 0.1, 0.3]) draws the first name about half the time.

One documented detail matters for reproducibility: passing p uses a more general but less efficient sampler, and it produces a different sample than the optimized sampler even when every element of p is 1/len(a). Adding a uniform p to existing code therefore changes the draws for a given seed.

4. Make the draw reproducible: numpy random seed

Without a seed, the generator is seeded from nondeterministic operating system data, so each run differs. Pass an integer seed to default_rng to reproduce a sequence: rng = np.random.default_rng(12345). The quick start says that the same seed gives the same output and that seeds should be large positive integers; it shows seed = secrets.randbits(128) as a way to generate one. Record the seed in your methods notes or code repository so another researcher can repeat the draw, which supports computational reproducibility.

The older np.random.seed reseeds the singleton RandomState behind the legacy functions. The legacy page says that class is frozen and guaranteed to produce the same values as the final NumPy 1.16 release, so old seeds keep reproducing old results. The quick start adds that Generator streams differ from legacy ones, so changing API changes the numbers even with the same seed number.

Related functions that people search alongside choice

  • numpy random permutation: Generator.permutation(x, axis=0) randomly permutes a sequence or returns a permuted range. If x is an integer it permutes np.arange(x); if it is an array it returns a shuffled copy.
  • numpy random normal: Generator.normal(loc=0.0, scale=1.0, size=None) draws from a normal distribution with the given mean and standard deviation. The unit Gaussian is also available as rng.standard_normal(10).
  • numpy random uniform: Generator.uniform draws samples from a uniform distribution between low and high.
  • numpy random rand and randn: these are legacy names. The Generator equivalents are rng.random(), a float in [0, 1), and rng.standard_normal().
  • numpy random integer: the legacy randint corresponds to rng.integers(low=0, high=10, size=5), which returns integers in [0, 10).

Output and how to read it

  • With size=None you get a single value; for an integer a it is a native Python int.
  • With a size you get an ndarray of that shape, with the dtype of a. For a list of strings the dtype is a fixed-width string type.
  • With replace=True, repeated values are expected. With replace=False, every value in one call is unique.
  • The values are pseudorandom: a seeded generator gives the same output every run, which is what makes an analysis repeatable.

Troubleshooting

The NumPy manual lists the conditions under which choice raises ValueError:

Cause Fix
a is an integer less than 0 Pass a non-negative integer or an array.
a is an array with size 0 Check that the list or array you pass is not empty.
p is not 1-dimensional Pass a flat list or 1-D array of probabilities.
a and p have different lengths Give exactly one probability per element of a.
p is not a valid probability vector Probabilities must be non-negative and sum to 1. The manual gives p = p / np.sum(p, dtype=np.float64) to normalize.
replace=False and size is larger than the population Lower size, or use replace=True if repeats are acceptable for your design.

Alternatives (standard library and pandas)

Tool What the official documentation says
Python random.sample(population, k, *, counts=None) Returns a list of k unique elements chosen from the population, for sampling without replacement. It raises ValueError if the sample size is larger than the population.
Python random.choices(population, weights=None, *, cum_weights=None, k=1) Returns a list of k elements chosen with replacement, with optional weights.
pandas DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None, ignore_index=False) Samples rows (or columns) from a DataFrame, by count or fraction, with optional weights and a random_state for reproducibility.

Use random.sample or random.choices for plain Python lists, and DataFrame.sample when the data already live in a pandas table. See also how to choose a statistical test and ANOVA in Python with statsmodels for what to do with the sampled data.

FAQ

What does numpy random choice do?

It generates a random sample from a given array, or from np.arange(a) when a is an integer, with or without replacement and with optional probabilities.

How do I sample without replacement in NumPy?

Call rng.choice(a, size, replace=False). The size must not exceed the population.

How do I get the same numpy random choice every time?

Create the generator with a fixed integer seed, np.random.default_rng(seed). For the legacy function, call np.random.seed first, remembering that legacy and Generator streams differ.

Should I use np.random.choice or rng.choice?

Use rng.choice. NumPy recommends moving to Generator, and only Generator.choice has the axis argument.

Does numpy random choice accept weights?

Yes, through p. It must be a valid probability vector, and it switches to a different sampler than the unweighted call.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about numpy random choice: Syntax, Weights, and Reproducible Sampling

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Ask CASRAI · Regulatory Radar

Research-admin question? Get an answer that links its sources.

An AI assistant specialized in research administration. Every answer links its sources to check before you act. 2 questions free, no account. $29/month after.

  • Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.
  • Every answer numbers its sources and links each one, so you can check the source yourself.