Come aggiungere una colonna aggiuntiva a un array NumPy


292

Diciamo che ho un array di NumPy, a:

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

E vorrei aggiungere una colonna di zeri per ottenere un array b:

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

Come posso farlo facilmente in NumPy?

Risposte:


181

Penso che una soluzione più semplice e veloce da avviare sia quella di fare quanto segue:

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

E tempi:

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

16
Voglio aggiungere (985,1) forma np araay a (985,2) np array per renderlo (985,3) np array, ma non funziona. Sto ottenendo l'errore "impossibile trasmettere array di input dalla forma (985) alla forma (985,1)". cosa c'è che non va nel mio codice? Codice: np.hstack (data, data1)
Outlier

5
@Più presto dovresti pubblicare una nuova domanda piuttosto che farne una nei commenti di questa.
JoshAdel,

4
@JoshAdel: ho provato il tuo codice su ipython e penso che ci sia un errore di sintassi. Potresti provare a cambiare a = np.random.rand((N,N))ina = np.random.rand(N,N)
hlin117 l'

Immagino che questo sia eccessivo per ciò che OP ha richiesto. La risposta di Op è appropriata!
lft93ryt,

Questo è solo un trucco per eseguire append, o insert o stack. e non dovrebbe essere accettato come risposta. Gli ingegneri dovrebbero considerare l'utilizzo delle risposte di seguito.
cinqS

326

np.r_[ ... ]e np.c_[ ... ] sono utili alternative a vstacke hstack, con parentesi quadre [] anziché round ().
Un paio di esempi:

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

(La ragione per le parentesi quadre [] invece che per round () è che Python si espande ad esempio 1: 4 in quadrato - le meraviglie del sovraccarico.)


7
stavo solo cercando informazioni su questo, e sicuramente questa è una risposta migliore di quella accettata, perché copre l'aggiunta di una colonna aggiuntiva all'inizio e alla fine, non solo alla fine come le altre risposte
Ay0

2
@ Ay0 Esattamente, stavo cercando un modo per aggiungere un'unità di polarizzazione alla mia rete neuronale artificiale in batch su tutti gli strati contemporaneamente, e questa è la risposta perfetta.
gaborous

E se vuoi aggiungere n colonne in un momento?
Riley,

1
@Riley, puoi fare un esempio per favore? Python 3 ha "disimballaggio ripetibile", ad es np.c_[ * iterable ]. vedere gli elenchi di espressioni .
denis,

@denis, era esattamente quello che stavo cercando!
Riley,

148

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

3
Questo è utile quando si inseriscono colonne più complicate.
Thomas Ahle,

6
Questo è più semplice della risposta di @JoshAdel, ma quando si ha a che fare con set di dati di grandi dimensioni, è più lento. Sceglierei tra i due a seconda dell'importanza della leggibilità.
dvj

3
appendchiama in realtà bastaconcatenate
rll

53

Un modo, usando hstack , è:

b = np.hstack((a, np.zeros((a.shape[0], 1), dtype=a.dtype)))

2
Penso che questa sia la soluzione più elegante.
Silvado,

2
+1 - ecco come lo farei - mi hai battuto a pubblicarlo come risposta :).
Blair,

3
Rimuovere il dtypeparametro, non è necessario e nemmeno consentito. Mentre la tua soluzione è abbastanza elegante, fai attenzione a non usarla se devi "aggiungere" frequentemente a un array. Se non è possibile creare l'intero array contemporaneamente e riempirlo in un secondo momento, creare un elenco di array e hstacktutto in una volta.
eumiro,

1
@eumiro Non sono sicuro di come sono riuscito a ottenere il dtype nella posizione sbagliata, ma il np.zeros ha bisogno di un dtype per evitare che tutto diventi float (mentre a è int)
Peter Smit

42

Trovo il seguente più elegante:

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

Un vantaggio insertè che consente anche di inserire colonne (o righe) in altri punti all'interno dell'array. Inoltre, invece di inserire un singolo valore, puoi facilmente inserire un intero vettore, ad esempio duplicare l'ultima colonna:

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

Il quale conduce a:

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

Per i tempi, insertpotrebbe essere più lento della soluzione di 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

1
Questo è abbastanza pulito. Peccato che non posso fare insert(a, -1, ...)per aggiungere la colonna. Immagino che lo prevederò invece.
Thomas Ahle,

2
@ThomasAhle Puoi aggiungere una riga o una colonna ottenendo la dimensione in quell'asse usando a.shape[axis]. I. e. per aggiungere una riga, lo fai np.insert(a, a.shape[0], 999, axis=0)e per una colonna, lo fai np.insert(a, a.shape[1], 999, axis=1).
blubberdiblub,

35

Ero anche interessato a questa domanda e ho confrontato la velocità di

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

che fanno tutti la stessa cosa per qualsiasi vettore di input a. Tempi per crescere a:

