Dans numpy
, les dimensions du tableau résultant varient au moment de l'exécution . Il y a souvent confusion entre un tableau 1d et un tableau 2d avec 1 colonne . Dans un cas, je peux parcourir les colonnes, dans l'autre cas ne peux pas.
Comment résolvez-vous ce problème avec élégance? Pour éviter de surcharger mon code d'instructions if
lors de la vérification de la dimensionnalité, j'utilise cette fonction:
def reshape_to_vect(ar):
if len(ar.shape) == 1:
return ar.reshape(ar.shape[0],1)
return ar
Cependant, cela semble inélégant et coûteux. Y a-t-il une meilleure solution?
Le moyen le plus simple:
ar.reshape(-1, 1)
Vous pourriez faire -
ar.reshape(ar.shape[0],-1)
Cette deuxième entrée dans reshape
: -1
prend en charge le nombre d'éléments pour le deuxième axe. Ainsi, pour un cas de saisie 2D
, cela ne change pas. Pour un cas de saisie 1D
, il crée un tableau 2D
avec tous les éléments étant "poussés" sur le premier axe en raison de ar.shape[0]
, qui correspond au nombre total d'éléments.
Exemples d'essais
Cas 1D:
In [87]: ar
Out[87]: array([ 0.80203158, 0.25762844, 0.67039516, 0.31021513, 0.80701097])
In [88]: ar.reshape(ar.shape[0],-1)
Out[88]:
array([[ 0.80203158],
[ 0.25762844],
[ 0.67039516],
[ 0.31021513],
[ 0.80701097]])
Cas 2D:
In [82]: ar
Out[82]:
array([[ 0.37684126, 0.16973899, 0.82157815, 0.38958523],
[ 0.39728524, 0.03952238, 0.04153052, 0.82009233],
[ 0.38748174, 0.51377738, 0.40365096, 0.74823535]])
In [83]: ar.reshape(ar.shape[0],-1)
Out[83]:
array([[ 0.37684126, 0.16973899, 0.82157815, 0.38958523],
[ 0.39728524, 0.03952238, 0.04153052, 0.82009233],
[ 0.38748174, 0.51377738, 0.40365096, 0.74823535]])
Une variante de la réponse par divakar est: x = np.reshape(x, (len(x),-1))
, qui traite également le cas où l'entrée est une liste 1d ou 2d.
Pour éviter le besoin de refaçonner en premier lieu, si vous découpez une ligne/colonne avec une liste ou une tranche "en cours d'exécution", vous obtiendrez un tableau 2D avec une ligne/colonne.
import numpy as np
x = np.array(np.random.normal(size=(4,4)))
print x, '\n'
Result:
[[ 0.01360395 1.12130368 0.95429414 0.56827029]
[-0.66592215 1.04852182 0.20588886 0.37623406]
[ 0.9440652 0.69157556 0.8252977 -0.53993904]
[ 0.6437994 0.32704783 0.52523173 0.8320762 ]]
y = x[:,[0]]
print y, 'col vector \n'
Result:
[[ 0.01360395]
[-0.66592215]
[ 0.9440652 ]
[ 0.6437994 ]] col vector
y = x[[0],:]
print y, 'row vector \n'
Result:
[[ 0.01360395 1.12130368 0.95429414 0.56827029]] row vector
# Slice with "running" index on a column
y = x[:,0:1]
print y, '\n'
Result:
[[ 0.01360395]
[-0.66592215]
[ 0.9440652 ]
[ 0.6437994 ]]
Si vous utilisez un nombre unique pour choisir la ligne/colonne, vous obtenez un tableau 1D, qui est la cause première de votre problème:
y = x[:,0]
print y, '\n'
Result:
[ 0.01360395 -0.66592215 0.9440652 0.6437994 ]
J'ai posé des questions sur dtype
parce que votre exemple est déroutant.
Je peux faire un tableau structuré avec 3 éléments (1d) et 3 champs:
In [1]: A = np.ones((3,), dtype='i,i,i')
In [2]: A
Out[2]:
array([(1, 1, 1), (1, 1, 1), (1, 1, 1)],
dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
Je peux accéder à un champ par son nom (l'ajout de crochets ne change rien)
In [3]: A['f0'].shape
Out[3]: (3,)
mais si j'accède à 2 champs, j'obtiens toujours un tableau 1d
In [4]: A[['f0','f1']].shape
Out[4]: (3,)
In [5]: A[['f0','f1']]
Out[5]:
array([(1, 1), (1, 1), (1, 1)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
En fait, ces crochets supplémentaires comptent, si je regarde les valeurs
In [22]: A['f0']
Out[22]: array([1, 1, 1], dtype=int32)
In [23]: A[['f0']]
Out[23]:
array([(1,), (1,), (1,)],
dtype=[('f0', '<i4')])
Si le tableau est simple en 2D, je ne comprends toujours pas vos formes
In [24]: A=np.ones((3,3),int)
In [25]: A[0].shape
Out[25]: (3,)
In [26]: A[[0]].shape
Out[26]: (1, 3)
In [27]: A[[0,1]].shape
Out[27]: (2, 3)
Mais quant à la question de s’assurer qu’un tableau est 2d, que l’indexation retourne 1d ou 2, votre fonction est fondamentalement ok
def reshape_to_vect(ar):
if len(ar.shape) == 1:
return ar.reshape(ar.shape[0],1)
return ar
Vous pouvez tester ar.ndim
au lieu de len(ar.shape)
. Mais de toute façon, cela n’est pas coûteux - c’est-à-dire que le temps d’exécution est minime - pas d’opérations de grande taille. reshape
ne copie pas les données (à moins que vos progrès ne soient bizarres). Il ne s'agit donc que du coût de création d'un nouvel objet tableau avec un pointeur de données partagé.
Regardez le code pour np.atleast_2d
; il teste pour 0d et 1d. Dans le cas 1d, il retourne result = ary[newaxis,:]
. Il ajoute d'abord l'axe supplémentaire, l'emplacement numpy
plus naturel pour l'ajout d'un axe. Vous l'ajoutez à la fin.
ar.reshape(ar.shape[0],-1)
est un moyen astucieux de contourner le test if
. Dans les petits délais, le test est plus rapide, mais nous parlons de microsecondes, l’effet d’une couche d’appel de fonction.
np.column_stack
est une autre fonction qui crée des tableaux de colonnes si nécessaire. Il utilise:
if arr.ndim < 2:
arr = array(arr, copy=False, subok=True, ndmin=2).T