¿Cómo seleccionar aleatoriamente un elemento de una lista?


1760

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?

Respuestas:


2678

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) usesecrets.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
¿Hacer dos llamadas consecutivas random.choice(foo)devuelve dos resultados diferentes?
Eduardo Pignatelli

34
@EduardoPignatelli Cada opción es aleatoria, por lo que puede devolver dos resultados diferentes, pero dependiendo de la semilla inicial, no está garantizada. Si desea seleccionar n elementos aleatorios distintos de una lista lst , usorandom.sample(lst, n)
Graham

66
en una nota relacionada, Standard pseudo-random generators are not suitable for security/cryptographic purposes. ref
Xiao

184

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 = {1, 2, 3, 4}               # 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á sacando un solo elemento de una lista, la elección es menos complicada, ya que usar sample tendría la sintaxis en random.sample(some_list, 1)[0]lugar de random.choice(some_list).

Desafortunadamente, la elecció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 elemento de un conjunto.

EDITAR: uso de 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 = {1, 2, 3, 4}               # 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 una línea más pitónica para seleccionar varios elementos, puede usar el desempaquetado.

import random
first_random_item, second_random_item = random.sample(group_of_items, 2)

1
Por cierto, secretsse añadió el módulo de la biblioteca estándar de Python en la versión 3.6 python.org/dev/peps/pep-0506
and1er

160

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

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

42

A partir de Python 3.6, puede usar el secretsmódulo, que es preferible al randommódulo para criptografía o usos de 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 más detalles, ver PEP 506 .


33

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

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([])

20
O podría simplemente random.shufflela listvez y, o bien iterate o el pop para producir resultados. Cualquiera de los dos resultaría en una secuencia de "selección aleatoria sin repeticiones" perfectamente adecuada, es solo que la aleatoriedad se introduciría al principio.
ShadowRanger

2
Teóricamente, 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

14
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)

66
Tenga en cuenta que random.choiceses con reemplazo mientras que random.samplees sin reemplazo.
CentAu

1
También tenga en cuenta que random.choices está disponible desde 3.6 y versiones posteriores, ¡no antes!
Cyril N.

11

numpy solución: numpy.random.choice

Para esta pregunta, funciona igual que la respuesta aceptada ( import random; random.choice()), pero la agregué porque el programador puede haber importado numpyya (como yo) y también hay 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

9

¿Cómo seleccionar aleatoriamente un elemento de una lista?

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?

Si quieres cerca de ser verdaderamente aleatorio , entonces 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, usando 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:

No se trata de si random.choice es realmente aleatorio o no. Si arregla la semilla, obtendrá los resultados reproducibles, y para eso está diseñada la semilla. También puede pasar una semilla a SystemRandom.sr = random.SystemRandom(42)

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

def seed(self, *args, **kwds):
    "Stub method.  Not used for a system random number generator."
    return None

8

si necesitas el índice solo usa:

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 :)


2
@tc. En realidad, hace esencialmente lo mismo. Implementación de random.choice(self, seq)is return seq[int(self.random() * len(seq))].
wim

2
@wim Eso es un poco decepcionante, pero lo muy decepcionante es que también es la definición de lo randrange()que significa, por ejemplo, random.SystemRandom().randrange(3<<51)exhibe un sesgo significativo. Suspiro ...
tc.

66
@ kevinsa5 En última instancia, se debe a que un 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: selecciona un número entero aleatorio [0, 2**53)y divide entre 2**53(53 es el número de bits en un doble). Entonces 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 este sesgo).
tc.

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 importe 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 de esta parte de su código.
Evgeni Sergeev

@tc .: En realidad, se randomusa getrandbitspara obtener un número adecuado de bits para generar un resultado para randranges más grandes ( random.choicetambién se usa 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 lo estúpido que crees que es.
ShadowRanger

7

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 manera más corta e inteligente para hacerlo:

import random

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

(pitón 2.7)


3

El siguiente código demuestra si necesita producir los mismos artículos. También puede especificar cuántas muestras desea extraer.
El samplemétodo devuelve una nueva lista que contiene elementos de la población mientras deja la población original sin cambios. La lista resultante está en orden de selección para que todos los sub-cortes 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']

1

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 lo siguiente:

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


0

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)

19
¿Por qué demonios lo harías de esta manera, cuando hay random.choice()y random.randrange()?
alexis

"random.choice ()" le dará "IndexError: índice de lista fuera de rango" en la lista vacía.
Abdul Majeed

66
Como debería: para eso están las excepciones. Elegir de una lista vacía es un error. Al regresar, Nonela lata se lanza a un punto aleatorio posterior donde el "elemento" no válido desencadena una excepción; o peor aún, obtienes un programa incorrecto en lugar de una excepción, y ni siquiera lo sabes.
alexis

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.