inserisci qui la descrizione dell'immagine

Si noti che tutte le varianti non contigue (in particolare stack/ vstack) sono infine più veloci di tutte le varianti contigue. column_stack(per la sua chiarezza e velocità) sembra essere una buona opzione se hai bisogno di contiguità.


Codice per riprodurre la trama:

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

1
Bel grafico! Solo pensato che avrebbe fatto piacere sapere che sotto il cofano, stack, hstack, vstack, column_stack, dstacksono tutte funzioni di aiuto costruiti in cima np.concatenate. Tracciando la definizione di stack ho scoperto che np.stack([a,a])sta chiamando np.concatenate([a[None], a[None]], axis=0). Potrebbe essere utile aggiungerlo np.concatenate([a[None], a[None]], axis=0).Tal perfplot per mostrare che np.concatenatepuò sempre essere veloce almeno quanto le sue funzioni di supporto.
unutbu,

@unutbu L'ha aggiunto.
Nico Schlömer,

Bella biblioteca, non ne ho mai sentito parlare! Abbastanza interessante che ho avuto gli stessi grafici tranne che stack e concat hanno cambiato posto (sia nelle varianti ascont che non cont). Inoltre sono stati scambiati anche concat-column e column_stack.
Antony Hatchkins,

1
Wow, adoro questi complotti!
jhegedus,

Sembra che per un'operazione ricorsiva di aggiunta di una colonna a un array, ad esempio b = [b, a], alcuni dei comandi non funzionino (viene generato un errore relativo alle dimensioni disuguali). Gli unici due che sembrano funzionare con matrici di dimensioni diverse (ovvero quando uno è una matrice e un altro è un vettore 1d) sono c_ecolumn_stack
Confonduto l'

29

Penso:

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

è più elegante.


12

np.concatenate funziona anche

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

np.concatenatesembra essere 3 volte più veloce rispetto np.hstackalle matrici 2x1, 2x2 e 2x3. np.concatenateera anche leggermente più veloce rispetto alla copia manuale delle matrici in una matrice vuota nei miei esperimenti. Ciò è coerente con la risposta di Nico Schlömer di seguito.
Lenar Hoyt,

11

Supponendo che Msia un (100,3) ndarray ed yè un (100,) ndarray appendpuò essere usato come segue:

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

Il trucco è usare

y[:, None]

Questo si converte yin un array (100, 1) 2D.

M.shape

ora dà

(100, 4)

Sei un eroe lo sai ?! Questo è esattamente quello che mi sto strappando i capelli nelle ultime 1 ora! Ty!
John Doe,

8

Mi piace la risposta di JoshAdel per l'attenzione focalizzata sulle prestazioni. Un piccolo miglioramento delle prestazioni è quello di evitare il sovraccarico di inizializzazione con zeri, solo per essere sovrascritto. Ciò ha una differenza misurabile quando N è grande, viene utilizzato vuoto anziché zeri e la colonna di zeri viene scritta come un passaggio separato:

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

È possibile utilizzare la trasmissione per riempire l'ultima colonna con zeri (o qualsiasi altro valore), che potrebbe essere più leggibile: b[:,-1] = 0. Inoltre, con array molto grandi, la differenza di prestazioni np.insert()diventa trascurabile, il che potrebbe rendere np.insert()più desiderabile a causa della sua succinta.
blubberdiblub,

7

np.insert serve anche allo scopo.

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

Inserisce valori, qui new_col, prima di un dato indice, qui idxlungo un asse. In altre parole, i valori appena inseriti occuperanno la idxcolonna e sposteranno quelli che erano originariamente lì in corrispondenza e idxall'indietro.


1
Si noti che insertnon è presente come si potrebbe presumere dato il nome della funzione (vedere i documenti collegati nella risposta).
Jneuendorf,

5

Aggiungi una colonna aggiuntiva a una matrice numpy:

Il np.appendmetodo di Numpy accetta tre parametri, i primi due sono array numpy 2D e il terzo è un parametro dell'asse che indica lungo quale asse aggiungere:

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

stampe:

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

Nota che stai aggiungendo y a x qui invece di aggiungere x a y - ecco perché il vettore di colonna di y si trova a destra delle colonne di x nel risultato.
Brian Popeck,

4

Un po 'in ritardo alla festa, ma nessuno ha ancora pubblicato questa risposta, quindi per completezza: puoi farlo con la comprensione dell'elenco, su un semplice array Python:

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

4

Per me, il prossimo modo sembra piuttosto intuitivo e semplice.

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

3

Nel mio caso, ho dovuto aggiungere una colonna di quelli a un array 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)

Dopo X.shape => (97, 2)

array([[ 1. , 6.1101],
       [ 1. , 5.5277],
...

1

C'è una funzione specifica per questo. Si chiama 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]])

Ecco cosa dice nel docstring:

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]])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.