Bagaimana cara menambahkan kolom tambahan ke array NumPy

292

Katakanlah saya punya array NumPy, a:

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

Dan saya ingin menambahkan kolom nol untuk mendapatkan sebuah array, b:

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

Bagaimana saya bisa melakukan ini dengan mudah di NumPy?

Peter Smit
sumber

Jawaban:

181

Saya pikir solusi yang lebih mudah dan lebih cepat untuk boot adalah dengan melakukan hal berikut:

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

Dan timing:

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
sumber
16
Saya ingin menambahkan (985,1) bentuk np araay ke (985,2) np array untuk membuatnya (985,3) array np, tetapi tidak berfungsi. Saya mendapatkan "tidak dapat menyiarkan larik input dari bentuk (985) ke bentuk (985,1)". Apa yang salah dengan kode saya? Kode: np.hstack (data, data1)
Outlier
5
@Outlier Anda harus memposting pertanyaan baru daripada menanyakan satu di komentar yang satu ini.
JoshAdel
4
@JoshAdel: Saya mencoba kode Anda di ipython, dan saya pikir ada kesalahan sintaksis. Anda mungkin ingin mencoba mengubah a = np.random.rand((N,N))kea = np.random.rand(N,N)
hlin117
Saya kira ini berlebihan untuk apa yang diminta OP. Jawaban Op tepat!
lft93ryt
Ini hanya trik untuk melakukan penambahan, atau memasukkan, atau menumpuk. dan tidak boleh diterima sebagai jawaban. Insinyur harus mempertimbangkan untuk menggunakan jawaban di bawah ini.
cinqS
326

np.r_[ ... ]dan np.c_[ ... ] merupakan alternatif yang bermanfaat untuk vstackdan hstack, dengan tanda kurung siku [] alih-alih bulat ().
Beberapa contoh:

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

(Alasan untuk tanda kurung siku [] alih-alih bulat () adalah bahwa Python mengembang misalnya 1: 4 di bujur sangkar - keajaiban kelebihan beban.)

denis
sumber
7
hanya mencari informasi tentang ini, dan secara pasti ini adalah jawaban yang lebih baik daripada yang diterima, karena itu mencakup penambahan kolom tambahan di awal dan di akhir, bukan hanya di akhir sebagai jawaban lainnya
Ay0
2
@ Ay0 Tepat, saya sedang mencari cara untuk menambahkan unit bias ke jaringan saraf tiruan saya secara batch pada semua lapisan sekaligus, dan ini adalah jawaban yang sempurna.
Gaborous
Dan bagaimana jika Anda ingin menambahkan n kolom sekaligus?
Riley
1
@Riley, bisakah Anda memberi contoh? Python 3 memiliki "iterable unpacking", misalnya np.c_[ * iterable ]; lihat daftar ekspresi .
denis
@denis, itulah tepatnya yang saya cari!
Riley
148

Gunakan 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
sumber
3
Ini bagus ketika memasukkan kolom yang lebih rumit.
Thomas Ahle
6
Ini lebih mudah daripada jawaban oleh @JoshAdel, tetapi ketika berhadapan dengan set data besar, ini lebih lambat. Saya akan memilih antara keduanya tergantung pada pentingnya keterbacaan.
dvj
3
appendsebenarnya hanya meneleponconcatenate
rll
53

Salah satu cara, menggunakan hstack , adalah:

b = np.hstack((a, np.zeros((a.shape[0], 1), dtype=a.dtype)))
Peter Smit
sumber
2
Saya pikir ini adalah solusi paling elegan.
silvado
2
+1 - ini adalah bagaimana saya akan melakukannya - Anda mengalahkan saya untuk mempostingnya sebagai jawaban :).
Blair
3
Hapus dtypeparameter, itu tidak diperlukan dan bahkan tidak diizinkan. Meskipun solusi Anda cukup elegan, perhatikan untuk tidak menggunakannya jika Anda perlu "menambahkan" ke sebuah array. Jika Anda tidak dapat membuat seluruh array sekaligus dan mengisinya nanti, buat daftar array dan hstacksemuanya sekaligus.
eumiro
1
@ eumiro Saya tidak yakin bagaimana saya berhasil mendapatkan dtype di lokasi yang salah, tetapi np.zeros membutuhkan dtype untuk menghindari segala sesuatu menjadi mengambang (saat sedang int)
Peter Smit
42

Saya menemukan yang paling elegan berikut:

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

Keuntungannya insertadalah ia juga memungkinkan Anda untuk memasukkan kolom (atau baris) di tempat lain di dalam array. Juga, alih-alih menyisipkan nilai tunggal, Anda dapat dengan mudah memasukkan seluruh vektor, misalnya menduplikasi kolom terakhir:

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

Yang mengarah ke:

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

Untuk waktunya, insertmungkin lebih lambat dari solusi 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
sumber
1
Ini cukup rapi. Sayang sekali saya tidak bisa insert(a, -1, ...)menambahkan kolom. Kurasa aku hanya akan menambahkannya.
Thomas Ahle
2
@ThomasAhle Anda dapat menambahkan baris atau kolom dengan menggunakan ukuran dalam sumbu itu menggunakan a.shape[axis]. Saya. E. untuk menambahkan baris, Anda lakukan np.insert(a, a.shape[0], 999, axis=0)dan untuk kolom, Anda lakukan np.insert(a, a.shape[1], 999, axis=1).
blubberdiblub
35

