Перемешать массив с python, рандомизировать порядок элементов массива с python

261

Какой самый простой способ перемешать массив с помощью Python?

davethegr8
источник
28
+1 за перенос самых полезных битов документации на python в всегда лучший формат SO Q & A.
charleslparker
1
есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
Чарли Паркер
5
Вы можете получить новый массив (без изменений) с new_array = random.sample( array, len(array) ).
Чарли Паркер

Ответы:

464
import random
random.shuffle(array)
Дэвид З
источник
3
есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
Чарли Паркер
@Charlie Это было бы неплохо задать в отдельном вопросе. (Может быть, кто-то еще уже спросил об этом.)
David Z
13
По иронии судьбы, эта страница стала хитом в Google, когда я только что искал «массив питонов shuffle»
Джошуа Хубер
2
@ Чарли люди Google эти вопросы, чтобы они могли найти ответы на них в таких местах, как переполнение стека. Пока это не дубликат, нет ничего плохого в том, чтобы сделать переполнение стека опцией в качестве ресурса
Мэтт
@javadba На самом деле это был ответ на первый вопрос. Нет ничего плохого в том, чтобы задавать вопросы о переполнении стека, даже если это можно было найти, покопавшись в Google. Это позволяет будущим людям найти ответ на стеке потока, когда они сами копают.
Мэтт
108
import random
random.shuffle(array)
Дуглас Лидер
источник
2
есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
Чарли Паркер
36

Альтернативный способ сделать это с помощью sklearn

from sklearn.utils import shuffle
X=[1,2,3]
y = ['one', 'two', 'three']
X, y = shuffle(X, y, random_state=0)
print(X)
print(y)

Вывод:

[2, 1, 3]
['two', 'one', 'three']

Преимущество: вы можете рандомизировать несколько массивов одновременно, не нарушая отображение. И «random_state» может контролировать перетасовку для воспроизводимого поведения.

Qy Zuo
источник
1
Спасибо, очень полезно перетасовать два массива одновременно.
Дмитрий
1
Искал это, TNX!
Ноябрь
2
это более полный (и часто более полезный), чем принятый ответ
Джавадба
21

Остальные ответы самые простые, однако немного раздражает, что random.shuffleметод на самом деле ничего не возвращает - он просто сортирует заданный список. Если вы хотите объединить вызовы или просто иметь возможность объявлять перемешанный массив в одну строку, вы можете сделать следующее:

    import random
    def my_shuffle(array):
        random.shuffle(array)
        return array

Тогда вы можете сделать такие строки:

    for suit in my_shuffle(['hearts', 'spades', 'clubs', 'diamonds']):
Марк Родос
источник
7
Он ничего не возвращает конкретно, потому что пытается напомнить вам, что работает, изменяя ввод на месте. (Это может сэкономить память.) Ваша функция также меняет свой ввод.
Джон Y
2
Я думаю, это стиль. Лично я предпочитаю тот факт, что я могу написать одну строку, чтобы добиться того, что в противном случае было бы парой. Мне кажется странным, что язык, который нацелен на то, чтобы программы были как можно более короткими, не склонен возвращать переданный объект в этих случаях. Поскольку он изменяет ввод на месте, вы можете заменить вызов random.shuffle на вызов этой версии без проблем.
Марк Родс
12
Python на самом деле не стремится быть максимально кратким. Python стремится сбалансировать читабельность с выразительностью. Так получилось довольно кратко, главным образом потому, что это язык очень высокого уровня. Собственные встроенные функции Python обычно (не всегда) стремятся либо быть «подобными функции» (возвращать значение, но не иметь побочных эффектов), либо быть «подобными процедуре» (работать через побочные эффекты и ничего не возвращать). Это идет рука об руку с довольно строгим различием Python между утверждениями и выражениями.
Джон Y
Ницца. Я предлагаю переименовать его в my_shuffle, чтобы сразу увидеть разницу в коде.
Джабба
Возможно, но это может быть преждевременной оптимизацией (это может быть полезно, но необходимость перестановки не требует явного возврата массива). Кроме того, shuffle (массив), за которым следует некоторое использование shuffle, будет состоять всего из 2 строк, а не 3 + n (использование раз), хотя я полагаю, что это будет экономия, если вы будете использовать его много раз. Вот отличное видео, в котором обсуждаются подобные
Аарон Ньютон,
12

