ChatGPT解决这个技术问题 Extra ChatGPT

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

假设我有一个 NumPy 数组 a

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

我想添加一列零来获取数组b

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

如何在 NumPy 中轻松做到这一点?


d
denis

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

(方括号 [] 而不是圆 () 的原因是 Python 扩展了例如 1:4 方括号——重载的奇迹。)


只是在寻找有关此的信息,并且绝对是比已接受的答案更好的答案,因为它涵盖了在开头和结尾添加一个额外的列,而不仅仅是在结尾处添加其他答案
@Ay0 没错,我一直在寻找一种方法,可以一次在所有层上批量向我的人工神经网络中添加偏置单元,这是完美的答案。
如果你想一次添加 n 列怎么办?
@Riley,你能举个例子吗? Python 3 具有“可迭代解包”,例如 np.c_[ * iterable ];见expression-lists
@denis,这正是我想要的!
J
JoshAdel

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

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

我想将 (985,1) 形状 np araay 附加到 (985,2) np 数组以使其成为 (985,3) np 数组,但它不起作用。我收到“无法将输入数组从形状 (985) 广播到形状 (985,1)”错误。我的代码有什么问题?代码:np.hstack(data, data1)
@Outlier 您应该发布一个新问题,而不是在此问题的评论中提出一个问题。
@JoshAdel:我在 ipython 上试过你的代码,我认为有语法错误。您可能想尝试将 a = np.random.rand((N,N)) 更改为 a = np.random.rand(N,N)
我想这对于 OP 的要求来说有点过头了。欧普的回答很贴切!
这只是执行追加、插入或堆栈的技巧。并且不应被接受为答案。工程师应考虑使用以下答案。
T
Thomas Ahle

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

这在插入更复杂的列时很好。
这比@JoshAdel 的答案更直接,但是在处理大型数据集时,它会更慢。我会根据可读性的重要性在两者之间进行选择。
append 实际上只是调用 concatenate
P
Peter Mortensen

使用 hstack 的一种方法是:

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

我认为这是最优雅的解决方案。
+1-这就是我的做法-您击败了我将其发布为答案:)。
去掉 dtype 参数,它不是必需的,甚至是不允许的。虽然您的解决方案足够优雅,但如果您需要经常“追加”到数组,请注意不要使用它。如果您不能一次创建整个数组并在以后填充它,请创建一个数组列表并一次hstack 全部完成。
@eumiro我不确定我是如何设法将dtype放在错误的位置,但是np.zeros需要一个dtype来避免一切都变成float(而a是int)
N
Nico Schlömer

我也对这个问题感兴趣并比较了速度

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 的增长时机:

https://i.stack.imgur.com/Dht56.png

请注意,所有非连续变体(尤其是 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")

好图!只是想您想知道在底层,stackhstackvstackcolumn_stackdstack 都是构建在 np.concatenate 之上的辅助函数。通过跟踪 definition of 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 补充说。
不错的图书馆,没听说过!有趣的是,除了 stack 和 concat 改变了位置(在 ascont 和非 cont 变体中)之外,我得到了相同的图。加上 concat-column 和 column_stack 也交换了。
哇,喜欢这些情节!
似乎对于将列附加到数组的递归操作,例如 b = [b, a],某些命令不起作用(引发了关于不等维度的错误)。仅有的两个似乎适用于大小不等的数组(即,一个是矩阵,另一个是一维向量)是 c_column_stack
P
Peter Mortensen

我发现以下最优雅:

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

这很整洁。太糟糕了,我不能做 insert(a, -1, ...) 来追加列。猜猜我只是把它放在前面。
@ThomasAhle 您可以通过使用 a.shape[axis] 获取该轴的大小来附加行或列。 IE。要追加一行,您执行 np.insert(a, a.shape[0], 999, axis=0),对于一列,您执行 np.insert(a, a.shape[1], 999, axis=1)
u
user2820502

我认为:

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

更优雅。


M
MSeifert

假设 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 小时里拉头发的原因!泰!
h
han4wluc

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 的回答一致。
n
nacho4d

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

请注意,您在此处将 y 附加到 x 而不是将 x 附加到 y - 这就是为什么 y 的列向量在结果中 x 的列的右侧。
我更新了答案以反映布赖恩的评论。 "x 附加到 y" → "y 附加到 x"
t
toddInPortland

我喜欢 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() 由于其简洁性而更受欢迎。
T
Tai

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

它沿一个轴在给定索引(此处为 idx)之前插入值(此处为 new_col)。换句话说,新插入的值将占据 idx 列,并将原来在 idx 处和之后的内容向后移动。


请注意,insert 没有到位,因为可以假设给定函数的名称(请参阅答案中链接的文档)。
C
Community

派对有点晚了,但还没有人发布这个答案,所以为了完整起见:你可以在一个普通的 Python 数组上使用列表推导来做到这一点:

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

S
Shimon S

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

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

P
Peter Mortensen

就我而言,我必须将一列添加到 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],
...

I
Ivan Hoffmann

有一个专门用于此的功能。它被称为 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]])

np.pad 是新功能吗?我很惊讶这没有得到更多的支持。
W
William H. Hooper

我喜欢这个:

new_column = np.zeros((len(a), 1))
b = np.block([a, new_column])