Como adicionar uma coluna extra a uma matriz NumPy

292

Digamos que eu tenho uma matriz NumPy a:

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

E eu gostaria de adicionar uma coluna de zeros para obter uma matriz b:

b = np.array([
    [1, 2, 3, 0],
    [2, 3, 4, 0]
    ])

Como posso fazer isso facilmente no NumPy?

Peter Smit
fonte

Respostas:

181

Eu acho que uma solução mais direta e mais rápida de inicializar é fazer o seguinte:

import numpy as np
N = 10
a = np.random.rand(N,N)
b = np.zeros((N,N+1))
b[:,:-1] = a

E horários:

In [23]: N = 10

In [24]: a = np.random.rand(N,N)

In [25]: %timeit b = np.hstack((a,np.zeros((a.shape[0],1))))
10000 loops, best of 3: 19.6 us per loop

In [27]: %timeit b = np.zeros((a.shape[0],a.shape[1]+1)); b[:,:-1] = a
100000 loops, best of 3: 5.62 us per loop
JoshAdel
fonte
16
Eu quero acrescentar (985,1) forma np araay a (985,2) np array para torná-lo (985,3) np array, mas não está funcionando. Estou recebendo o erro "não foi possível transmitir a matriz de entrada da forma (985) para a forma (985,1)". o que está errado com meu código? Código: np.hstack (data, data1)
Outlier
5
@Outlier, você deve postar uma nova pergunta em vez de fazer uma nos comentários desta.
JoshAdel
4
@ JosAdel: Eu tentei seu código no ipython, e acho que há um erro de sintaxe. Você pode tentar mudar a = np.random.rand((N,N))paraa = np.random.rand(N,N)
hlin117 11/11/2015
Eu acho que isso é um exagero para o que o OP pediu. A resposta do Op é adequada!
Lft93ryt 26/0917
Este é apenas um truque para executar anexar, inserir ou empilhar. e não deve ser aceito como respostas. Os engenheiros devem considerar usar as respostas abaixo.
cinqS
326

np.r_[ ... ]e np.c_[ ... ] são alternativas úteis para vstacke hstack, com colchetes [] em vez de redondo ().
Alguns exemplos:

: import numpy as np
: N = 3
: A = np.eye(N)

: np.c_[ A, np.ones(N) ]              # add a column
array([[ 1.,  0.,  0.,  1.],
       [ 0.,  1.,  0.,  1.],
       [ 0.,  0.,  1.,  1.]])

: np.c_[ np.ones(N), A, np.ones(N) ]  # or two
array([[ 1.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  1.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  1.]])

: np.r_[ A, [A[1]] ]              # add a row
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  1.,  0.]])
: # not np.r_[ A, A[1] ]

: np.r_[ A[0], 1, 2, 3, A[1] ]    # mix vecs and scalars
  array([ 1.,  0.,  0.,  1.,  2.,  3.,  0.,  1.,  0.])

: np.r_[ A[0], [1, 2, 3], A[1] ]  # lists
  array([ 1.,  0.,  0.,  1.,  2.,  3.,  0.,  1.,  0.])

: np.r_[ A[0], (1, 2, 3), A[1] ]  # tuples
  array([ 1.,  0.,  0.,  1.,  2.,  3.,  0.,  1.,  0.])

: np.r_[ A[0], 1:4, A[1] ]        # same, 1:4 == arange(1,4) == 1,2,3
  array([ 1.,  0.,  0.,  1.,  2.,  3.,  0.,  1.,  0.])

(A razão para colchetes [] em vez de round () é que o Python expande, por exemplo, 1: 4 em quadrado - as maravilhas da sobrecarga.)

denis
fonte
7
apenas estava à procura de informações sobre isso, e definitivamente esta é uma resposta melhor do que a aceita, porque abrange adicionando uma coluna extra no início e no final, não apenas no final como as outras respostas
Ay0
2
@ Ay0 Exatamente, eu estava procurando uma maneira de adicionar uma unidade de viés à minha rede neuronal artificial em lotes em todas as camadas ao mesmo tempo, e esta é a resposta perfeita.
gaborous 18/08/16
E se você quiser adicionar n colunas ao mesmo tempo?
Riley
1
@Riley, você pode dar um exemplo, por favor? O Python 3 tem "descompactação iterável", por exemplo np.c_[ * iterable ]; veja listas de expressões .
Denis
@denis, era exatamente o que eu estava procurando!
Riley
148

Use numpy.append:

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

>>> z = np.zeros((2,1), dtype=int64)
>>> z
array([[0],
       [0]])

