Перемешать два списка одновременно в том же порядке

89

Я использую корпус nltkбиблиотеки, movie_reviewsкоторый содержит большое количество документов. Моя задача - добиться прогнозной эффективности этих обзоров с предварительной обработкой данных и без предварительной обработки. Но есть проблема, в списках documentsи documents2у меня одни и те же документы, и мне нужно перетасовать их, чтобы сохранить одинаковый порядок в обоих списках. Я не могу перемешать их по отдельности, потому что каждый раз, когда я перемешиваю список, я получаю другие результаты. Вот почему мне нужно перемешать сразу в том же порядке, потому что мне нужно сравнить их в конце (это зависит от порядка). Я использую Python 2.7

Пример (на самом деле строки токенизированы, но не относительны):

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

И мне нужно получить этот результат после перетасовки обоих списков:

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

У меня есть такой код:

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
Ярослав Климчик
источник

Ответы:

217

Вы можете сделать это как:

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]

Конечно, это был пример с более простыми списками, но для вашего случая адаптация будет такой же.

Надеюсь, это поможет. Удачи.

sshashank124
источник
Спасибо, это именно то, что мне нужно.
Ярослав Климчик
4
(вопрос новичка) - что означает *?
ᔕᖺᘎᕊ 02
2
@ ᔕᖺᘎᕊ, это означает распаковать значения c, чтобы он назывался как zip(1,2,3)вместоzip([1,2,3])
sshashank124 03
2
Я использовал это решение до и aи bбыли списки в конце. В Python 3.6.8 в конце того же примера я получаю aи в bвиде кортежей.
vinzee
1
... Кортежи ... так что просто a = list (a) и b = list (b)
RichardBJ
37

У меня есть простой способ сделать это

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])
Хуа Вэй
источник
Исходный пост посвящен обычным спискам в python, но мне нужно было решение для массивов numpy. Ты только что спас мне день!
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
источник
6

Перемешивайте произвольное количество списков одновременно.

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)

Выход:

$ (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)

Примечание:
объекты, возвращаемые shuffle_list()are tuples.

PS shuffle_list()также может применяться кnumpy.array()

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

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

Выход:

$ (3, 1, 2) (6, 4, 5)
Лев Лай
источник
4

Простой и быстрый способ сделать это - использовать random.seed () с random.shuffle (). Это позволяет вам генерировать один и тот же случайный порядок много раз. Это будет выглядеть так:

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]

Это также работает, когда вы не можете работать с обоими списками одновременно из-за проблем с памятью.

Борис
источник
2
Разве это не должно быть random.shuffle (a)?
Хан
-2

Вы можете использовать второй аргумент функции перемешивания, чтобы исправить порядок перемешивания.

В частности, вы можете передать второму аргументу функции перемешивания функцию с нулевым аргументом, которая возвращает значение в [0, 1). Возвращаемое значение этой функции фиксирует порядок перемешивания. (По умолчанию, т.е. если вы не передаете какую-либо функцию в качестве второго аргумента, она использует эту функцию random.random(). Вы можете увидеть это в строке 277 здесь .)

Этот пример иллюстрирует то, что я описал:

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

Выход:

['e', 'c', 'd', 'a', 'b']
[5, 3, 4, 1, 2]
Кундан Кумар
источник
random.shuffleФункция вызывает randomфункцию более одного раза, так используя , lambdaчто всегда возвращает то же значение может иметь непредсказуемые последствия для вывода.
Blckknght
Ты прав. Это будет предвзятое перемешивание, зависящее от значения r. Это может быть практически хорошо для многих случаев, но не всегда.
Кундан Кумар