如何将numpy数组的列表转换为单个numpy数组?

198

假设我有:

LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])] # inner lists are numpy arrays

我试图进行转换;

array([[1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5])

目前我正在通过在vstack上进行迭代来解决它,但对于特别大的LIST来说,速度非常慢。

您认为最有效的方法是什么?


8
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]] 这不是正确的Python语法,请澄清。 (翻译者注:原始内容中的“array”可能指的是numpy中的数组对象) - Marcin
13
即使编译器也不会那么粗鲁。 - Hedwin Bonnavaud
2
OP在标题中指定了numpy;array是该框架中常见的对象之一。如果OP执行了from numpy import array,那么就是正确的。同意Hedwin上面的评论,没有理由因为问题需要一些关于Python生态系统中实际上是标准库一部分的知识而对OP不友善。 - AmphotericLewisAcid
5个回答

255
通常情况下,您可以沿任意轴连接一整个数组序列:
numpy.concatenate( LIST, axis=0 )

但是你确实需要担心列表中每个数组的形状和维度(对于一个二维3x5的输出,你需要确保它们都是已经是二维n行5列的数组)。如果你想将一维数组连接成二维输出的行,你需要扩展它们的维度。
正如Jorge的回答指出的那样,在numpy 1.10中还有一个函数stack。
numpy.stack( LIST, axis=0 )

这种方法采用了互补的方式:它为每个输入数组创建了一个新的视图,并在连接之前添加了一个额外的维度(在这种情况下,是在左侧,所以每个n元素的一维数组变成了一个1乘n的二维数组)。这种方法只有在所有输入数组具有相同的形状时才有效。
vstack(或等效的row_stack)通常是一个更容易使用的解决方案,因为它可以接受一系列1维和/或2维数组,并在必要时自动扩展维度,仅在必要时扩展维度,然后将整个列表连接在一起。当需要一个新的维度时,它会在左侧添加。同样,您可以一次连接整个列表,而无需进行迭代。
numpy.vstack( LIST )

这种灵活的行为也可以通过语法快捷方式numpy.r_[ array1, ...., arrayN ](注意方括号)来展示。这对于连接几个明确命名的数组很好,但在您的情况下,它变得不太可读,因为[]下标不接受list。您需要将序列转换为tuplenumpy.r_[tuple(LIST)]。使用vstack()更易读。
还有一个类似的函数column_stack和快捷方式c_[...],用于水平(按列)堆叠,以及一个几乎类似的函数hstack,尽管由于某种原因,后者不太灵活(它对输入数组的维度要求更严格,并尝试将1-D数组首尾相连而不是将它们视为列)。
最后,在垂直堆叠1-D数组的特定情况下,以下方法也适用:
numpy.array( LIST )

因为数组可以由其他数组的序列构建而成,从而在开头添加一个新的维度。

8
我认为他想要一个二维数组作为输出。 - Beefster
1
这个答案不正确。 np.concatenate(LIST, axis=0)将会得到一个一维数组。这个答案不应该被接受。 - svebert
@svebert 你读完了吗? - jez

17

从NumPy 1.10版本开始,我们拥有了 stack 方法。它可以堆叠任何维度相同的数组:

# List of arrays.
L = [np.random.randn(5,4,2,5,1,2) for i in range(10)]

# Stack them using axis=0.
M = np.stack(L)
M.shape # == (10,5,4,2,5,1,2)
np.all(M == L) # == True

M = np.stack(L, axis=1)
M.shape # == (5,10,4,2,5,1,2)
np.all(M == L) # == False (Don't Panic)

# This are all true    
np.all(M[:,0,:] == L[0]) # == True
all(np.all(M[:,i,:] == L[i]) for i in range(10)) # == True

享受吧,


14
我检查了一些速度性能的方法,发现它们之间没有区别!唯一的区别就是使用某些方法时,你必须小心地检查维度。

时间:

|------------|----------------|-------------------|
|            | shape (10000)  |  shape (1,10000)  |
|------------|----------------|-------------------|
| np.concat  |    0.18280     |      0.17960      |
|------------|----------------|-------------------|
|  np.stack  |    0.21501     |      0.16465      |
|------------|----------------|-------------------|
| np.vstack  |    0.21501     |      0.17181      |
|------------|----------------|-------------------|
|  np.array  |    0.21656     |      0.16833      |
|------------|----------------|-------------------|

您可以看到我尝试了两个实验 - 使用 np.random.rand(10000)np.random.rand(1, 10000) 如果我们使用二维数组,则np.stacknp.array会创建额外的维度 - 结果形状为(1,10000,10000)和(10000,1,10000),因此它们需要额外的操作来避免这种情况。

代码:

from time import perf_counter
from tqdm import tqdm_notebook
import numpy as np
l = []
for i in tqdm_notebook(range(10000)):
    new_np = np.random.rand(10000)
    l.append(new_np)



start = perf_counter()
stack = np.stack(l, axis=0 )
print(f'np.stack: {perf_counter() - start:.5f}')

start = perf_counter()
vstack = np.vstack(l)
print(f'np.vstack: {perf_counter() - start:.5f}')

start = perf_counter()
wrap = np.array(l)
print(f'np.array: {perf_counter() - start:.5f}')

start = perf_counter()
l = [el.reshape(1,-1) for el in l]
conc = np.concatenate(l, axis=0 )
print(f'np.concatenate: {perf_counter() - start:.5f}')

3

另一种解决方法是使用 asarray 函数:

numpy.asarray( LIST )


0
我发现了一个更加强大的numpy函数reshapestackvstack的问题在于,它们无法处理空列表。
>>> LIST = [np.array([1, 2, 3, 4, 5]), np.array([1, 2, 3, 4, 5]),np.array([1,2,3,4,5])]
>>> s = np.vstack(LIST)
>>> s.shape
(3, 5)
>>> s = np.vstack([])
ValueError: need at least one array to concatenate

另一种选择是reshape

>>> s = np.reshape(LIST, (len(LIST),5))
>>> s.shape
(3, 5)
>>> LIST = []
>>> s = np.reshape(LIST, (len(LIST),5))
>>> s.shape
(0,5)

缺点是,你需要知道内部数组的长度/形状


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