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

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.


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

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]

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)

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.


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]

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.