web-dev-qa-db-fra.com

Échange des dimensions d'un tableau numpy

Je voudrais faire ce qui suit:

for i in dimension1:
  for j in dimension2:
    for k in dimension3:
      for l in dimension4:
        B[k,l,i,j] = A[i,j,k,l]

sans utiliser de boucles. En fin de compte, A et B contiennent les mêmes informations mais indexées différemment.

Je dois souligner que les dimensions 1, 2, 3 et 4 peuvent être identiques ou différentes. Un numpy.reshape () semble donc difficile.

28
sponce

Veuillez noter: la réponse de Jaime est mieux. NumPy fournit np.transpose précisément à cet effet.


Ou utilisez np.einsum ; c'est peut-être une perversion de son objectif, mais la syntaxe est plutôt sympa:

In [195]: A = np.random.random((2,4,3,5))

In [196]: B = np.einsum('klij->ijkl', A)

In [197]: A.shape
Out[197]: (2, 4, 3, 5)

In [198]: B.shape
Out[198]: (3, 5, 2, 4)

In [199]: import itertools as IT    
In [200]: all(B[k,l,i,j] == A[i,j,k,l] for i,j,k,l in IT.product(*map(range, A.shape)))
Out[200]: True
21
unutbu

La manière canonique de le faire en numpy serait d'utiliser np.transpose argument de permutation facultatif. Dans votre cas, pour passer de ijkl à klij, la permutation est (2, 3, 0, 1), par exemple.:

In [16]: a = np.empty((2, 3, 4, 5))

In [17]: b = np.transpose(a, (2, 3, 0, 1))

In [18]: b.shape
Out[18]: (4, 5, 2, 3)
56
Jaime

Vous pourriez rollaxis deux fois:

>>> A = np.random.random((2,4,3,5))
>>> B = np.rollaxis(np.rollaxis(A, 2), 3, 1)
>>> A.shape
(2, 4, 3, 5)
>>> B.shape
(3, 5, 2, 4)
>>> from itertools import product
>>> all(B[k,l,i,j] == A[i,j,k,l] for i,j,k,l in product(*map(range, A.shape)))
True

ou peut-être swapaxes deux fois est plus facile à suivre:

>>> A = np.random.random((2,4,3,5))
>>> C = A.swapaxes(0, 2).swapaxes(1,3)
>>> C.shape
(3, 5, 2, 4)
>>> all(C[k,l,i,j] == A[i,j,k,l] for i,j,k,l in product(*map(range, A.shape)))
True
11
DSM

Je regarderais numpy.ndarray.shape et itertools.product:

import numpy, itertools
A = numpy.ones((10,10,10,10))
B = numpy.zeros((10,10,10,10))

for i, j, k, l in itertools.product(*map(xrange, A.shape)):
    B[k,l,i,j] = A[i,j,k,l]

Par "sans utiliser de boucles", je suppose que vous voulez dire "sans utiliser de boucles imbriquées", bien sûr. À moins qu'il y ait un certain numpy intégré qui le fasse, je pense que c'est votre meilleur pari.

2
metaperture

On peut également utiliser numpy.moveaxis() pour se déplacer les axes requis aux emplacements souhaités. Voici une illustration, volant l'exemple de réponse de Jaime :

In [160]: a = np.empty((2, 3, 4, 5))

# move the axes that are originally at positions [0, 1] to [2, 3]
In [161]: np.moveaxis(a, [0, 1], [2, 3]).shape 
Out[161]: (4, 5, 2, 3)
1
kmario23