Подтвердить что ты не робот

Numpy перемещает многомерный массив только по строке, сохраняет порядок столбцов без изменений

Как я могу перетасовать многомерный массив по строке только в Python (так что не перетасовывайте столбцы).

Я ищу наиболее эффективное решение, потому что моя матрица очень огромная. Возможно ли также сделать это очень эффективным для исходного массива (чтобы сохранить память)?

Пример:

import numpy as np
X = np.random.random((6, 2))
print(X)
Y = ???shuffle by row only not colls???
print(Y)

Теперь я ожидаю оригинальную матрицу:

[[ 0.48252164  0.12013048]
 [ 0.77254355  0.74382174]
 [ 0.45174186  0.8782033 ]
 [ 0.75623083  0.71763107]
 [ 0.26809253  0.75144034]
 [ 0.23442518  0.39031414]]

Выходные данные перетасовывают строки не cols, например:

[[ 0.45174186  0.8782033 ]
 [ 0.48252164  0.12013048]
 [ 0.77254355  0.74382174]
 [ 0.75623083  0.71763107]
 [ 0.23442518  0.39031414]
 [ 0.26809253  0.75144034]]
4b9b3361

Ответ 1

То, что numpy.random.shuffle() для:

>>> X = np.random.random((6, 2))
>>> X
array([[ 0.9818058 ,  0.67513579],
       [ 0.82312674,  0.82768118],
       [ 0.29468324,  0.59305925],
       [ 0.25731731,  0.16676408],
       [ 0.27402974,  0.55215778],
       [ 0.44323485,  0.78779887]])

>>> np.random.shuffle(X)
>>> X
array([[ 0.9818058 ,  0.67513579],
       [ 0.44323485,  0.78779887],
       [ 0.82312674,  0.82768118],
       [ 0.29468324,  0.59305925],
       [ 0.25731731,  0.16676408],
       [ 0.27402974,  0.55215778]])

Ответ 2

Вы также можете использовать np.random.permutation для генерации произвольной перестановки индексов строк, а затем индексировать строки X с помощью np.take с axis=0. Кроме того, np.take облегчает переписывание на входной массив X с параметром out=, который сохранит нам память. Таким образом, реализация будет выглядеть так:

np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X)

Пример прогона -

In [23]: X
Out[23]: 
array([[ 0.60511059,  0.75001599],
       [ 0.30968339,  0.09162172],
       [ 0.14673218,  0.09089028],
       [ 0.31663128,  0.10000309],
       [ 0.0957233 ,  0.96210485],
       [ 0.56843186,  0.36654023]])

In [24]: np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X);

In [25]: X
Out[25]: 
array([[ 0.14673218,  0.09089028],
       [ 0.31663128,  0.10000309],
       [ 0.30968339,  0.09162172],
       [ 0.56843186,  0.36654023],
       [ 0.0957233 ,  0.96210485],
       [ 0.60511059,  0.75001599]])

Дополнительное повышение производительности

Вот трюк для ускорения np.random.permutation(X.shape[0]) с np.argsort() -

np.random.rand(X.shape[0]).argsort()

Результаты ускорения -

In [32]: X = np.random.random((6000, 2000))

In [33]: %timeit np.random.permutation(X.shape[0])
1000 loops, best of 3: 510 µs per loop

In [34]: %timeit np.random.rand(X.shape[0]).argsort()
1000 loops, best of 3: 297 µs per loop

Таким образом, решение перетасовки может быть изменено на -

np.take(X,np.random.rand(X.shape[0]).argsort(),axis=0,out=X)

Тесты времени выполнения -

Эти тесты включают в себя два подхода, перечисленных в этом сообщении, и np.shuffle на основе одного в @Kasramvd solution.

In [40]: X = np.random.random((6000, 2000))

In [41]: %timeit np.random.shuffle(X)
10 loops, best of 3: 25.2 ms per loop

In [42]: %timeit np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X)
10 loops, best of 3: 53.3 ms per loop

In [43]: %timeit np.take(X,np.random.rand(X.shape[0]).argsort(),axis=0,out=X)
10 loops, best of 3: 53.2 ms per loop

Таким образом, кажется, что использование этих np.take оснований может быть использовано только в том случае, если память является проблемой, а решение на основе np.random.shuffle похоже на способ перехода.

Ответ 3

После небольшого эксперимента я обнаружил, что большинство памяти и времени эффективный способ перетасовать данные (ряд мудрый) nd-массива - перетасовать индекс и получить данные из перетасованного индекса

