Des baies ND aux baies 1D

141

Disons que j'ai un tableau a:

a = np.array([[1,2,3], [4,5,6]])

array([[1, 2, 3],
       [4, 5, 6]])

Je voudrais le convertir en un tableau 1D (c'est-à-dire un vecteur de colonne):

b = np.reshape(a, (1,np.product(a.shape)))

mais cela revient

array([[1, 2, 3, 4, 5, 6]])

ce qui n'est pas la même chose que:

array([1, 2, 3, 4, 5, 6])

Je peux prendre le premier élément de ce tableau pour le convertir manuellement en un tableau 1D:

b = np.reshape(a, (1,np.product(a.shape)))[0]

mais cela me demande de connaître le nombre de dimensions du tableau d'origine (et de concaténer [0] lorsque vous travaillez avec des dimensions plus élevées)

Existe-t-il un moyen indépendant des dimensions d'obtenir un vecteur colonne / ligne à partir d'un ndarray arbitraire?

Amelio Vazquez-Reina
la source

Réponses:

277

Utilisez np.ravel (pour une vue 1D) ou np.ndarray.flatten (pour une copie 1D) ou np.ndarray.flat (pour un itérateur 1D):

In [12]: a = np.array([[1,2,3], [4,5,6]])

In [13]: b = a.ravel()

In [14]: b
Out[14]: array([1, 2, 3, 4, 5, 6])

Notez que ravel()renvoie un viewde alorsque cela est possible. Donc, modifier bmodifie également a. ravel()renvoie a viewlorsque les éléments 1D sont contigus en mémoire, mais renvoie a copysi, par exemple, aont été créés en découpant un autre tableau en utilisant une taille de pas non unitaire (par exemple a = x[::2]).

Si vous voulez une copie plutôt qu'une vue, utilisez

In [15]: c = a.flatten()

Si vous voulez juste un itérateur, utilisez np.ndarray.flat:

In [20]: d = a.flat

In [21]: d
Out[21]: <numpy.flatiter object at 0x8ec2068>

In [22]: list(d)
Out[22]: [1, 2, 3, 4, 5, 6]
unutbu
la source
4
<pedantic> Dans cet exemple, ravel()renvoie une vue, mais ce n'est pas toujours vrai. Il y a des cas où ravel()renvoie une copie. </pedantic>
Warren Weckesser
3
a.ravel()semble être environ trois fois plus rapide que a.reshape(-1). a.flatten()est beaucoup plus lent, car il doit faire une copie.
BallpointBen
25
In [14]: b = np.reshape(a, (np.product(a.shape),))

In [15]: b
Out[15]: array([1, 2, 3, 4, 5, 6])

ou simplement:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])
NPE
la source
11
Peut utiliser b = a.reshape(-1)pour faire court dans le premier exemple.
Syrtis Major
5

L'un des moyens les plus simples consiste à utiliser flatten(), comme cet exemple:

 import numpy as np

 batch_y =train_output.iloc[sample, :]
 batch_y = np.array(batch_y).flatten()

Mon tableau était comme ceci:

    0
0   6
1   6
2   5
3   4
4   3
.
.
.

Après utilisation flatten():

array([6, 6, 5, ..., 5, 3, 6])

C'est aussi la solution des erreurs de ce type:

Cannot feed value of shape (100, 1) for Tensor 'input/Y:0', which has shape '(?,)' 
DINA TAKLIT
la source
4

Pour la liste des tableaux de tailles différentes, utilisez les éléments suivants:

import numpy as np

# ND array list with different size
a = [[1],[2,3,4,5],[6,7,8]]

# stack them
b = np.hstack(a)

print(b)

Production:

[1 2 3 4 5 6 7 8]

bikram
la source
comment obtiendriez-vous la forme du ados b?
dvdblk
Si vous souhaitez diviser 1D en morceaux. Voir ce stackoverflow.com/a/8495740/6117565
bikram
4

Je voulais voir un résultat de référence des fonctions mentionnées dans les réponses, y compris celles d'unutbu .

Je tiens également à souligner que numpy doc recommande d'utiliser arr.reshape(-1)au cas où la vue est préférable. (même si ravelc'est un peu plus rapide dans le résultat suivant)


TL; DR : np.ravelest le plus performant (en très petite quantité).

Référence

Les fonctions:

version numpy: '1.18.0'

Temps d'exécution sur différentes ndarraytailles

+-------------+----------+-----------+-----------+-------------+
|  function   |   10x10  |  100x100  | 1000x1000 | 10000x10000 |
+-------------+----------+-----------+-----------+-------------+
| ravel       | 0.002073 |  0.002123 |  0.002153 |    0.002077 |
| reshape(-1) | 0.002612 |  0.002635 |  0.002674 |    0.002701 |
| flatten     | 0.000810 |  0.007467 |  0.587538 |  107.321913 |
| flat        | 0.000337 |  0.000255 |  0.000227 |    0.000216 |
+-------------+----------+-----------+-----------+-------------+

Conclusion

ravelet reshape(-1)le temps d 'exécution était cohérent et indépendant de la taille de ndarray. Cependant, ravelc'est un peu plus rapide, mais reshapeoffre une flexibilité dans le remodelage de la taille. (c'est peut-être pourquoi numpy doc recommande de l'utiliser à la place. Ou il peut y avoir des cas où reshaperenvoie view et ravelnon).
Si vous avez affaire à des ndarray de grande taille, l'utilisation flattenpeut entraîner un problème de performances. Je recommande de ne pas l'utiliser. Sauf si vous avez besoin d'une copie des données pour faire autre chose.

Code utilisé

import timeit
setup = '''
import numpy as np
nd = np.random.randint(10, size=(10, 10))
'''

timeit.timeit('nd = np.reshape(nd, -1)', setup=setup, number=1000)
timeit.timeit('nd = np.ravel(nd)', setup=setup, number=1000)
timeit.timeit('nd = nd.flatten()', setup=setup, number=1000)
timeit.timeit('nd.flat', setup=setup, number=1000)
haku
la source
0

Bien que cela n'utilise pas le format de tableau np, (paresseux pour modifier mon code) cela devrait faire ce que vous voulez ... Si vous voulez vraiment un vecteur de colonne, vous voudrez transposer le résultat du vecteur. Tout dépend de la manière dont vous envisagez de l'utiliser.

def getVector(data_array,col):
    vector = []
    imax = len(data_array)
    for i in range(imax):
        vector.append(data_array[i][col])
    return ( vector )
a = ([1,2,3], [4,5,6])
b = getVector(a,1)
print(b)

Out>[2,5]

Donc, si vous avez besoin de transposer, vous pouvez faire quelque chose comme ceci:

def transposeArray(data_array):
    # need to test if this is a 1D array 
    # can't do a len(data_array[0]) if it's 1D
    two_d = True
    if isinstance(data_array[0], list):
        dimx = len(data_array[0])
    else:
        dimx = 1
        two_d = False
    dimy = len(data_array)
    # init output transposed array
    data_array_t = [[0 for row in range(dimx)] for col in range(dimy)]
    # fill output transposed array
    for i in range(dimx):
        for j in range(dimy):
            if two_d:
                data_array_t[j][i] = data_array[i][j]
            else:
                data_array_t[j][i] = data_array[j]
    return data_array_t
xcellsior
la source