При работе с обычными списками Python, random.shuffle()сделайте работу так же, как показывают предыдущие ответы.

Но когда дело доходит до ndarray( numpy.array), random.shuffleкажется, сломать оригинал ndarray. Вот пример:

import random
import numpy as np
import numpy.random

a = np.array([1,2,3,4,5,6])
a.shape = (3,2)
print a
random.shuffle(a) # a will definitely be destroyed
print a

Просто используйте: np.random.shuffle(a)

Мол random.shuffle, np.random.shuffleтасует массив на месте.

Шуай Чжан
источник
2
что именно означает уничтоженный? (Я имею в виду, в этом контексте - я не ELL.)
dbliss
Хорошо, если я попробую A = np.array (range (9)). Reshape ([3,3])
Николас Маккарти
11

На всякий случай, если вы хотите новый массив, вы можете использовать sample:

import random
new_array = random.sample( array, len(array) )
Чарли Паркер
источник
3

Вы можете отсортировать ваш массив со случайным ключом

sorted(array, key = lambda x: random.random())

ключ читается только один раз, поэтому сравнение элементов во время сортировки остается эффективным.

но похоже random.shuffle(array)будет быстрее так как написано на С

Трин Хоанг Нху
источник
1
это создает новый случайный элемент для каждого элемента массива?
Джавадба
@javadba Нет, это просто сортировка массива по случайному индексу, который в конечном итоге перетасует массив
Trinh Hoang Nhu
1
К сожалению я был , возможно , не ясно , что я не имею в виду , arrayя имел в виду Randomэлемент: то есть в может быть генерирующим новым экземпляр класса каждый раз. На самом деле я не уверен: это был бы неправильный способ сделать это: вы должны создать и затем вызвать . Но не уверен, как работает Pythonlambdarandom.random()RandomjavaRandom rng = Random()rng.nextGaussian()random.random()
Javadba
1
Хотя ваш код может корректироваться как ответ, но если вы уточните, что делает ваш код, это может улучшить качество вашего ответа. Оформить заказ статьи: Как мне написать хороший ответ?
LuFFy
1

В дополнение к предыдущим ответам я хотел бы представить еще одну функцию.

numpy.random.shuffleа также random.shuffleвыполнять перетасовку на месте. Однако, если вы хотите вернуть перетасованный массив, numpy.random.permutationэто функция для использования.

сабля
источник
1

Я не знаю, использовал ли random.shuffle()он, но он возвращает «None» мне, поэтому я написал это, может быть полезным для кого-то

def shuffle(arr):
    for n in range(len(arr) - 1):
        rnd = random.randint(0, (len(arr) - 1))
        val1 = arr[rnd]
        val2 = arr[rnd - 1]

        arr[rnd - 1] = val1
        arr[rnd] = val2

    return arr
Jeeva
источник
2
да, он возвращает None, но массив модифицируется, если вы действительно хотите что-то вернуть, тогда выполните этот импорт random def shuffle (arr): random.shuffle (arr) return arr
user781903
0
# arr = numpy array to shuffle

def shuffle(arr):
    a = numpy.arange(len(arr))
    b = numpy.empty(1)
    for i in range(len(arr)):
        sel = numpy.random.random_integers(0, high=len(a)-1, size=1)
        b = numpy.append(b, a[sel])
        a = numpy.delete(a, sel)
    b = b[1:].astype(int)
    return arr[b]
Sudeep
источник
0

Помните, что random.shuffle()не следует использовать многомерные массивы, поскольку это вызывает повторения.

Представьте, что вы хотите перетащить массив вдоль его первого измерения, мы можем создать следующий тестовый пример:

import numpy as np
x = np.zeros((10, 2, 3))

for i in range(10):
   x[i, ...] = i*np.ones((2,3))

так что вдоль первой оси i-й элемент соответствует матрице 2x3, где все элементы равны i.

Если мы используем правильную функцию тасования для многомерных массивов, т. np.random.shuffle(x)Е. Массив будет перетасовываться вдоль первой оси по желанию. Однако использование random.shuffle(x)приведет к повторениям. Вы можете проверить это, запустив len(np.unique(x))после перетасовки, что дает 10 (как и ожидалось), np.random.shuffle()но только около 5 при использовании random.shuffle().

Мудрое Облако
источник