Misture duas listas de uma vez com a mesma ordem

94

Estou usando o corpus nltkda biblioteca, movie_reviewsque contém um grande número de documentos. Minha tarefa é obter o desempenho preditivo dessas revisões com pré-processamento dos dados e sem pré-processamento. Mas há um problema, em listas documentse documents2eu tenho os mesmos documentos e preciso embaralhá-los para manter a mesma ordem nas duas listas. Não posso embaralhá-los separadamente porque cada vez que embaralho a lista, obtenho outros resultados. É por isso que preciso embaralhar os de uma vez com a mesma ordem, porque preciso compará-los no final (depende da ordem). Estou usando o python 2.7

Exemplo (na realidade, são strings com token, mas não é 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')]

E preciso obter este resultado após embaralhar as duas 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')]

Eu tenho este código:

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
fonte
1
Possível duplicata de Better way to shuffle two numpy arrays em uníssono
Rick Smith

Respostas:

230

Você pode fazer isso 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]

Claro, este foi um exemplo com listas mais simples, mas a adaptação será a mesma para o seu caso.

Espero que ajude. Boa sorte.

sshashank124
fonte
Obrigado, é exatamente disso que preciso.
Jaroslav Klimčík
5
(pergunta noob) - o que o * significa?
ᔕᖺᘎᕊ
2
@ ᔕᖺᘎᕊ, significa desempacotar os valores de c para que seja chamado em zip(1,2,3)vez dezip([1,2,3])
sshashank124
2
Eu usei essa solução antes e ae fui blistada no final. Com Python 3.6.8, no final do mesmo exemplo, obtenho ae bcomo tuplas.
vinzee
1
... Tuplas ... então apenas a = list (a) eb = list (b)
RichardBJ
40

Eu consigo uma maneira fácil de fazer isso

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
fonte
A postagem original é sobre listas normais em python, mas eu precisava de uma solução para matrizes entorpecidas. Você acabou de salvar meu dia!
finngu
11
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
fonte
6

Misture um número arbitray de listas simultaneamente.

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)

Resultado:

$ (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:
objetos retornados por shuffle_list()são tuples.

PS shuffle_list()também pode ser aplicado anumpy.array()

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

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

Resultado:

$ (3, 1, 2) (6, 4, 5)
Lion Lai
fonte
4

A maneira fácil e rápida de fazer isso é usar random.seed () com random.shuffle (). Ele permite que você gere a mesma ordem aleatória quantas vezes quiser. Isso parecerá assim:

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]

Isso também funciona quando você não pode trabalhar com as duas listas ao mesmo tempo, devido a problemas de memória.

Boris
fonte
2
não deveria ser random.shuffle (a)?
Khan
-2

Você pode usar o segundo argumento da função shuffle para corrigir a ordem de embaralhamento.

Especificamente, você pode passar ao segundo argumento da função shuffle uma função de argumento zero que retorna um valor em [0, 1). O valor de retorno desta função fixa a ordem de embaralhamento. (Por padrão, ou seja, se você não passar nenhuma função como o segundo argumento, ele usa a função random.random(). Você pode vê-la na linha 277 aqui .)

Este exemplo ilustra o que descrevi:

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

Resultado:

['e', 'c', 'd', 'a', 'b']
[5, 3, 4, 1, 2]
Kundan Kumar
fonte
A random.shufflefunção chama a randomfunção mais de uma vez, portanto, usar um lambdaque sempre retorna o mesmo valor pode ter efeitos indesejados na ordem de saída.
Blckknght
Você está certo. Este será um embaralhamento tendencioso, dependendo do valor de r. Pode ser praticamente bom para muitos casos, mas nem sempre.
Kundan Kumar