如何在numpy中堆叠数组和标量?

12
我有一个包含NumPy向量(1-D数组)或标量(即只有数字)的列表。所有向量长度相同,但我不知道长度是多少。我需要使用vstack将所有元素堆叠在一起以创建一个矩阵(2-D数组),使标量被视为每个位置都有标量值的向量。

以下是一个示例:

情况1:

>>> np.vstack([np.array([1, 2, 3]), np.array([3, 2, 1])])
array([[1, 2, 3],
       [3, 2, 1]])

案例2:

>>> np.vstack([1, 2])
array([[1],
       [2]])

第三种情况:

>>> np.vstack([np.array([1, 2, 3]), 0, np.array([3, 2, 1])])
np.array([[1, 2, 3],
          [0, 0, 0],
          [3, 2, 1]])

1和2案例可以直接使用。然而,在第3种情况下,由于vstack需要所有元素都是相同长度的数组,所以无法使用。

有没有一种简单的方法(最好只用一行代码)可以实现这个呢?

3个回答

15
你可以创建广播对象,并在其上调用np.column_stack
In [175]: np.column_stack(np.broadcast([1, 2, 3], 0, [3, 2, 1]))
Out[175]: 
array([[1, 2, 3],
       [0, 0, 0],
       [3, 2, 1]])

或者,您可以要求NumPy将项目“ literally broadcast”到兼容形状的数组:

In [158]: np.broadcast_arrays([1, 2, 3], [3, 2, 1], 0)
Out[158]: [array([1, 2, 3]), array([3, 2, 1]), array([0, 0, 0])]

然后在其上调用vstackrow_stack:
In [176]: np.row_stack(np.broadcast_arrays([1, 2, 3], 0, [3, 2, 1]))
Out[176]: 
array([[1, 2, 3],
       [0, 0, 0],
       [3, 2, 1]])

在这两个选项中(使用np.broadcastnp.broadcast_arrays),np.broadcast更快,因为您实际上不需要实例化广播的子数组。

然而,np.broadcast的一个限制是最多可以接受32个参数。在这种情况下,请使用np.broadcast_arrays


是的,那正是我想要的。只有一个小问题(纯粹出于好奇):在第一种情况下(使用“broadcast”),为什么“column_stack”会将元素放在行而不是列中呢?如果没有标量并且省略了“broadcast”,向量会变成列而不是行。就好像“broadcast”对结果进行了转置一样。 - zegkljan
1
@zegkljan: np.broadcast 返回一个迭代器。该迭代器返回元组,其中包含每个原始数组(或标量)中将被分组在一起进行逐元素操作的值。查看 list(np.broadcast(np.arange(24).reshape(2,3,4), np.arange(3*4).reshape(3,4))) 返回的内容。它是一个由2元组组成的24个元素列表。它不像 np.broadcast_arrays 那样显示单独广播的数组。它显示了逐元素配对。由于 np.broadcast 返回的迭代器的性质,需要使用 np.column_stack 来形成所需的数组。 - unutbu
np.array(list(np.broadcast(....))np.vstack(np.broadcast(...))更快。它不需要通过np.atleast_2d传递数组。 - hpaulj

1
这里的问题是填补可读的Python世界和高效的NumPy世界之间的差距。
实验结果显示,对于这个任务,令人惊讶的是Python通常比NumPy更好。使用l=[ randint(10) if n%2 else randint(0,10,100) for n in range(32)]进行实验:
In [11]: %timeit array([x if type(x) is ndarray else [x]*100 for x in l])
1000 loops, best of 3: 655 µs per loop

In [12]: %timeit column_stack(broadcast(*l))
100 loops, best of 3: 3.77 ms per loop

此外,广播仅限于32个元素。

-1

虽然不是一行代码,但你可以用标量填充一个空数组。

>>> a = np.empty(4, dtype=int )
>>> a.fill(2)
>>> print(a)
[2 2 2 2]

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