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


261

Який найпростіший спосіб перетасувати масив з python?


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, коли я просто шукав "масив пітонних перетасовок"
Джошуа Хубер

2
@Charlie люди Google ці питання, щоб вони могли знайти відповіді на них у таких місцях, як переповнення стека. Поки це не дублікат, немає нічого поганого в тому, щоб зробити переповнення стека опцією як ресурсом
Метт

@javadba Це насправді мало бути відповіддю на перше запитання. Немає нічого поганого в тому, щоб задавати питання про переповнення стека, навіть якщо його можна було знайти під час копання в Google. Це дозволяє майбутнім людям знайти відповідь на stackoverflow, коли вони роблять свої копання.
Метт


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" може керувати переміщенням для відтворюваної поведінки.


1
Дякую, дуже корисно перетасувати два масиви одночасно.
Дмитро

1
Шукав цього, TNX!
nOp

2
це більш повна (і часто корисніша), ніж прийнята відповідь
javadba

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, щоб побачити різницю в коді негайно.
Джабба

Можливо, але це може бути передчасна оптимізація (це може бути корисно, але необхідність перетасувати не вимагає явного необхідності повертати масив). Крім того, перетасовка (масив) з деяким використанням перетасовки буде лише 2 рядки на відміну від 3 + n (використання разів), хоча, я думаю, це було б економією, якщо ви будете використовувати її багато разів. Ось чудове відео, в якому обговорюються такі речі (наприклад, вимоги фантома та передчасна оптимізація) - pyvideo.org/video/880/stop-writing-classes
Аарон Ньютон,

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 (діапазон (9)). Переформатувати ([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

@javadba Ні, це просто сортувати масив за випадковим індексом, який у результаті перетасує масив
Trinh Hoang Nhu

1
До жаль я був , можливо , не ясно , що я не маю на увазі , arrayя мав на увазі Randomелемент: тобто в може бути генеруючим новим екземпляр класу кожен раз. Я насправді не впевнений: у цьому було б неправильним способом це зробити: ви повинні створити і потім викликати . Але не впевнений, як працює пітонlambdarandom.random()RandomjavaRandom rng = Random()rng.nextGaussian()random.random()
javadba

1
Хоча ваш код може виправлятись як відповідь, але розробивши те, що робить ваш код, він може покращити якість вашої відповіді. Оформити статтю: Як написати гарну відповідь?
LuFFy

1

Окрім попередніх відповідей, я хотів би запровадити ще одну функцію.

numpy.random.shuffleа також random.shuffleвиконувати переміщення на місці. Однак якщо ви хочете повернути перетасований масив numpy.random.permutation- це функція, яку слід використовувати.


1

Я не знаю, що я використав, random.shuffle()але він повертає мені "Нічого", тому я написав це, що може комусь допомогти

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

2
так, він повертає None, але масив модифікується, якщо ви дійсно хочете щось повернути, то виконайте це імпортування випадкових 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]

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.