Concatenando duas matrizes NumPy unidimensionais

266

Eu tenho duas matrizes unidimensionais simples no NumPy . Eu deveria ser capaz de concatená-los usando numpy.concatenate . Mas recebo este erro para o código abaixo:

TypeError: somente matrizes de comprimento 1 podem ser convertidas em escalares Python

Código

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

Por quê?

alta largura de banda
fonte
Se você deseja concatená-los (em uma única matriz) ao longo de um eixo, use np.concatenat(..., axis). Se você deseja empilhá-los verticalmente, use np.vstack. Se você deseja empilhá-los (em várias matrizes) horizontalmente, use np.hstack. (Se você quiser empilhá-los em profundidade, ou seja, na 3ª dimensão, use np.dstack). Observe que os últimos são semelhantes aos pandaspd.concat
smci em

Respostas:

372

A linha deve ser:

numpy.concatenate([a,b])

As matrizes que você deseja concatenar precisam ser transmitidas como uma sequência, não como argumentos separados.

Na documentação do NumPy :

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

Una uma sequência de matrizes.

Ele estava tentando interpretar o seu bcomo o parâmetro do eixo, e é por isso que reclamou que não podia convertê-lo em um escalar.

Winston Ewert
fonte
1
obrigado! apenas curioso - qual é a lógica por trás disso?
user391339
8
@ user391339, e se você quisesse concatenar três matrizes? A função é mais útil na tomada de uma sequência do que se tiver apenas duas matrizes.
Winston Ewert
@WinstonEwert Supondo que o problema não seja codificado em dois argumentos, você pode usá-lo como numpy.concatenate(a1, a2, a3)ou numpy.concatenate(*[a1, a2, a3])se preferir. O Python é suficientemente fluido para que a diferença pareça mais cosmética do que substancial, mas é bom quando a API é consistente (por exemplo, se todas as funções numpy que usam listas de argumentos de comprimento variável exigem sequências explícitas).
Jim K.
@JimK. O que aconteceria com o parâmetro do eixo?
Winston Ewert
1
Supondo que as coisas a concatenar sejam todos parâmetros posicionais, você pode manter o eixo como argumento de palavra-chave, por exemplo def concatx(*sequences, **kwargs)). Não é o ideal, pois você não consegue nomear explicitamente a palavra-chave args na assinatura dessa maneira, mas existem soluções alternativas.
Jim K.
37

Existem várias possibilidades para concatenar matrizes 1D, por exemplo,

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

Todas essas opções são igualmente rápidas para matrizes grandes; para os pequenos, concatenatetem uma ligeira vantagem:

insira a descrição da imagem aqui

A plotagem foi criada com 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)",
)
Nico Schlömer
fonte
9
As alternativas que todos usam np.concatenate. Eles apenas massageiam a lista de entrada de várias maneiras antes da mão. np.stackpor exemplo, adiciona uma dimensão extra a todas as matrizes de entrada. Veja o código fonte deles. Somente concatenateé compilado.
Hpaulj
1
Apenas para adicionar ao comentário de @hpaulj - todos os tempos convergem à medida que o tamanho das matrizes aumenta porque np.concatenatefaz cópias das entradas. Esse custo de memória e tempo supera o tempo gasto 'massageando' a entrada.
N1k31t4 9/0318
31

O primeiro parâmetro a concatenatedeve ser uma sequência de matrizes para concatenar:

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

Uma alternativa é usar a forma abreviada de "concatenar", que é "r _ [...]" ou "c _ [...]", conforme mostrado no código de exemplo abaixo (consulte http://wiki.scipy.org / NumPy_for_Matlab_Users para informações adicionais):

%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)

O que resulta em:

[ 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.]]
Semjon Mössinger
fonte
2
vector_b = [1,1,1,1] #short form of "array", Isto simplesmente não é verdade. vector_b será um tipo de lista padrão do Python. No entanto, o Numpy é muito bom em aceitar seqüências em vez de forçar todas as entradas a serem tipos numpy.array.
Hannes Ovrén
2
Você está certo - eu estava errado. Corrigi meu código fonte e o resultado.
Semjon Mössinger
0

Aqui estão mais abordagens para fazer isso usando numpy.ravel(), numpy.array()utilizando o fato de que as matrizes 1D podem ser descompactadas em elementos 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])
kmario23
fonte
0

Mais alguns fatos dos documentos numpy :

Com sintaxe como numpy.concatenate((a1, a2, ...), axis=0, out=None)

eixo = 0 para concatenação em linha eixo = 1 para concatenação em coluna

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

Espero que ajude !

Pedro
fonte