¿Cómo puedo seleccionar aleatoriamente un artículo de una lista?

2029

Supongamos que tengo la siguiente lista:

foo = ['a', 'b', 'c', 'd', 'e']

¿Cuál es la forma más sencilla de recuperar un elemento al azar de esta lista?

0
3031

Utilizar random.choice():

import random

foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))

Para opciones aleatorias criptográficamente seguras (por ejemplo, para generar una frase de contraseña a partir de una lista de palabras), use secrets.choice():

import secrets

foo = ['battery', 'correct', 'horse', 'staple']
print(secrets.choice(foo))

secretses nuevo en Python 3.6. En versiones anteriores de Python, puede usar la random.SystemRandomclase:

import random

secure_random = random.SystemRandom()
print(secure_random.choice(foo))
3
  • 4
    ¿Hacer dos llamadas consecutivas random.choice(foo)devuelve dos resultados diferentes? 7/12/18 a las 17:13
  • 60
    @EduardoPignatelli Cada elección es aleatoria, por lo que puede devolver dos resultados diferentes, pero dependiendo de la semilla inicial, no está garantizado. Si desea seleccionar n elementos aleatorios distintos de una lista lst , el usorandom.sample(lst, n)
    Graham
    23 dic 2018 a las 17:02
  • 8
    en una nota relacionada, Standard pseudo-random generators are not suitable for security/cryptographic purposes. ref.
    XoXo
    30/01/19 a las 19:46
240

Si desea seleccionar aleatoriamente más de un elemento de una lista, o seleccionar un elemento de un conjunto, le recomiendo usar en su random.samplelugar.

import random
group_of_items = {'a', 'b', 'c', 'd', 'e'}  # a sequence or set will work here.
num_to_select = 2                           # set the number to select here.
list_of_random_items = random.sample(group_of_items, num_to_select)
first_random_item = list_of_random_items[0]
second_random_item = list_of_random_items[1] 

Sin embargo, si solo está extrayendo un solo elemento de una lista, la elección es menos torpe, ya que usar la muestra tendría la sintaxis en random.sample(some_list, 1)[0]lugar de random.choice(some_list).

Sin embargo, desafortunadamente, la opción solo funciona para una única salida de secuencias (como listas o tuplas). Aunque random.choice(tuple(some_set))puede ser una opción para obtener un solo artículo de un conjunto.

EDITAR: Usando secretos

Como muchos han señalado, si necesita muestras pseudoaleatorias más seguras, debe usar el módulo de secretos:

import secrets                              # imports secure module.
secure_random = secrets.SystemRandom()      # creates a secure random object.
group_of_items = {'a', 'b', 'c', 'd', 'e'}  # a sequence or set will work here.
num_to_select = 2                           # set the number to select here.
list_of_random_items = secure_random.sample(group_of_items, num_to_select)
first_random_item = list_of_random_items[0]
second_random_item = list_of_random_items[1]

EDITAR: Pythonic One-Liner

Si desea un resumen más pitónico para seleccionar varios elementos, puede utilizar el desembalaje.

import random
first_random_item, second_random_item = random.sample({'a', 'b', 'c', 'd', 'e'}, 2)
1
170

Si también necesita el índice, use random.randrange

from random import randrange
random_index = randrange(len(foo))
print(foo[random_index])
0
49

A partir de Python 3.6, puede usar el secretsmódulo, que es preferible al randommódulo para usos de criptografía o seguridad.

Para imprimir un elemento aleatorio de una lista:

import secrets
foo = ['a', 'b', 'c', 'd', 'e']
print(secrets.choice(foo))

Para imprimir un índice aleatorio:

print(secrets.randbelow(len(foo)))

Para obtener más detalles, consulte PEP 506 .

36

Propongo un script para eliminar elementos seleccionados aleatoriamente de una lista hasta que esté vacía:

Mantenga sety elimine el elemento seleccionado aleatoriamente (con choice) hasta que la lista esté vacía.

s=set(range(1,6))
import random

while len(s)>0:
  s.remove(random.choice(list(s)))
  print(s)

Tres carreras dan tres respuestas diferentes:

>>> 
set([1, 3, 4, 5])
set([3, 4, 5])
set([3, 4])
set([4])
set([])
>>> 
set([1, 2, 3, 5])
set([2, 3, 5])
set([2, 3])
set([2])
set([])

