Как добавить дополнительный столбец в массив NumPy

292

Допустим, у меня есть массив NumPy a:

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

И я хотел бы добавить столбец нулей, чтобы получить массив b:

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

Как я могу сделать это легко в NumPy?

Питер Смит
источник

Ответы:

181

Я думаю, что более простое решение и более быстрая загрузка состоит в следующем:

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

И сроки:

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
источник
16
Я хочу добавить (985,1) shape np araay к массиву (985,2) np, чтобы сделать его (985,3) массивом np, но это не работает. Я получаю сообщение об ошибке «Не удалось передать входной массив из формы (985) в форму (985,1)». Что не так с моим кодом? Код: np.hstack (данные, данные 1)
Outlier
5
@ Вы должны публиковать новый вопрос, а не задавать его в комментариях.
JoshAdel
4
@JoshAdel: я попробовал ваш код на ipython, и я думаю, что есть синтаксическая ошибка. Вы можете попробовать перейти a = np.random.rand((N,N))наa = np.random.rand(N,N)
hlin117
Я предполагаю, что это излишество для того, что попросил OP. Ответ Оп является подходящим!
lft93ryt
Это всего лишь прием при добавлении, вставке или стеке. и не должны быть приняты в качестве ответов. Инженеры должны рассмотреть возможность использования ответов ниже.
CinqS
326

np.r_[ ... ]и np.c_[ ... ] являются полезными альтернативами vstackи hstack, с квадратными скобками [] вместо round ().
Пара примеров:

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

(Причина, по которой квадратные скобки [] вместо round () заключаются в том, что Python расширяется, например, в 1: 4 в квадрат - чудеса перегрузки.)

Денис
источник
7
Просто искал информацию об этом, и, безусловно, это лучший ответ, чем принятый, потому что он включает добавление дополнительного столбца в начале и в конце, а не только в конце, как другие ответы
Ay0
2
@ Ay0 Точно, я искал способ добавить блок смещения в мою искусственную нейронную сеть в пакетном режиме на всех слоях одновременно, и это идеальный ответ.
Габорист
А что, если вы хотите добавить n столбцов за раз?
Райли
1
@ Райли, можешь привести пример? Python 3 имеет «повторяемую распаковку», например np.c_[ * iterable ]; см. списки выражений .
денис
@denis, это было именно то, что я искал!
Райли
148

Используйте 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
источник
3
Это хорошо при вставке более сложных столбцов.
Томас Ахле
6
Это более просто, чем ответ @JoshAdel, но при работе с большими наборами данных он медленнее. Я бы выбрал между двумя в зависимости от важности читабельности.
dvj
3
appendна самом деле просто звонитconcatenate
RLL
53

Одним из способов использования hstack является:

b = np.hstack((a, np.zeros((a.shape[0], 1), dtype=a.dtype)))
Питер Смит
источник
2
Я думаю, что это самое элегантное решение.
Сильвадо
2
+1 - это то, как я бы это сделал - вы опередили меня, чтобы опубликовать это как ответ :).
Блэр
3
Удалите dtypeпараметр, он не нужен и даже не разрешен. Хотя ваше решение достаточно элегантно, обратите внимание, чтобы не использовать его, если вам нужно часто «добавлять» в массив. Если вы не можете создать весь массив сразу и заполнить его позже, создайте список массивов и hstackвсе сразу.
Eumiro
1
@eumiro Я не уверен, как мне удалось получить dtype в неправильном месте, но np.zeros нужен dtype, чтобы избежать того, что все становится float (пока a is int)
Питер Смит
42

Я считаю следующие самые элегантные:

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

Преимущество insertзаключается в том, что он также позволяет вставлять столбцы (или строки) в других местах массива. Также вместо вставки одного значения вы можете легко вставить целый вектор, например, дублировать последний столбец:

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

Что приводит к:

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

По срокам, insertможет быть медленнее, чем решение 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
Это довольно опрятно. Жаль, что я не могу сделать, insert(a, -1, ...)чтобы добавить колонку. Думаю, я просто добавлю это вместо этого.
Томас Ахле
2
@ThomasAhle Вы можете добавить строку или столбец, получив размер по этой оси, используя a.shape[axis]. И. е. для добавления строки, вы делаете, np.insert(a, a.shape[0], 999, axis=0)и для столбца, вы делаете np.insert(a, a.shape[1], 999, axis=1).
blubberdiblub
35

Я тоже интересовался этим вопросом и сравнил скорость

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

которые все делают то же самое для любого входного вектора a. Сроки выращивания a:

введите описание изображения здесь

