连接两个一维NumPy数组

406

我该如何在NumPy中连接两个一维数组?我尝试了numpy.concatenate

import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5])
np.concatenate(a, b)

但我遇到了一个错误:

类型错误:只有长度为1的数组才能转换为Python标量


7
如果您想将它们(合并为一个数组)沿着某个轴拼接,请使用np.concatenate(...,axis)。如果您想垂直堆叠它们,请使用np.vstack。如果您想水平堆叠它们(成多个数组),请使用np.hstack。(如果您想堆叠它们在第三维即深度方向上,则使用np.dstack)。请注意,后者与pandas的pd.concat类似。 - smci
7个回答

538

用法:

np.concatenate([a, b])
你需要将要连接的数组作为序列传递,而不是分开作为参数传递。
根据 NumPy 文档 的说明:

numpy.concatenate((a1, a2, ...), axis=0)

将一系列数组连接在一起。

它试图将你的 b 解释为轴参数,这就是为什么它抱怨无法将其转换为标量值的原因。

3
谢谢!只是好奇,这背后的逻辑是什么? - user391339
9
@user391339,如果您想要连接三个数组呢?这个函数在接受序列时更有用,而不仅仅是两个数组。 - Winston Ewert
假设问题不是硬编码为两个参数,您可以使用这样的方式 numpy.concatenate(a1, a2, a3) 或者如果您喜欢的话,还可以使用 numpy.concatenate(*[a1, a2, a3])。Python非常灵活,这种差异在实际使用中并不会对程序产生实质性影响,但API保持一致性很重要(例如,如果所有接受可变长度参数列表的numpy函数都需要显式序列)。 - Jim K.
1
@JimK。axis参数会发生什么? - Winston Ewert
1
假设要连接的所有内容都是位置参数,您可以将轴保留为关键字参数(例如def concatx(*sequences, **kwargs))。这并不理想,因为您似乎无法以这种方式在签名中明确命名关键字参数,但有解决方法。 - Jim K.
np.concatenate 是一个 Type: builtin_function_or_method。因此,接口在 numpy 编译代码中是“硬编码”的。np.append 是一个设计不良的替代方法,它需要2个参数(加上关键字),并将它们放入一个序列中。整个 stack 函数范围也像 concatenate 一样工作。同样适用于无处不在的 np.array。基本的 Python list() 也是如此。 - hpaulj

82

有几种将一维数组连接起来的可能性,例如:

import numpy as np

np.r_[a, a]
np.stack([a, a]).reshape(-1)
np.hstack([a, a])
np.concatenate([a, a])

对于大型数组,所有这些选项的速度都是相同的;对于小型数组,concatenate略有优势:

enter image description here

该图是使用perfplot创建的:

import numpy
import perfplot

perfplot.show(
    setup=lambda n: numpy.random.rand(n),
    kernels=[
        lambda a: numpy.r_[a, a],
        lambda a: numpy.stack([a, a]).reshape(-1),
        lambda a: numpy.hstack([a, a]),
        lambda a: numpy.concatenate([a, a]),
    ],
    labels=["r_", "stack+reshape", "hstack", "concatenate"],
    n_range=[2 ** k for k in range(19)],
    xlabel="len(a)",
)

18
所有替代方法都使用np.concatenate。它们只是以不同的方式处理输入列表。例如,np.stack在所有输入数组上添加了一个额外的维度。查看它们的源代码。只有concatenate被编译。 - hpaulj
2
只是补充一下@hpaulj的评论——随着数组大小的增长,时间会聚合在一起,因为np.concatenate会复制输入。这种内存和时间成本就超过了花费在“调整”输入上的时间。 - n1k31t4
谢谢!我使用了你的代码来检查数组数量(大小为100)的影响,并得到了类似的结果:https://i.stack.imgur.com/w6ojK.png - Ofir Shifman
我之前不知道perfplot,真的很方便。 - Tacio Medeiros

39
< p > concatenate 的第一个参数本身应该是要连接的数组序列

numpy.concatenate((a,b)) # Note the extra parentheses.

14

另一种选择是使用“concatenate”的简短形式,即“r_ [...]”或“c_ [...]”,如下面的示例代码所示(有关更多信息,请参见链接):

%pylab
vector_a = r_[0.:10.] #short form of "arange"
vector_b = array([1,1,1,1])
vector_c = r_[vector_a,vector_b]
print vector_a
print vector_b
print vector_c, '\n\n'

a = ones((3,4))*4
print a, '\n'
c = array([1,1,1])
b = c_[a,c]
print b, '\n\n'

a = ones((4,3))*4
print a, '\n'
c = array([[1,1,1]])
b = r_[a,c]
print b

print type(vector_b)

这导致:
[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.]
[1 1 1 1]
[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.  1.  1.  1.  1.] 


[[ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]] 

[[ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]] 


[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]] 

[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 1.  1.  1.]]

2
vector_b = [1,1,1,1] #short form of "array",这并不是真的。vector_b将是标准的Python列表类型。然而,Numpy非常擅长接受序列,而不是强制所有输入都是numpy.array类型。 - Hannes Ovrén

4

以下是来自numpy 文档 的更多信息:

使用语法numpy.concatenate((a1,a2,...),axis = 0,out = None)

axis = 0 用于按行连接 axis = 1 用于按列连接

>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])

# Appending below last row
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])

# Appending after last column
>>> np.concatenate((a, b.T), axis=1)    # Notice the transpose
array([[1, 2, 5],
       [3, 4, 6]])

# Flattening the final array
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])

我希望这能有所帮助!


2
以下是使用 numpy.ravel()numpy.array() 的更多方法,利用一维数组可以解包为普通元素的事实:
# we'll utilize the concept of unpacking
In [15]: (*a, *b)
Out[15]: (1, 2, 3, 5, 6)

# using `numpy.ravel()`
In [14]: np.ravel((*a, *b))
Out[14]: array([1, 2, 3, 5, 6])

# wrap the unpacked elements in `numpy.array()`
In [16]: np.array((*a, *b))
Out[16]: array([1, 2, 3, 5, 6])

0
稍微不同的问题,即如果您想要两个形状为(n,)的一维数组转换为(2,n),那么您有以下几种选择:
import numpy as np

np.r_[[a], [a]]
np.stack([a, a])
np.vstack([a, a])
np.concatenate([[a], [a]])
np.array([a, a])

最快的方法是使用普通的numpy.array

import numpy
import perfplot

perfplot.show(
    setup=lambda n: numpy.random.rand(n),
    kernels=[
        lambda a: numpy.r_[[a], [a]],
        lambda a: numpy.stack([a, a]),
        lambda a: numpy.vstack([a, a]),
        lambda a: numpy.concatenate([[a], [a]]),
        lambda a: numpy.array([a, a]),
    ],
    labels=["r_", "stack", "vstack", "concatenate", "array"],
    n_range=[2 ** k for k in range(19)],
    xlabel="len(a)",
)

enter image description here


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