>>> 
set([1, 2, 3, 5])
set([1, 2, 3])
set([1, 2])
set([1])
set([])
2
  • 23
    O podría simplemente random.shufflela listvez y, o bien iterate o el pop para producir resultados. Cualquiera resultaría en una secuencia perfectamente adecuada de "seleccionar aleatoriamente sin repeticiones", es solo que la aleatoriedad se introduciría al principio. 25 de diciembre de 2015 a las 3:23
  • 2
    En teoría, puede usar el método pop () de un conjunto para eliminar un elemento arbitrario de un conjunto y devolverlo, pero probablemente no sea lo suficientemente aleatorio.
    Joubarc
    17 de junio de 2016 a las 7:07
23
foo = ['a', 'b', 'c', 'd', 'e']
number_of_samples = 1

En Python 2:

random_items = random.sample(population=foo, k=number_of_samples)

En Python 3:

random_items = random.choices(population=foo, k=number_of_samples)
2
  • 11
    Tenga en cuenta que random.choiceses con reemplazo mientras que no random.sampletiene reemplazo.
    CentAu
    5 de marzo de 2018 a las 23:43
  • 2
    También tenga en cuenta que random.choices está disponible desde 3.6 y versiones posteriores, ¡no antes! 20 oct 2018 a las 9:43
18

Solución NumPy :numpy.random.choice

Para esta pregunta, funciona igual que la respuesta aceptada ( import random; random.choice()), pero la agregué porque es posible que el programador ya haya importado NumPy (como yo)

Y también existen algunas diferencias entre los dos métodos que pueden afectar a su caso de uso real.

import numpy as np
np.random.choice(foo) # randomly selects a single item

Para la reproducibilidad, puede hacer:

np.random.seed(123)
np.random.choice(foo) # first call will always return 'c'

Para muestras de uno o más elementos , devueltos como un array, pase el sizeargumento:

np.random.choice(foo, 5)          # sample with replacement (default)
np.random.choice(foo, 5, False)   # sample without replacement
12

How to randomly select an item from a list?

Assume I have the following list:

foo = ['a', 'b', 'c', 'd', 'e']  

What is the simplest way to retrieve an item at random from this list?

Si lo desea cerca de lo verdaderamente aleatorio , sugiero secrets.choicede la biblioteca estándar (Nuevo en Python 3.6.):

>>> from secrets import choice         # Python 3 only
>>> choice(list('abcde'))
'c'

Lo anterior es equivalente a mi recomendación anterior, usar un SystemRandomobjeto del randommódulo con el choicemétodo, disponible anteriormente en Python 2:

>>> import random                      # Python 2 compatible
>>> sr = random.SystemRandom()
>>> foo = list('abcde')
>>> foo
['a', 'b', 'c', 'd', 'e']

Y ahora:

>>> sr.choice(foo)
'd'
>>> sr.choice(foo)
'e'
>>> sr.choice(foo)
'a'
>>> sr.choice(foo)
'b'
>>> sr.choice(foo)
'a'
>>> sr.choice(foo)
'c'
>>> sr.choice(foo)
'c'

Si desea una selección pseudoaleatoria determinista, use la choicefunción (que en realidad es un método enlazado en un Randomobjeto):

>>> random.choice
<bound method Random.choice of <random.Random object at 0x800c1034>>

Parece aleatorio, pero en realidad no lo es, lo que podemos ver si lo resembramos repetidamente:

>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')

Un comentario:

This is not about whether random.choice is truly random or not. If you fix the seed, you will get the reproducible results -- and that's what seed is designed for. You can pass a seed to SystemRandom, too. sr = random.SystemRandom(42)

Bueno, sí, puede pasarle un argumento "semilla", pero verá que el SystemRandomobjeto simplemente lo ignora :

def seed(self, *args, **kwds):
    "Stub method.  Not used for a system random number generator."
    return None
1
  • Esto es simplemente pedante, pero los secretos no son verdaderamente aleatorios, es pseudoaleatorio criptográficamente seguro.
    Paul
    10 de ene a las 22:07
12

Si necesita el índice, simplemente use:

import random
foo = ['a', 'b', 'c', 'd', 'e']
print int(random.random() * len(foo))
print foo[int(random.random() * len(foo))]

random.choice hace lo mismo :)

