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