Mezclar dos listas a la vez con el mismo orden

88

Estoy usando el corpus de la nltkbiblioteca movie_reviewsque contiene una gran cantidad de documentos. Mi tarea es obtener un rendimiento predictivo de estas revisiones con preprocesamiento de los datos y sin preprocesamiento. Pero hay un problema, en las listas documentsy documents2tengo los mismos documentos y necesito mezclarlos para mantener el mismo orden en ambas listas. No puedo mezclarlos por separado porque cada vez que mezclo la lista, obtengo otros resultados. Es por eso que necesito mezclarlos a la vez con el mismo orden porque necesito compararlos al final (depende del orden). Estoy usando python 2.7

Ejemplo (en real son cadenas tokenizadas, pero no es relativo):

documents = [(['plot : two teen couples go to a church party , '], 'neg'),
             (['drink and then drive . '], 'pos'),
             (['they get into an accident . '], 'neg'),
             (['one of the guys dies'], 'neg')]

documents2 = [(['plot two teen couples church party'], 'neg'),
              (['drink then drive . '], 'pos'),
              (['they get accident . '], 'neg'),
              (['one guys dies'], 'neg')]

Y necesito obtener este resultado después de mezclar ambas listas:

documents = [(['one of the guys dies'], 'neg'),
             (['they get into an accident . '], 'neg'),
             (['drink and then drive . '], 'pos'),
             (['plot : two teen couples go to a church party , '], 'neg')]

documents2 = [(['one guys dies'], 'neg'),
              (['they get accident . '], 'neg'),
              (['drink then drive . '], 'pos'),
              (['plot two teen couples church party'], 'neg')]

Tengo este codigo:

def cleanDoc(doc):
    stopset = set(stopwords.words('english'))
    stemmer = nltk.PorterStemmer()
    clean = [token.lower() for token in doc if token.lower() not in stopset and len(token) > 2]
    final = [stemmer.stem(word) for word in clean]
    return final

documents = [(list(movie_reviews.words(fileid)), category)
             for category in movie_reviews.categories()
             for fileid in movie_reviews.fileids(category)]

documents2 = [(list(cleanDoc(movie_reviews.words(fileid))), category)
             for category in movie_reviews.categories()
             for fileid in movie_reviews.fileids(category)]

random.shuffle( and here shuffle documents and documents2 with same order) # or somehow
Jaroslav Klimčík
fuente
1
Posible duplicado de Mejor manera de mezclar dos matrices numpy al unísono
Rick Smith

Respuestas:

216

Puedes hacerlo como:

import random

a = ['a', 'b', 'c']
b = [1, 2, 3]

c = list(zip(a, b))

random.shuffle(c)

a, b = zip(*c)

print a
print b

[OUTPUT]
['a', 'c', 'b']
[1, 3, 2]

Por supuesto, este fue un ejemplo con listas más simples, pero la adaptación será la misma para tu caso.

Espero eso ayude. Buena suerte.

sshashank124
fuente
Gracias, eso es exactamente lo que necesito.
Jaroslav Klimčík
4
(pregunta de novato) - ¿Qué significa *?
ᔕᖺᘎᕊ
2
@ ᔕᖺᘎᕊ, Significa descomprimir los valores de c para que se llame como en zip(1,2,3)lugar dezip([1,2,3])
sshashank124
2
Usé esta solución antes ay beran listas al final. Con Python 3.6.8, al final del mismo ejemplo, obtengo ay bcomo tuplas.
vinzee
1
... Tuplas ... entonces solo a = lista (a) yb = lista (b)
RichardBJ
37

Tengo una manera fácil de hacer esto

import numpy as np
a = np.array([0,1,2,3,4])
b = np.array([5,6,7,8,9])

indices = np.arange(a.shape[0])
np.random.shuffle(indices)

a = a[indices]
b = b[indices]
# a, array([3, 4, 1, 2, 0])
# b, array([8, 9, 6, 7, 5])
Hua Wei
fuente
La publicación original trata sobre listas normales en Python, pero necesitaba una solución para matrices numpy. ¡Me acabas de salvar el día!
finngu
10
from sklearn.utils import shuffle

a = ['a', 'b', 'c','d','e']
b = [1, 2, 3, 4, 5]

a_shuffled, b_shuffled = shuffle(np.array(a), np.array(b))
print(a_shuffled, b_shuffled)

#random output
#['e' 'c' 'b' 'd' 'a'] [5 3 2 4 1]
YScharf
fuente
6

Mezcle un número arbitrario de listas simultáneamente.

from random import shuffle

def shuffle_list(*ls):
  l =list(zip(*ls))

  shuffle(l)
  return zip(*l)

a = [0,1,2,3,4]
b = [5,6,7,8,9]

a1,b1 = shuffle_list(a,b)
print(a1,b1)

a = [0,1,2,3,4]
b = [5,6,7,8,9]
c = [10,11,12,13,14]
a1,b1,c1 = shuffle_list(a,b,c)
print(a1,b1,c1)

Salida:

$ (0, 2, 4, 3, 1) (5, 7, 9, 8, 6)
$ (4, 3, 0, 2, 1) (9, 8, 5, 7, 6) (14, 13, 10, 12, 11)

Nota: los
objetos devueltos por shuffle_list()son tuples.

PS shuffle_list()también se puede aplicar anumpy.array()

a = np.array([1,2,3])
b = np.array([4,5,6])

a1,b1 = shuffle_list(a,b)
print(a1,b1)

Salida:

$ (3, 1, 2) (6, 4, 5)
León Lai
fuente
4

Una forma fácil y rápida de hacer esto es usar random.seed () con random.shuffle (). Te permite generar el mismo orden aleatorio tantas veces como quieras. Se verá así:

a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
seed = random.random()
random.seed(seed)
a.shuffle()
random.seed(seed)
b.shuffle()
print(a)
print(b)

>>[3, 1, 4, 2, 5]
>>[8, 6, 9, 7, 10]

Esto también funciona cuando no puede trabajar con ambas listas al mismo tiempo, debido a problemas de memoria.

Boris
fuente
2
¿No debería ser random.shuffle (a)?
Khan
-2

Puede utilizar el segundo argumento de la función shuffle para fijar el orden de la mezcla.

Específicamente, puede pasar al segundo argumento de la función shuffle una función de argumento cero que devuelve un valor en [0, 1). El valor de retorno de esta función fija el orden de mezcla. (Por defecto, es decir, si no pasa ninguna función como segundo argumento, usa la función random.random(). Puede verla en la línea 277 aquí ).

Este ejemplo ilustra lo que describí:

import random

a = ['a', 'b', 'c', 'd', 'e']
b = [1, 2, 3, 4, 5]

r = random.random()            # randomly generating a real in [0,1)
random.shuffle(a, lambda : r)  # lambda : r is an unary function which returns r
random.shuffle(b, lambda : r)  # using the same function as used in prev line so that shuffling order is same

print a
print b

Salida:

['e', 'c', 'd', 'a', 'b']
[5, 3, 4, 1, 2]
Kundan Kumar
fuente
La random.shufflefunción llama a la randomfunción más de una vez, por lo que el uso de un lambdaque siempre devuelve el mismo valor puede tener efectos no deseados en el orden de salida.
Blckknght
Tienes razón. Este será un barajado sesgado, dependiendo del valor de r. Puede ser prácticamente bueno para muchos casos, pero no siempre.
Kundan Kumar