如何在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中轻松做到这一点?

Answers:


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

16
我想将(985,1)shape np araay附加到(985,2)np array中,使其成为(985,3)np array,但是它不起作用。我收到“无法将输入数组从形状(985)广播到形状(985,1)”错误。我的代码有什么问题?代码:np.hstack(data,data1)
离群值

5
@Outlier您应该发布一个新问题,而不要在此问题的评论中提问。
JoshAdel 2014年

4
@JoshAdel:我在ipython上尝试过您的代码,但我认为存在语法错误。您可能想尝试更改a = np.random.rand((N,N))a = np.random.rand(N,N)
hlin117

我想这对于OP的要求来说是一个过大的杀伤力。Op的答案很贴切!
lft93ryt

这只是执行追加,插入或堆栈的一个技巧。并且不应该作为答案。工程师应考虑使用以下答案。
cinqS

325

np.r_[ ... ]并且np.c_[ ... ] 是有用的替代品vstackhstack,用方括号[]代替圆()。
几个例子:

: 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
@Riley,请您举个例子吗?Python 3具有“可迭代的拆包”功能,例如np.c_[ * iterable ];参见expression-lists
丹尼斯,

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

3
当插入更复杂的列时,这很好。
Thomas Ahle 2014年

6
这比@JoshAdel的答案更直接,但是在处理大型数据集时,它的速度较慢。我会根据可读性的重要性在两者之间进行选择。
DVJ

3
append实际上只是打电话给您concatenate
-rll

53

使用hstack的一种方法是:

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

2
我认为这是最优雅的解决方案。
silvado 2011年

2
+1-这就是我的做法-您击败了我,将其发布为答案:)。
布莱尔

3
删除该dtype参数,它是不需要的,甚至是不允许的。尽管您的解决方案足够优雅,但是如果您需要经常“追加”到阵列中,请注意不要使用它。如果您无法一次创建整个数组并在以后填充它,请一次创建一个数组列表,并hstack全部创建一次。
eumiro 2011年

1
@eumiro我不确定如何将dtype放置在错误的位置,但是np.zeros需要一个dtype来避免所有内容变为浮动状态(而a是int时)
Peter Smit

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, ...)添加该列。猜猜我将代替它。
Thomas Ahle 2014年

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
不错的图!只是以为你想知道的是,引擎盖下,stackhstackvstackcolumn_stackdstack是建立在顶部的所有辅助功能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添加了。
NicoSchlömer17年

漂亮的图书馆,从来没有听说过!有趣的是,除了stack和concat改变了位置(在ascont和non-cont变体中)之外,我得到了相同的图。加上concat-column和column_stack也进行了交换。
安东尼·哈奇金斯

1
哇,喜欢这些情节!
jhegedus

似乎对于将一列追加到数组的递归操作(例如b = [b,a]),某些命令不起作用(引发了有关尺寸不相等的错误)。只有两个,似乎工作大小不等的阵列(即,当一个是矩阵,另一种是一个一维矢量)是c_column_stack
混淆

29

我认为:

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

更优雅。


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

np.concatenate似乎比np.hstack2x1、2x2和2x3矩阵快3倍。np.concatenate在我的实验中,比手动将矩阵复制到一个空矩阵中要快得多。这与NicoSchlömer在下面的回答是一致的。
莱纳尔·霍伊特

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个小时拉头发的原因!!
John Doe

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

您可以使用广播将零(或任何其他值)填充到最后一列,这可能更容易理解: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


1
请注意,insert由于没有提供给定的函数名称,因此该位置不适当(请参见答案中链接的文档)。
jneuendorf

5

向numpy数组添加额外的列:

Numpy的np.append方法需要三个参数,前两个是2D numpy数组,第三个是轴参数,指示要沿哪个轴附加:

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的列的右侧。
Brian Popeck

4

晚会晚了一点,但是还没有人发布这个答案,因此为了完整起见:您可以使用列表推导在一个简单的Python数组上执行此操作:

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

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

3

对我来说,下一种方法看起来非常直观和简单。

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

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]])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.