Concaténation de deux tableaux NumPy unidimensionnels


266

J'ai deux tableaux unidimensionnels simples dans NumPy . Je devrais pouvoir les concaténer en utilisant numpy.concatenate . Mais j'obtiens cette erreur pour le code ci-dessous:

TypeError: seuls les tableaux de longueur 1 peuvent être convertis en scalaires Python

Code

import numpy
a = numpy.array([1, 2, 3])
b = numpy.array([5, 6])
numpy.concatenate(a, b)

Pourquoi?


Si vous souhaitez les concaténer (en un seul tableau) le long d' un axe, utilisez np.concatenat(..., axis). Si vous souhaitez les empiler verticalement, utilisez np.vstack. Si vous souhaitez les empiler (en plusieurs tableaux) horizontalement, utilisez np.hstack. (Si vous voulez les empiler en profondeur, c'est-à-dire la 3ème dimension, utilisez np.dstack). Notez que ces derniers sont similaires aux pandaspd.concat
smci

Réponses:


372

La ligne doit être:

numpy.concatenate([a,b])

Les tableaux que vous souhaitez concaténer doivent être transmis sous forme de séquence, et non sous forme d'arguments distincts.

De la documentation NumPy :

numpy.concatenate((a1, a2, ...), axis=0)

Joignez une séquence de tableaux ensemble.

Il essayait d'interpréter votre bcomme paramètre d'axe, c'est pourquoi il se plaignait de ne pas pouvoir le convertir en scalaire.


1
Merci! juste curieux - quelle est la logique derrière cela?
user391339

8
@ user391339, et si vous vouliez concaténer trois tableaux? La fonction est plus utile pour prendre une séquence que si elle ne prenait que deux tableaux.
Winston Ewert

@WinstonEwert En supposant que le problème n'est pas qu'il est codé en dur avec deux arguments, vous pouvez l'utiliser comme numpy.concatenate(a1, a2, a3)ou numpy.concatenate(*[a1, a2, a3])si vous préférez. Python est suffisamment fluide pour que la différence finisse par être plus esthétique que substantielle, mais c'est bien lorsque l'API est cohérente (par exemple, si toutes les fonctions numpy qui prennent des listes d'arguments de longueur variable nécessitent des séquences explicites).
Jim K.

@JimK. Qu'arriverait-il au paramètre d'axe?
Winston Ewert

1
En supposant que les éléments à concaténer sont tous des paramètres positionnels, vous pouvez conserver l'axe comme argument de mot clé, par exemple def concatx(*sequences, **kwargs)). Ce n'est pas idéal car vous ne pouvez pas sembler nommer explicitement le mot-clé args dans la signature, mais il existe des solutions de contournement.
Jim K.

37

Il existe plusieurs possibilités de concaténation de tableaux 1D, par exemple,

numpy.r_[a, a],
numpy.stack([a, a]).reshape(-1),
numpy.hstack([a, a]),
numpy.concatenate([a, a])

Toutes ces options sont également rapides pour les grands tableaux; pour les petits, concatenatea un léger avantage:

entrez la description de l'image ici

L'intrigue a été créée avec perfplot :

import numpy
import perfplot

perfplot.show(
    setup=lambda n: numpy.random.rand(n),
    kernels=[
        lambda a: numpy.r_[a, a],
        lambda a: numpy.stack([a, a]).reshape(-1),
        lambda a: numpy.hstack([a, a]),
        lambda a: numpy.concatenate([a, a]),
    ],
    labels=["r_", "stack+reshape", "hstack", "concatenate"],
    n_range=[2 ** k for k in range(19)],
    xlabel="len(a)",
)

9
Les alternatives utilisent toutes np.concatenate. Ils massent simplement la liste d'entrée de différentes manières avant la main. np.stackpar exemple, ajoute une dimension supplémentaire à tous les tableaux d'entrée. Regardez leur code source. Seul concatenateest compilé.
hpaulj

1
Juste pour ajouter au commentaire de @hpaulj - les temps convergent tous au fur et à mesure que la taille des tableaux augmente, car cela np.concatenatefait des copies des entrées. Ce coût en mémoire et en temps l'emporte alors sur le temps passé à «masser» l'entrée.
n1k31t4

31

Le premier paramètre à concatenatelui-même devrait être une séquence de tableaux à concaténer:

numpy.concatenate((a,b)) # Note the extra parentheses.

10

Une alternative est d'utiliser la forme courte de "concaténer" qui est soit "r _ [...]" ou "c _ [...]" comme indiqué dans l'exemple de code ci-dessous (voir http://wiki.scipy.org / NumPy_for_Matlab_Users pour plus d'informations):

%pylab
vector_a = r_[0.:10.] #short form of "arange"
vector_b = array([1,1,1,1])
vector_c = r_[vector_a,vector_b]
print vector_a
print vector_b
print vector_c, '\n\n'

a = ones((3,4))*4
print a, '\n'
c = array([1,1,1])
b = c_[a,c]
print b, '\n\n'

a = ones((4,3))*4
print a, '\n'
c = array([[1,1,1]])
b = r_[a,c]
print b

print type(vector_b)

Ce qui se traduit par:

[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.]
[1 1 1 1]
[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.  1.  1.  1.  1.] 


[[ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]] 

[[ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]] 


[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]] 

[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 1.  1.  1.]]

2
vector_b = [1,1,1,1] #short form of "array", ce n'est tout simplement pas vrai. vector_b sera un type de liste Python standard. Numpy est cependant assez bon pour accepter des séquences au lieu de forcer toutes les entrées à être de type numpy.array.
Hannes Ovrén

2
Vous avez raison - j'avais tort. J'ai corrigé mon code source ainsi que le résultat.
Semjon Mössinger

0

Voici des approches plus pour le faire en utilisant numpy.ravel(), numpy.array(), en utilisant le fait que les tableaux 1D peut être décompressé en éléments simples:

# we'll utilize the concept of unpacking
In [15]: (*a, *b)
Out[15]: (1, 2, 3, 5, 6)

# using `numpy.ravel()`
In [14]: np.ravel((*a, *b))
Out[14]: array([1, 2, 3, 5, 6])

# wrap the unpacked elements in `numpy.array()`
In [16]: np.array((*a, *b))
Out[16]: array([1, 2, 3, 5, 6])

0

Quelques faits supplémentaires à partir des documents numpy :

Avec la syntaxe as numpy.concatenate((a1, a2, ...), axis=0, out=None)

axe = 0 pour la concaténation en ligne axe = 1 pour la concaténation en colonne

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

# Appending below last row
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])

# Appending after last column
>>> np.concatenate((a, b.T), axis=1)    # Notice the transpose
array([[1, 2, 5],
       [3, 4, 6]])

# Flattening the final array
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])

J'espère que ça aide!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.