Обратите внимание, что все несмежные варианты (в частности stack/ vstack) в конечном итоге быстрее, чем все смежные варианты. column_stack(для его ясности и скорости), кажется, хороший вариант, если вам требуется смежность.


Код для воспроизведения сюжета:

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
Хороший график! Просто думал , что вы хотели бы знать , что под капотом, stack, hstack, vstack, column_stack, dstackвсе вспомогательные функции , построенные на вершине np.concatenate. Просматривая определение стека, я обнаружил, что np.stack([a,a])это вызов np.concatenate([a[None], a[None]], axis=0). Было бы неплохо добавить np.concatenate([a[None], a[None]], axis=0).Tв perfplot, чтобы показать, что он np.concatenateвсегда может быть по крайней мере так же быстр, как его вспомогательные функции.
unutbu
@unutbu добавил это.
Нико Шлёмер
Хорошая библиотека, никогда не слышал об этом! Интересно, что я получил только те же графики, за исключением того, что стек и concat поменялись местами (как в ascont, так и в non-cont вариантах). Плюс конкатат-столбец и столбец_стак поменялись местами.
Энтони Хэтчкинс
1
Ух ты, люби эти сюжеты!
Джегедус
Кажется, что для рекурсивной операции добавления столбца в массив, например, b = [b, a], некоторые команды не работают (возникает ошибка о неравных измерениях). Только два , которые , кажется, работа с массивами неравного размера (то есть , когда одна матрица , а другой представляет собой 1d вектор) являются c_иcolumn_stack
постыдятся
29

Думаю:

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

более элегантно

user2820502
источник
12

np.concatenate также работает

>>> 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
источник
np.concatenateкажется, в 3 раза быстрее, чем np.hstackдля матриц 2x1, 2x2 и 2x3. np.concatenateбыло также немного быстрее, чем копировать матрицы вручную в пустую матрицу в моих экспериментах. Это согласуется с ответом Нико Шлёмера ниже.
Ленар Хойт
11

Предполагая M, что (100,3) ndarray и y(100,) ndarray appendможно использовать следующим образом:

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

Хитрость заключается в использовании

y[:, None]

Это преобразуется yв (100, 1) 2D массив.

M.shape

сейчас дает

(100, 4)
Роэл Верховен
источник
Ты герой, ты это знаешь ?! Это именно то, что я дергаю за последние 1 час! Ty!
Джон Доу
8

Мне нравится ответ JoshAdel из-за сосредоточенности на производительности. Незначительное улучшение производительности состоит в том, чтобы избежать затрат на инициализацию с нулями, только для перезаписи. Это имеет измеримую разницу, когда N велико, вместо нулей используется пустое, а столбец нулей записывается как отдельный шаг:

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
источник
Вы можете использовать вещания для заполнения последнего столбца нулей (или любого другого значения), которое может быть более удобным для чтения: b[:,-1] = 0. Кроме того, с очень большими массивами разница в производительности np.insert()становится незначительной, что может быть np.insert()более желательным из-за ее краткости.
blubberdiblub
7

np.insert также служит цели.

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

Здесь он вставляет значения здесь new_col, перед данным индексом, здесь idxвдоль одной оси. Другими словами, вновь вставленные значения будут занимать idxстолбец и перемещать то, что было изначально в и после, idxназад.

Tai
источник
1
Обратите внимание, что insertэто не так, как можно предположить, учитывая имя функции (см. Документы в ответе).
Юнендорф
5

Добавьте дополнительный столбец в массив numpy:

Метод Numpy np.appendпринимает три параметра, первые два - это двумерные массивы, а третий - параметр оси, указывающий, к какой оси добавить:

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

Печать:

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]]
Хасан Бахалу
источник
Обратите внимание, что вы добавляете y к x здесь, а не добавляете x к y - вот почему вектор столбца y находится справа от столбцов x в результате.
Брайан Попек
4

Немного опоздал на вечеринку, но никто еще не опубликовал этот ответ, поэтому для полноты картины: вы можете сделать это с помощью списочных представлений в простом массиве Python:

source = a.tolist()
result = [row + [0] for row in source]
b = np.array(result)
БТК
источник
4

Для меня следующий путь выглядит довольно интуитивно и просто.

zeros = np.zeros((2,1)) #2 is a number of rows in your array.   
b = np.hstack((a, zeros))
Шимон С
источник
3

В моем случае мне пришлось добавить столбец единиц в массив 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)

После X.shape => (97, 2)

array([[ 1. , 6.1101],
       [ 1. , 5.5277],
...
Мирча Станчу
источник
1

Специально для этого есть функция. Это называется 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]])

Вот что написано в строке документации:

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]])
Иван Гофман
источник