>>> np.append(a, z, axis=1)
array([[1, 2, 3, 0],
       [2, 3, 4, 0]])
gemy
fonte
3
Isso é bom ao inserir colunas mais complicadas.
Thomas Ahle
6
Isso é mais direto do que a resposta de @JoshAdel, mas ao lidar com grandes conjuntos de dados, é mais lento. Eu escolheria entre os dois, dependendo da importância da legibilidade.
DVJ
3
appendna verdade apenas chamaconcatenate
rll
53

Uma maneira, usando o hstack , é:

b = np.hstack((a, np.zeros((a.shape[0], 1), dtype=a.dtype)))
Peter Smit
fonte
2
Eu acho que essa é a solução mais elegante.
Silvado
2
+1 - é assim que eu faria - você me venceu em publicá-la como resposta :).
Blair
3
Remova o dtypeparâmetro, ele não é necessário e nem mesmo permitido. Embora sua solução seja elegante o suficiente, preste atenção para não usá-la se precisar "anexar" frequentemente a uma matriz. Se você não pode criar toda a matriz de uma só vez e preenchê-la mais tarde, crie uma lista de matrizes e hstacktudo de uma só vez.
eumiro
1
@eumiro Eu não sei como eu consegui obter o dtipo no local errado, mas os np.zeros precisa de um dtipo evitar tudo se tornando float (enquanto um é int)
Peter Smit
42

Acho o seguinte mais elegante:

b = np.insert(a, 3, values=0, axis=1) # Insert values before column 3

Uma vantagem insertdisso é que ele também permite inserir colunas (ou linhas) em outros lugares dentro da matriz. Além disso, em vez de inserir um único valor, você pode inserir facilmente um vetor inteiro, por exemplo, duplicar a última coluna:

b = np.insert(a, insert_index, values=a[:,2], axis=1)

O que leva a:

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

No momento, insertpode ser mais lento que a solução de JoshAdel:

In [1]: N = 10

In [2]: a = np.random.rand(N,N)

In [3]: %timeit b = np.hstack((a, np.zeros((a.shape[0], 1))))
100000 loops, best of 3: 7.5 µs per loop

In [4]: %timeit b = np.zeros((a.shape[0], a.shape[1]+1)); b[:,:-1] = a
100000 loops, best of 3: 2.17 µs per loop

In [5]: %timeit b = np.insert(a, 3, values=0, axis=1)
100000 loops, best of 3: 10.2 µs per loop
Björn
fonte
1
Isso é bem legal. Pena que não posso fazer insert(a, -1, ...)para anexar a coluna. Acho que vou acrescentá-lo antes.
Thomas Ahle
2
@ThomasAhle Você pode anexar uma linha ou coluna obtendo o tamanho nesse eixo usando a.shape[axis]. I. e. para anexar uma linha, você faz np.insert(a, a.shape[0], 999, axis=0)e para uma coluna, você faz np.insert(a, a.shape[1], 999, axis=1).
precisa saber é o seguinte
35

Eu também estava interessado nesta questão e comparei a velocidade da

numpy.c_[a, a]
numpy.stack([a, a]).T
numpy.vstack([a, a]).T
numpy.ascontiguousarray(numpy.stack([a, a]).T)               
numpy.ascontiguousarray(numpy.vstack([a, a]).T)
numpy.column_stack([a, a])
numpy.concatenate([a[:,None], a[:,None]], axis=1)
numpy.concatenate([a[None], a[None]], axis=0).T

que todos fazem a mesma coisa para qualquer vetor de entrada a. Horários para o cultivo a:

insira a descrição da imagem aqui

Observe que todas as variantes não contíguas (em particular stack/ vstack) são eventualmente mais rápidas que todas as variantes contíguas. column_stack(por sua clareza e velocidade) parece ser uma boa opção se você precisar de contiguidade.


Código para reproduzir o gráfico:

import numpy
import perfplot

