如何向NumPy数组添加额外的列?

447

给定以下2D数组:

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

我想在第二个轴上添加一列零,以获得:

b = np.array([
    [1, 2, 3, 0],
    [2, 3, 4, 0],
])
17个回答

490
`np.r_[...]` (docs) 和 `np.c_[...]` (docs) 是替代 `np.vstack` 和 `np.hstack` 的有用方法。 请注意,它们使用方括号 [] 而不是圆括号 ()。
一些示例:
: 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.])

方括号 [] 而不是圆括号 () 的原因是,Python 将 1:4 转换为方括号中的切片对象。

13
我会尽力进行翻译:我只是在寻找有关此事的信息,毫无疑问,这个答案比被采纳的答案更好,因为它涵盖了在开头和结尾添加额外列,而不仅仅是在结尾添加,这是其他答案所没有的。 - user4093955
2
@Ay0 没错,我正在寻找一种方法,在所有层上批量添加偏置单元到我的人工神经网络中,这是完美的答案。 - gaborous
如果你想一次添加n列呢? - Riley
2
@Riley,请你举个例子好吗?Python 3有“可迭代解包”功能,例如np.c_[*iterable];请参见expression-lists - denis
@denis,这正是我正在寻找的! - Riley
显示剩余2条评论

232

我认为一个更加直接且速度更快的解决方法是执行以下操作:

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

27
我想将一个形状为(985,1)的np数组追加到一个形状为(985,2)的np数组中,使其变成一个形状为(985,3)的np数组,但是我的代码出了问题。我收到了“无法将输入数组从形状(985)广播到形状(985,1)”的错误。 我的代码有什么问题? 代码:np.hstack(data,data1)。您可以尝试使用以下代码来解决这个问题: np.hstack((data, data1.reshape(-1, 1))) 这将把形状为(985,1)的np数组转换为形状为(985,)的一维数组,并将它与形状为(985,2)的np数组水平拼接,最终生成形状为(985,3)的np数组。 - Outlier
8
@Outlier,你应该发布一个新问题而不是在评论中问一个问题。 - JoshAdel
4
@JoshAdel:我在IPython上尝试了你的代码,我认为有语法错误。你可能需要将a = np.random.rand((N,N))更改为a = np.random.rand(N,N)来尝试一下。 - hlin117
我猜这对于 OP 所要求的内容来说有点过度。OP 的回答很适合! - lft93ryt
2
这只是一个关于执行追加、插入或堆栈的技巧,不应该被接受为答案。工程师们应该考虑使用下面的答案。 - cinqS
显示剩余2条评论

209
使用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
8
相对于@JoshAdel的回答,这个更加直接明了,但在处理大型数据集时速度较慢。我会根据可读性的重要性来选择其中之一。 - dvj
7
"append"实际上只是调用了"concatenate"。 - rll

78

使用 hstack 的一种方法是:

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

5
我认为这是最优雅的解决方案。 - silvado
2
+1 - 这是我会这样做的方式 - 你打我一步把它作为答案发布了:)。 - Blair
3
删除 dtype 参数,它不是必要的,甚至是不允许的。虽然你的解决方案已经足够优雅,但如果需要频繁“添加”到数组中,请注意不要使用它。如果无法一次性创建整个数组并稍后填充它,则创建一个数组列表,然后一次性使用 hstack 连接所有数组。 - eumiro
2
@eumiro 我不确定我是如何把dtype放错位置的,但np.zeros需要一个dtype来避免所有东西变成浮点数(而a是整数)。 - Peter Smit

73

我也对这个问题很感兴趣,比较了一下速度。

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的时间如下:

enter image description here

请注意,所有非连续变体(特别是stack/vstack)最终比所有连续变体更快。如果您需要连续性,则column_stack(因其清晰度和速度而言)似乎是一个不错的选择。


用于复制图的代码:

import numpy as np
import perfplot

b = perfplot.bench(
    setup=np.random.rand,
    kernels=[
        lambda a: np.c_[a, a],
        lambda a: np.ascontiguousarray(np.stack([a, a]).T),
        lambda a: np.ascontiguousarray(np.vstack([a, a]).T),
        lambda a: np.column_stack([a, a]),
        lambda a: np.concatenate([a[:, None], a[:, None]], axis=1),
        lambda a: np.ascontiguousarray(np.concatenate([a[None], a[None]], axis=0).T),
        lambda a: np.stack([a, a]).T,
        lambda a: np.vstack([a, a]).T,
        lambda a: np.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(23)],
    xlabel="len(a)",
)
b.save("out.png")

4
好的图表!只是想让你知道,在幕后,stackhstackvstackcolumn_stackdstack等函数都是在np.concatenate函数之上构建的辅助函数。通过跟踪stack的定义,我发现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
1
@unutbu 已经添加了。 - Nico Schlömer
不错的库,从未听说过!有趣的是,我得到了完全相同的绘图,只是堆叠和连接在两个变体(连续和非连续)中交换了位置。此外,concat-column和column_stack也被交换了。 - Antony Hatchkins
2
哇,喜欢这些图表! - jhegedus
2
似乎对于将列附加到数组的递归操作,例如 b = [b, a],某些命令无法正常工作(会引发关于不相等维度的错误)。唯一两个似乎能够处理大小不同的数组(即一个是矩阵,另一个是1D向量)的命令是 c_column_stack - Confounded
显示剩余2条评论

57

我认为以下内容非常优雅:

b = np.insert(a, 3, values=0, axis=1) # Insert values before column 3
< p > < code > 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
3
你可以通过使用a.shape[axis]获取指定轴向上的大小来追加一行或一列。例如,若要追加一行,可以使用np.insert(a, a.shape[0], 999, axis=0)命令;若要追加一列,可以使用np.insert(a, a.shape[1], 999, axis=1)命令。请注意,不要改变原文的意思。 - blubberdiblub

35

我认为:

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

更加优美。


15
假设 M 是一个形状为 (100,3) 的 ndarray,y 是一个形状为 (100,) 的 ndarray,则可以按照以下方式使用 append
M=numpy.append(M,y[:,None],1)

诀窍在于使用

y[:, None]

这将y转换为一个形状为(100, 1)的二维数组。

M.shape

现在提供

(100, 4)

1
你知道吗?你是个英雄!这正是我过去一小时里苦苦思索的问题!谢谢! - John Doe

14

给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]]
y appended to x on axis of 1:
[[1 2 3 1]
 [4 5 6 1]]

3
请注意,此处将y附加到x而非将x附加到y,这就是为什么y的列向量在结果中位于x的列向量右侧的原因。 - Brian Popeck
我更新了答案以反映布赖恩的评论。"x附加到y" → "y附加到x" - nacho4d

13

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

在2x1、2x2和2x3矩阵中,np.concatenate似乎比np.hstack快3倍。在我的实验中,np.concatenate也比手动将矩阵复制到空矩阵中略微快一些。这与Nico Schlömer在下面的回答一致。 - Lenar Hoyt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接