2016-02-26 13 views
15

Come posso mescolare un array multidimensionale per riga solo in Python (quindi non mescolare le colonne).Numpy shuffle array multidimensionale per riga, mantenere invariato l'ordine delle colonne

Sto cercando la soluzione più efficiente, perché la mia matrice è molto grande. È anche possibile farlo in modo estremamente efficiente sull'array originale (per risparmiare memoria)?

Esempio:

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

Cosa mi aspetto ora è matrice originale:

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

uscita mischiare le righe non cols esempio:

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

Opzione 1: vista mescolata su un array. Immagino che significherebbe un'implementazione personalizzata. (quasi) nessun impatto sull'utilizzo della memoria, Obv. un certo impatto in fase di esecuzione. Dipende davvero da come intendi usare ** questa matrice. –

+1

Opzione 2: shuffle array in posizione. 'np.random.shuffle (x)', i documenti dichiarano che "questa funzione mescola solo l'array lungo il primo indice di un array multidimensionale", che è abbastanza buono per te, giusto? Ovvero, un po 'di tempo preso all'avvio, ma da quel momento, è veloce come la matrice originale. –

+0

Confrontare con 'np.random.shuffle (x)', ** l'indice di shuffling di nd-array e ottenere dati dall'indice mescolato ** è un modo più efficiente per risolvere questo problema. Per maggiori dettagli, confrontare la mia risposta [qui sotto] (http://stackoverflow.com/questions/35646908/numpy-shuffle-multidimensional-array-by-row-only-keep-column-order-unchanged/43716153#43716153) –

risposta

13

Questo è quello che numpy.random.shuffle() è per:

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

Mi chiedo se questo potrebbe essere accelerato da numpy, forse approfittando della concorrenza. –

+0

@ GeorgSchölly Penso che questo sia l'approccio ottimizzato più disponibile in python. Se vuoi accelerarlo, devi apportare modifiche all'algoritmo. – Kasramvd

+0

Sono completamente d'accordo. Ho appena realizzato che stai usando 'np.random' invece del modulo' random' di Python che contiene anche una funzione shuffle. Mi dispiace per aver causato confusione. –

9

È possibile anche utilizzare np.random.permutation per generare permutazione casuale di indici di riga e quindi indice nelle righe di X usando np.take con axis=0. Inoltre, np.take facilita la sovrascrittura sull'array di input X con l'opzione out=, che ci farebbe risparmiare memoria. Così, l'implementazione sarebbe simile a questa -

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

Campione run -

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

prestazioni aggiuntive spinta

Ecco un trucco per accelerare np.random.permutation(X.shape[0]) con np.argsort() -

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

Spee risultati DUP -

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 

Così, la soluzione rimescolamento potrebbe essere modificato per -

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

test Runtime -

Questi test includono i due approcci elencati in questo post e np.shuffle basate uno su @Kasramvd's 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 

Così, sembra utilizzare questi np.take base potrebbe essere utilizzato solo se la memoria è una preoccupazione o altro np.random.shuffle soluzione basata appare come la strada da percorrere.

+0

Sembra carino. Puoi aggiungere un'informazione temporale al tuo post, di np.take v.s. shuffle standard? Il np.shuffle sul mio sistema è più veloce (27,9 ms) rispetto al tuo take (62,9 ms), ma come ho letto nel tuo post, c'è un vantaggio di memoria? – robert

+0

@robert Appena aggiunto, dai un'occhiata! – Divakar

1

Lo shuffle sopra (vedere la risposta Kasramvd) non funziona sempre. Per esempio.:

Esempio:

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) 

Uscite:

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.]] 
+2

'shuffle' muta i dati originali. Il suo valore di ritorno è 'Nessuno'. –

2

Dopo un esperimento bit i trovato più memoria e tempo modo efficiente per mescolare i dati (riga saggio) di Nd-array è, shuffle l'indice e ottenere i dati dall'indice mescolato

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] 

più in dettaglio
Qui, sto usando memory_profiler per trovare l'utilizzo di memoria e modulo built "tempo" di pitone per registrare il tempo e confrontando tutte le risposte precedenti

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

dei risultati per Tempo

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 

Profilo di memoria Risultato

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))) 
+0

Ciao, puoi fornire il codice che produce questo output? – omerbp

+1

ho perso il codice per produrre output [memory_profiler] (https://pypi.python.org/pypi/memory_profiler). Ma può essere riprodotto molto facilmente seguendo i passaggi nel link indicato. –