web-dev-qa-db-fra.com

Numpy shuffle tableau multidimensionnel par ligne uniquement, conservez l'ordre des colonnes

Comment puis-je mélanger un tableau multidimensionnel par ligne uniquement en Python (afin de ne pas mélanger les colonnes).

Je cherche la solution la plus efficace, car ma matrice est très énorme. Est-il également possible de faire cela très efficacement sur le tableau d'origine (pour économiser de la mémoire)?  

Exemple:

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

Ce que j'attends maintenant, c'est la matrice d'origine:

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

La sortie mélange les lignes et non les colonnes, par exemple:

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

C'est ce que numpy.random.shuffle() est pour:

>>> 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]])
25
Kasrâmvd

Vous pouvez également utiliser np.random.permutation pour générer une permutation aléatoire des index de ligne, puis indexer dans les lignes de X à l’aide de np.take avec axis=0. De plus, np.take facilite l'écriture sur le tableau d'entrée X avec l'option out=, ce qui nous permettrait d'économiser de la mémoire. Ainsi, la mise en œuvre ressemblerait à ceci -

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

Exemple de cycle -

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

Augmentation de la performance supplémentaire

Voici une astuce pour accélérer np.random.permutation(X.shape[0]) avec np.argsort() -

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

Résultats d'accélération -

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

Ainsi, la solution de brassage pourrait être modifiée pour -

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

Tests d'exécution -

Ces tests incluent les deux approches énumérées dans cet article et l'une basée sur np.shuffle dans @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

Donc, il semble que l'utilisation de ces np.take pourrait ne être utilisée que si la mémoire est une préoccupation ou sinon la solution basée sur np.random.shuffle semble être la voie à suivre.

19
Divakar

Après un peu d'expérience, j'ai trouvé le moyen le plus efficace en termes de mémoire et de temps pour mélanger les données (rangée) de nd-array, mélanger l'index et obtenir les données de l'index mélangé.

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]

en plus de détails
Ici, j'utilise memory_profiler pour trouver l'utilisation de la mémoire et le module "time" intégré de python pour enregistrer le temps et comparer toutes les réponses précédentes

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

Résultat pour le temps

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

Profileur de mémoire Résultat

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)))
5
Janmejaya Nanda

Vous pouvez mélanger un tableau à deux dimensions par ligne en utilisant la fonction np.vectorize(), comme ceci: 

shuffle = np.vectorize(np.random.permutation, signature='(n)->(n)')
1
Ben-Hur Cardoso