5
  • 2
    @tc. En realidad, hace esencialmente lo mismo. Implementación de random.choice(self, seq)is return seq[int(self.random() * len(seq))].
    wim
    12 de abril de 2013 a las 4:56
  • 2
    @wim Eso es un poco decepcionante, pero lo más decepcionante es que esa también es la definición de lo randrange()que significa, por ejemplo, que random.SystemRandom().randrange(3<<51)exhibe un sesgo significativo. Suspiro...
    tc.
    13/04/13 a las 23:55
  • 7
    @ kevinsa5 En última instancia, se debe a que a float(un doble IEEE) solo puede tomar un número finito de valores en [0,1). Random.random()genera su salida de la manera tradicional: elija un número entero aleatorio [0, 2**53)y divídalo por 2**53(53 es el número de bits en un doble). Por lo tanto, random()devuelve 2 ** 53 dobles equiprobables, y puede dividir esto uniformemente en N salidas solo si N es una potencia de 2. El sesgo es pequeño para N pequeño, pero vea collections.Counter(random.SystemRandom().randrange(3<<51)%6 for i in range(100000)).most_common(). (Random.nextInt () de Java evita tal sesgo).
    tc.
    18/01/2014 a las 16:37
  • 1
    @tc. Supongo que algo menos que aproximadamente 2**40, (que es 1099511627776), sería lo suficientemente pequeño como para que el sesgo no importara en la práctica. Esto realmente debería señalarse en la documentación, porque si alguien no es meticuloso, es posible que no espere que surjan problemas en esta parte de su código. 29 de mayo de 2015 a las 1:28
  • 1
    @tc .: En realidad, randomusa getrandbitspara obtener una cantidad adecuada de bits para generar un resultado para randranges más grandes ( random.choicetambién está usando eso). Esto es cierto tanto en 2.7 como en 3.5. Solo se usa self.random() * len(seq)cuando getrandbitsno está disponible. No está haciendo la estupidez que crees. 25 de diciembre de 2015 a las 3:32
8

Este es el código con una variable que define el índice aleatorio:

import random

foo = ['a', 'b', 'c', 'd', 'e']
randomindex = random.randint(0,len(foo)-1) 
print (foo[randomindex])
## print (randomindex)

Este es el código sin la variable:

import random

foo = ['a', 'b', 'c', 'd', 'e']
print (foo[random.randint(0,len(foo)-1)])

Y este es el código de la forma más corta e inteligente de hacerlo:

import random

foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))

(pitón 2.7)

4

Selección aleatoria de artículos:

import random

my_list = [1, 2, 3, 4, 5]
num_selections = 2

new_list = random.sample(my_list, num_selections)

Para preservar el orden de la lista, puede hacer:

randIndex = random.sample(range(len(my_list)), n_selections)
randIndex.sort()
new_list = [my_list[i] for i in randIndex]

Duplicado de https://stackoverflow.com/a/49682832/4383027

3

El siguiente código demuestra si necesita producir los mismos elementos. También puede especificar cuántas muestras desea extraer.
El samplemétodo devuelve una nueva lista que contiene elementos de la población sin modificar la población original. La lista resultante está en orden de selección para que todas las sub-rebanadas también sean muestras aleatorias válidas.

import random as random
random.seed(0)  # don't use seed function, if you want different results in each run
print(random.sample(foo,3))  # 3 is the number of sample you want to retrieve

Output:['d', 'e', 'a']
3

Podrías simplemente:

from random import randint

foo = ["a", "b", "c", "d", "e"]

print(foo[randint(0,4)])
3

Es posible que esta ya sea una respuesta, pero podría usarla random.shuffle. Ejemplo:

import random
foo = ['a', 'b', 'c', 'd', 'e']
random.shuffle(foo)
1
  • - ¡¡¡¡¡Shuffle !!!!!! 16 de agosto a las 4:21
-1

También podemos hacer esto usando randint.

from random import randint
l= ['a','b','c']

def get_rand_element(l):
    if l:
        return l[randint(0,len(l)-1)]
    else:
        return None

get_rand_element(l)
4
  • 22
    ¿Por qué diablos lo harías de esta manera, cuando hay random.choice()y random.randrange()?
    alexis
    19 de marzo de 2016 a las 15:10
  • "random.choice ()" le dará "IndexError: list index out of range" en una lista vacía. 5 de septiembre de 2017 a las 5:45
  • 9
    Como debería: para eso están las excepciones. Elegir de una lista vacía es un error. Regresar Nonesimplemente patea la lata a algún punto posterior aleatorio donde el "elemento" inválido desencadena una excepción; o peor aún, obtiene un programa incorrecto en lugar de una excepción y ni siquiera lo sabe.
    alexis
    5 de septiembre de 2017 a las 9:27
  • ¿Puede agregar una referencia a randint , preferiblemente a la documentación oficial? 31 jul a las 19:00