perfplot.save(
    "out.png",
    setup=lambda n: numpy.random.rand(n),
    kernels=[
        lambda a: numpy.c_[a, a],
        lambda a: numpy.ascontiguousarray(numpy.stack([a, a]).T),
        lambda a: numpy.ascontiguousarray(numpy.vstack([a, a]).T),
        lambda a: numpy.column_stack([a, a]),
        lambda a: numpy.concatenate([a[:, None], a[:, None]], axis=1),
        lambda a: numpy.ascontiguousarray(
            numpy.concatenate([a[None], a[None]], axis=0).T
        ),
        lambda a: numpy.stack([a, a]).T,
        lambda a: numpy.vstack([a, a]).T,
        lambda a: numpy.concatenate([a[None], a[None]], axis=0).T,
    ],
    labels=[
        "c_",
        "ascont(stack)",
        "ascont(vstack)",
        "column_stack",
        "concat",
        "ascont(concat)",
        "stack (non-cont)",
        "vstack (non-cont)",
        "concat (non-cont)",
    ],
    n_range=[2 ** k for k in range(20)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)
Nico Schlömer
fonte
1
Bom gráfico! Só pensei que você gostaria de saber que sob o capô, stack, hstack, vstack, column_stack, dstacksão todas as funções auxiliares construídas em cima de np.concatenate. Ao rastrear a definição de pilha , descobri que np.stack([a,a])está chamando np.concatenate([a[None], a[None]], axis=0). Pode ser bom adicionar np.concatenate([a[None], a[None]], axis=0).Tao perfplot para mostrar que np.concatenatesempre pode ser pelo menos tão rápido quanto suas funções auxiliares.
unutbu 6/09/17
@unutbu Adicionado isso.
Nico Schlömer
Biblioteca agradável, nunca ouvi falar disso! Interessante o suficiente para que eu tenha exatamente os mesmos gráficos, exceto que stack e concat mudaram de lugar (nas variantes ascont e non-cont). Além disso, concat-column e column_stack também foram trocados.
Antony Hatchkins
1
Uau, adoro esses enredos!
jhegedus
Parece que, para uma operação recursiva de anexar uma coluna a uma matriz, por exemplo, b = [b, a], alguns dos comandos não funcionam (um erro sobre dimensões desiguais é gerado). Os únicos dois que parecem funcionar com matrizes de tamanho desigual (isto é, quando um é uma matriz e outro é um vetor 1d) são c_ecolumn_stack
Confundidos
29

Eu acho que:

np.column_stack((a, zeros(shape(a)[0])))

é mais elegante.

user2820502
fonte
12

O np.concatenate também funciona

>>> a = np.array([[1,2,3],[2,3,4]])
>>> a
array([[1, 2, 3],
       [2, 3, 4]])
>>> z = np.zeros((2,1))
>>> z
array([[ 0.],
       [ 0.]])
>>> np.concatenate((a, z), axis=1)
array([[ 1.,  2.,  3.,  0.],
       [ 2.,  3.,  4.,  0.]])
han4wluc
fonte
np.concatenateparece ser 3 vezes mais rápido que np.hstacknas matrizes 2x1, 2x2 e 2x3. np.concatenatetambém foi muito mais rápido do que copiar manualmente as matrizes para uma matriz vazia nas minhas experiências. Isso é consistente com a resposta de Nico Schlömer abaixo.
Lenar Hoyt 28/05
11

Supondo que Mé um ndarray (100,3) e yé um ndarray (100,) appendpode ser usado da seguinte maneira:

M=numpy.append(M,y[:,None],1)

O truque é usar

y[:, None]

Isso se converte yem uma matriz 2D (100, 1).

M.shape

agora dá

(100, 4)
Roel Verhoeven
fonte
Você é um herói, você sabe disso ?! É exatamente isso que estou puxando meu cabelo nas últimas 1 hora! Ty!
John Doe
8

Eu gosto da resposta de JoshAdel por causa do foco no desempenho. Uma pequena melhoria no desempenho é evitar a sobrecarga de inicializar com zeros, apenas para ser substituída. Isso tem uma diferença mensurável quando N é grande, vazio é usado em vez de zeros e a coluna de zeros é escrita como uma etapa separada:

In [1]: import numpy as np

In [2]: N = 10000

In [3]: a = np.ones((N,N))

In [4]: %timeit b = np.zeros((a.shape[0],a.shape[1]+1)); b[:,:-1] = a
1 loops, best of 3: 492 ms per loop

In [5]: %timeit b = np.empty((a.shape[0],a.shape[1]+1)); b[:,:-1] = a; b[:,-1] = np.zeros((a.shape[0],))
1 loops, best of 3: 407 ms per loop
toddInPortland
fonte
Você pode usar a transmissão para preencher a última coluna com zeros (ou qualquer outro valor), o que pode ser mais legível: b[:,-1] = 0. Além disso, com matrizes muito grandes, a diferença de desempenho se np.insert()torna insignificante, o que pode ser np.insert()mais desejável devido à sua sucessão.
precisa saber é o seguinte
7

np.insert também serve ao propósito.

matA = np.array([[1,2,3], 
                 [2,3,4]])
idx = 3
new_col = np.array([0, 0])
np.insert(matA, idx, new_col, axis=1)

array([[1, 2, 3, 0],
       [2, 3, 4, 0]])

Ele insere valores, aqui new_col, antes de um determinado índice, aqui idxao longo de um eixo. Em outras palavras, os novos valores inseridos ocuparão a idxcoluna e moverão o que estava originalmente lá no e depois idxpara trás.

Tai
fonte
1
Observe que insertnão está no lugar, como se poderia assumir, com o nome da função (consulte os documentos vinculados na resposta).
Jneuendorf 27/07/19
5

Adicione uma coluna extra a uma matriz numpy:

O np.appendmétodo de Numpy usa três parâmetros, os dois primeiros são matrizes numpy 2D e o terceiro é um parâmetro de eixo que instrui ao longo de qual eixo acrescentar:

import numpy as np  
x = np.array([[1,2,3], [4,5,6]]) 
print("Original x:") 
print(x) 

y = np.array([[1], [1]]) 
print("Original y:") 
print(y) 

print("x appended to y on axis of 1:") 
print(np.append(x, y, axis=1)) 

Impressões:

Original x:
[[1 2 3]
 [4 5 6]]
Original y:
[[1]
 [1]]
x appended to y on axis of 1:
[[1 2 3 1]
 [4 5 6 1]]
Hassan Bahaloo
fonte
Observe que você anexa y a x aqui em vez de anexar x a y - é por isso que o vetor da coluna de y está à direita das colunas de x no resultado.
Brian Popeck
4

Um pouco atrasado para a festa, mas ninguém postou esta resposta ainda, por uma questão de integridade: você pode fazer isso com a compreensão da lista, em uma matriz Python simples:

source = a.tolist()
result = [row + [0] for row in source]
b = np.array(result)
BTK
fonte
4

Para mim, a próxima maneira parece bastante intuitiva e simples.

zeros = np.zeros((2,1)) #2 is a number of rows in your array.   
b = np.hstack((a, zeros))
Shimon S
fonte
3

No meu caso, eu tive que adicionar uma coluna de uns a uma matriz NumPy

X = array([ 6.1101, 5.5277, ... ])
X.shape => (97,)
X = np.concatenate((np.ones((m,1), dtype=np.int), X.reshape(m,1)), axis=1)

Após X.shape => (97, 2)

array([[ 1. , 6.1101],
       [ 1. , 5.5277],
...
Mircea Stanciu
fonte
1

Existe uma função específica para isso. É chamado numpy.pad

a = np.array([[1,2,3], [2,3,4]])
b = np.pad(a, ((0, 0), (0, 1)), mode='constant', constant_values=0)
print b
>>> array([[1, 2, 3, 0],
           [2, 3, 4, 0]])

Aqui está o que diz na doutrina:

Pads an array.

Parameters
----------
array : array_like of rank N
    Input array
pad_width : {sequence, array_like, int}
    Number of values padded to the edges of each axis.
    ((before_1, after_1), ... (before_N, after_N)) unique pad widths
    for each axis.
    ((before, after),) yields same before and after pad for each axis.
    (pad,) or int is a shortcut for before = after = pad width for all
    axes.
mode : str or function
    One of the following string values or a user supplied function.

    'constant'
        Pads with a constant value.
    'edge'
        Pads with the edge values of array.
    'linear_ramp'
        Pads with the linear ramp between end_value and the
        array edge value.
    'maximum'
        Pads with the maximum value of all or part of the
        vector along each axis.
    'mean'
        Pads with the mean value of all or part of the
        vector along each axis.
    'median'
        Pads with the median value of all or part of the
        vector along each axis.
    'minimum'
        Pads with the minimum value of all or part of the
        vector along each axis.
    'reflect'
        Pads with the reflection of the vector mirrored on
        the first and last values of the vector along each
        axis.
    'symmetric'
        Pads with the reflection of the vector mirrored
        along the edge of the array.
    'wrap'
        Pads with the wrap of the vector along the axis.
        The first values are used to pad the end and the
        end values are used to pad the beginning.
    <function>
        Padding function, see Notes.
stat_length : sequence or int, optional
    Used in 'maximum', 'mean', 'median', and 'minimum'.  Number of
    values at edge of each axis used to calculate the statistic value.

    ((before_1, after_1), ... (before_N, after_N)) unique statistic
    lengths for each axis.

    ((before, after),) yields same before and after statistic lengths
    for each axis.

    (stat_length,) or int is a shortcut for before = after = statistic
    length for all axes.

    Default is ``None``, to use the entire axis.
constant_values : sequence or int, optional
    Used in 'constant'.  The values to set the padded values for each
    axis.

    ((before_1, after_1), ... (before_N, after_N)) unique pad constants
    for each axis.

    ((before, after),) yields same before and after constants for each
    axis.

    (constant,) or int is a shortcut for before = after = constant for
    all axes.

    Default is 0.
end_values : sequence or int, optional
    Used in 'linear_ramp'.  The values used for the ending value of the
    linear_ramp and that will form the edge of the padded array.

    ((before_1, after_1), ... (before_N, after_N)) unique end values
    for each axis.

    ((before, after),) yields same before and after end values for each
    axis.

    (constant,) or int is a shortcut for before = after = end value for
    all axes.

    Default is 0.
reflect_type : {'even', 'odd'}, optional
    Used in 'reflect', and 'symmetric'.  The 'even' style is the
    default with an unaltered reflection around the edge value.  For
    the 'odd' style, the extented part of the array is created by
    subtracting the reflected values from two times the edge value.

Returns
-------
pad : ndarray
    Padded array of rank equal to `array` with shape increased
    according to `pad_width`.

Notes
-----
.. versionadded:: 1.7.0

For an array with rank greater than 1, some of the padding of later
axes is calculated from padding of previous axes.  This is easiest to
think about with a rank 2 array where the corners of the padded array
are calculated by using padded values from the first axis.

The padding function, if used, should return a rank 1 array equal in
length to the vector argument with padded values replaced. It has the
following signature::

    padding_func(vector, iaxis_pad_width, iaxis, kwargs)

where

    vector : ndarray
        A rank 1 array already padded with zeros.  Padded values are
        vector[:pad_tuple[0]] and vector[-pad_tuple[1]:].
    iaxis_pad_width : tuple
        A 2-tuple of ints, iaxis_pad_width[0] represents the number of
        values padded at the beginning of vector where
        iaxis_pad_width[1] represents the number of values padded at
        the end of vector.
    iaxis : int
        The axis currently being calculated.
    kwargs : dict
        Any keyword arguments the function requires.

Examples
--------
>>> a = [1, 2, 3, 4, 5]
>>> np.pad(a, (2,3), 'constant', constant_values=(4, 6))
array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6])

>>> np.pad(a, (2, 3), 'edge')
array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5])

