web-dev-qa-db-fra.com

Numpy remodèle un tableau 1d à 2d avec 1 colonne

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?

13
DevShark

Le moyen le plus simple:

ar.reshape(-1, 1)
10
KaaPex

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

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. 

3
Luca Citi

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 ] 
0
Yuval Atzmon

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
0
hpaulj