rand_num2 = np.random.randint(5, size=(6000, 2000))
perm = np.arange(rand_num2.shape[0])
np.random.shuffle(perm)
rand_num2 = rand_num2[perm]

подробнее
Здесь я использую memory_profiler, чтобы найти использование памяти и python встроенный модуль времени для записи времени и сравнения всех предыдущих ответов

def main():
    # shuffle data itself
    rand_num = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    np.random.shuffle(rand_num)
    print('Time for direct shuffle: {0}'.format((time.time() - start)))

    # Shuffle index and get data from shuffled index
    rand_num2 = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    perm = np.arange(rand_num2.shape[0])
    np.random.shuffle(perm)
    rand_num2 = rand_num2[perm]
    print('Time for shuffling index: {0}'.format((time.time() - start)))

    # using np.take()
    rand_num3 = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    np.take(rand_num3, np.random.rand(rand_num3.shape[0]).argsort(), axis=0, out=rand_num3)
    print("Time taken by np.take, {0}".format((time.time() - start)))

Результат для времени

Time for direct shuffle: 0.03345608711242676   # 33.4msec
Time for shuffling index: 0.019818782806396484 # 19.8msec
Time taken by np.take, 0.06726956367492676     # 67.2msec

Профайлер памяти Результат

Line #    Mem usage    Increment   Line Contents
================================================
    39  117.422 MiB    0.000 MiB   @profile
    40                             def main():
    41                                 # shuffle data itself
    42  208.977 MiB   91.555 MiB       rand_num = np.random.randint(5, size=(6000, 2000))
    43  208.977 MiB    0.000 MiB       start = time.time()
    44  208.977 MiB    0.000 MiB       np.random.shuffle(rand_num)
    45  208.977 MiB    0.000 MiB       print('Time for direct shuffle: {0}'.format((time.time() - start)))
    46                             
    47                                 # Shuffle index and get data from shuffled index
    48  300.531 MiB   91.555 MiB       rand_num2 = np.random.randint(5, size=(6000, 2000))
    49  300.531 MiB    0.000 MiB       start = time.time()
    50  300.535 MiB    0.004 MiB       perm = np.arange(rand_num2.shape[0])
    51  300.539 MiB    0.004 MiB       np.random.shuffle(perm)
    52  300.539 MiB    0.000 MiB       rand_num2 = rand_num2[perm]
    53  300.539 MiB    0.000 MiB       print('Time for shuffling index: {0}'.format((time.time() - start)))
    54                             
    55                                 # using np.take()
    56  392.094 MiB   91.555 MiB       rand_num3 = np.random.randint(5, size=(6000, 2000))
    57  392.094 MiB    0.000 MiB       start = time.time()
    58  392.242 MiB    0.148 MiB       np.take(rand_num3, np.random.rand(rand_num3.shape[0]).argsort(), axis=0, out=rand_num3)
    59  392.242 MiB    0.000 MiB       print("Time taken by np.take, {0}".format((time.time() - start)))

Ответ 4

Перемешивание выше (см. ответ Кашрамвд) не всегда работает. Например:.

Пример:

import numpy as np 
X = np.array([[1,1,1,2,3,5],
              [1,2,1,2,3,5],
              [1,3,1,2,3,5],
              [1,4,1,2,3,5],
              [1,5,1,2,3,5],
              [1,6,1,2,3,5],
              [1,7,1,2,3,5], 
              [1,8,1,2,3,5],
              [1,9,1,2,3,5],
              [1,10,1,2,3,5],
              [1,11,1,2,3,5],
              [1,12,1,2,3,5], 
              [0,13,1,2,3,5]],np.float32)

Y = np.random.shuffle(X)
print('Shuffle ',Y)
print('X',X)

Выходы:

Shuffle  None
X [[  0.  13.   1.   2.   3.   5.]
 [  1.   9.   1.   2.   3.   5.]
 [  1.   4.   1.   2.   3.   5.]
 [  1.   1.   1.   2.   3.   5.]
 [  1.   7.   1.   2.   3.   5.]
 [  1.   3.   1.   2.   3.   5.]
 [  1.   2.   1.   2.   3.   5.]
 [  1.  11.   1.   2.   3.   5.]
 [  1.  12.   1.   2.   3.   5.]
 [  1.  10.   1.   2.   3.   5.]
 [  1.   5.   1.   2.   3.   5.]
 [  1.   6.   1.   2.   3.   5.]
 [  1.   8.   1.   2.   3.   5.]]