>>> np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4))
array([ 5,  3,  1,  2,  3,  4,  5,  2, -1, -4])

>>> np.pad(a, (2,), 'maximum')
array([5, 5, 1, 2, 3, 4, 5, 5, 5])

>>> np.pad(a, (2,), 'mean')
array([3, 3, 1, 2, 3, 4, 5, 3, 3])

>>> np.pad(a, (2,), 'median')
array([3, 3, 1, 2, 3, 4, 5, 3, 3])

>>> a = [[1, 2], [3, 4]]
>>> np.pad(a, ((3, 2), (2, 3)), 'minimum')
array([[1, 1, 1, 2, 1, 1, 1],
       [1, 1, 1, 2, 1, 1, 1],
       [1, 1, 1, 2, 1, 1, 1],
       [1, 1, 1, 2, 1, 1, 1],
       [3, 3, 3, 4, 3, 3, 3],
       [1, 1, 1, 2, 1, 1, 1],
       [1, 1, 1, 2, 1, 1, 1]])

>>> a = [1, 2, 3, 4, 5]
>>> np.pad(a, (2, 3), 'reflect')
array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2])

>>> np.pad(a, (2, 3), 'reflect', reflect_type='odd')
array([-1,  0,  1,  2,  3,  4,  5,  6,  7,  8])

>>> np.pad(a, (2, 3), 'symmetric')
array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3])

>>> np.pad(a, (2, 3), 'symmetric', reflect_type='odd')
array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7])

>>> np.pad(a, (2, 3), 'wrap')
array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3])

>>> def pad_with(vector, pad_width, iaxis, kwargs):
...     pad_value = kwargs.get('padder', 10)
...     vector[:pad_width[0]] = pad_value
...     vector[-pad_width[1]:] = pad_value
...     return vector
>>> a = np.arange(6)
>>> a = a.reshape((2, 3))
>>> np.pad(a, 2, pad_with)
array([[10, 10, 10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10, 10, 10],
       [10, 10,  0,  1,  2, 10, 10],
       [10, 10,  3,  4,  5, 10, 10],
       [10, 10, 10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10, 10, 10]])
>>> np.pad(a, 2, pad_with, padder=100)
array([[100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100],
       [100, 100,   0,   1,   2, 100, 100],
       [100, 100,   3,   4,   5, 100, 100],
       [100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100]])
Ivan Hoffmann
fonte