Saya juga tertarik dengan pertanyaan ini dan membandingkan kecepatan

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

yang semuanya melakukan hal yang sama untuk setiap vektor input a. Pengaturan waktu untuk tumbuh a:

masukkan deskripsi gambar di sini

Perhatikan bahwa semua varian yang tidak bersebelahan (khususnya stack/ vstack) pada akhirnya lebih cepat daripada semua varian yang bersebelahan. column_stack(untuk kejelasan dan kecepatannya) tampaknya menjadi pilihan yang baik jika Anda memerlukan kedekatan.


Kode untuk mereproduksi plot:

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
sumber
1
Grafik yang bagus! Hanya berpikir Anda ingin tahu bahwa di bawah tenda, stack, hstack, vstack, column_stack, dstacksemua fungsi pembantu dibangun di atas np.concatenate. Dengan menelusuri definisi stack saya menemukan bahwa np.stack([a,a])memanggil np.concatenate([a[None], a[None]], axis=0). Mungkin bagus untuk menambahkan np.concatenate([a[None], a[None]], axis=0).Tperfplot untuk menunjukkan bahwa np.concatenateselalu dapat setidaknya secepat fungsi pembantu.
unutbu
@unutbu Menambahkan itu.
Nico Schlömer
Perpustakaan yang bagus, tidak pernah mendengarnya! Cukup menarik sehingga saya mendapatkan plot yang sama kecuali bahwa stack dan concat telah mengubah tempat (dalam varian ascont dan non-cont). Ditambah concat-column dan column_stack ditukar juga.
Antony Hatchkins
1
Wow, suka plot ini!
jhegedus
Tampaknya untuk operasi rekursif menambahkan kolom ke array, misalnya b = [b, a], beberapa perintah tidak berfungsi (kesalahan tentang dimensi yang tidak sama dinaikkan). Satu-satunya dua yang tampaknya bekerja dengan array ukuran tidak sama (yaitu ketika satu adalah matriks dan yang lain adalah vektor 1d) adalah c_dancolumn_stack
Confounded
29

Kupikir:

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

lebih elegan.

pengguna2820502
sumber
12

np.concatenate juga berfungsi

>>> 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
sumber
np.concatenatetampaknya menjadi 3 kali lebih cepat daripada np.hstackmatriks 2x1, 2x2 dan 2x3. np.concatenatejuga sangat sedikit lebih cepat daripada menyalin matriks secara manual ke dalam matriks kosong dalam percobaan saya. Itu konsisten dengan jawaban Nico Schlömer di bawah ini.
Lenar Hoyt
11

Dengan asumsi Madalah (100,3) ndarray dan ymerupakan (100,) ndarray appenddapat digunakan sebagai berikut:

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

Triknya adalah menggunakan

y[:, None]

Ini mengonversi yke array (100, 1) 2D.

M.shape

sekarang memberi

(100, 4)
Roel Verhoeven
sumber
Anda adalah pahlawan, Anda tahu itu ?! Itulah tepatnya yang saya tarik rambut saya selama 1 jam terakhir! Ty!
John Doe
8

Saya suka jawaban JoshAdel karena fokus pada kinerja. Peningkatan kinerja kecil adalah untuk menghindari overhead menginisialisasi dengan nol, hanya untuk ditimpa. Ini memiliki perbedaan yang terukur ketika N besar, kosong digunakan sebagai ganti nol, dan kolom nol ditulis sebagai langkah terpisah:

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
sumber
Anda dapat menggunakan siaran untuk mengisi kolom terakhir dengan nol (atau nilai lain), yang mungkin lebih mudah dibaca: b[:,-1] = 0. Juga, dengan susunan yang sangat besar, perbedaan kinerja np.insert()menjadi diabaikan, yang mungkin membuat np.insert()lebih diinginkan karena ringkasnya.
blubberdiblub
7

np.insert juga melayani tujuannya.

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

Ini menyisipkan nilai, di sini new_col, sebelum indeks yang diberikan, di sini di idxsepanjang satu sumbu. Dengan kata lain, nilai-nilai yang baru dimasukkan akan menempati idxkolom dan memindahkan apa yang awalnya ada di dan setelah idxmundur.

Tai
sumber
1
Perhatikan bahwa inserttidak ada di tempat karena orang dapat menganggap diberi nama fungsi (lihat dokumen terkait dalam jawabannya).
jneuendorf
5

Tambahkan kolom tambahan ke array numpy:

np.appendMetode Numpy mengambil tiga parameter, dua yang pertama adalah array numpy 2D dan ke-3 adalah parameter sumbu yang menginstruksikan sepanjang sumbu mana yang akan ditambahkan:

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

Cetakan:

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
sumber
Perhatikan Anda menambahkan y ke x di sini daripada menambahkan x ke y - itulah sebabnya vektor kolom y adalah di sebelah kanan kolom x dalam hasilnya.
Brian Popeck
4

Agak terlambat ke pesta, tetapi belum ada yang memposting jawaban ini, jadi demi kelengkapan: Anda dapat melakukan ini dengan daftar pemahaman, pada array Python sederhana:

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

Bagi saya, cara selanjutnya terlihat cukup intuitif dan sederhana.

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

Dalam kasus saya, saya harus menambahkan kolom yang ke 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)

Setelah X.shape => (97, 2)

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

Ada fungsi khusus untuk ini. Ini disebut 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]])

Inilah yang dikatakan dalam dokumen:

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
sumber