web-dev-qa-db-fra.com

Le moyen le plus efficace d'inverser un tableau numpy

Croyez-le ou non, après avoir profilé mon code actuel, les opérations répétitives de réversion de tableaux numpy ont absorbé une partie gigantesque du temps d'exécution. Ce que j'ai maintenant c'est la méthode commune basée sur les vues:

reversed_arr = arr[::-1]

Y a-t-il un autre moyen de le faire plus efficacement, ou est-ce simplement une illusion de mon obsession pour des performances numpy irréalistes?

227
nye17

Lorsque vous créez reversed_arr, vous créez une vue dans le tableau d'origine. Vous pouvez ensuite modifier le tableau d'origine et la vue sera mise à jour pour refléter les modifications.

Recréez-vous la vue plus souvent que nécessaire? Vous devriez pouvoir faire quelque chose comme ça:

arr = np.array(some_sequence)
reversed_arr = arr[::-1]

do_something(arr)
look_at(reversed_arr)
do_something_else(arr)
look_at(reversed_arr)

Je ne suis pas un expert en numpy, mais cela semble être le moyen le plus rapide de faire les choses en numpy. Si c'est ce que vous faites déjà, je ne pense pas que vous puissiez l'améliorer.

P.S. Grande discussion sur les vues numpy ici:

Voir sur un tableau numpy?

196
steveha

np.fliplr() retourne le tableau de gauche à droite. 

Notez que pour les tableaux 1d, vous devez tromper un peu: 

arr1d = np.array(some_sequence)
reversed_arr = np.fliplr([arr1d])[0]
37
tooty44

Comme mentionné ci-dessus, a[::-1] ne crée en réalité qu'une vue, il s'agit donc d'une opération à temps constant (et ne prend donc pas plus de temps à mesure que le tableau s'agrandit). Si vous avez besoin que le tableau soit contigu (par exemple parce que vous effectuez de nombreuses opérations vectorielles), ascontiguousarray est à peu près aussi rapide que flipup/fliplr:

 enter image description here


Code pour générer l'intrigue:

import numpy
import perfplot


perfplot.show(
    setup=lambda n: numpy.random.randint(0, 1000, n),
    kernels=[
        lambda a: a[::-1],
        lambda a: numpy.ascontiguousarray(a[::-1]),
        lambda a: numpy.fliplr([a])[0]
        ],
    labels=['a[::-1]', 'ascontiguousarray(a[::-1])', 'fliplr'],
    n_range=[2**k for k in range(25)],
    xlabel='len(a)',
    logx=True,
    logy=True,
    )
35
Nico Schlömer

Parce que cela ne semble pas être marqué comme une réponse pour l'instant ... La réponse de Thomas Arildsen devrait être la bonne: utilisez simplement

np.flipud(your_array) 

s'il s'agit d'un tableau 1d (tableau de colonnes). 

Avec matrizes faire 

fliplr(matrix)

si vous souhaitez inverser les lignes et flipud(matrix) si vous souhaitez inverser les colonnes. Inutile de transformer votre tableau de colonnes 1d en tableau de lignes bidimensionnel (matrice avec un calque Aucun), puis de le retourner.

33
zauberfein

Je vais développer la réponse précédente à propos de np.fliplr(). Voici un code qui montre comment construire un tableau 1d, le transformant en tableau 2d, le retournant puis le reconvertissant en tableau 1d. time.clock() sera utilisé pour conserver le temps, qui est présenté en termes de secondes.

import time
import numpy as np

start = time.clock()
x = np.array(range(3))
#transform to 2d
x = np.atleast_2d(x)
#flip array
x = np.fliplr(x)
#take first (and only) element
x = x[0]
#print x
end = time.clock()
print end-start

Avec déclaration imprimée non commentée:

[2 1 0]
0.00203907123594

Avec déclaration imprimée commentée:

5.59799927506e-05

Donc, en termes d'efficacité, je pense que c'est décent. Pour ceux d'entre vous qui aiment le faire en une seule ligne, voici cette forme.

np.fliplr(np.atleast_2d(np.array(range(3))))[0]
3
M. Murphy

En développant ce que d'autres ont dit, je vais donner un exemple court.

Si vous avez un tableau 1D ...

>>> import numpy as np
>>> x = np.arange(4) # array([0, 1, 2, 3])
>>> x[::-1] # returns a view
Out[1]: 
array([3, 2, 1, 0])

Mais si vous travaillez avec un tableau 2D ...

>>> x = np.arange(10).reshape(2, 5)
>>> x
Out[2]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> x[::-1] # returns a view:
Out[3]: array([[5, 6, 7, 8, 9],
               [0, 1, 2, 3, 4]])

Cela n'inverse pas réellement la matrice.

Devrait utiliser np.flip pour inverser les éléments

>>> np.flip(x)
Out[4]: array([[9, 8, 7, 6, 5],
               [4, 3, 2, 1, 0]])

Si vous souhaitez imprimer les éléments d’une matrice un par un, utilisez-les à plat avec le flip.

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0
0
John Mil.