如何将 N 维 numpy 数组按元素转换为列表

How to convert N-D numpy arrays element-wise to list

我有两个 numpy 数组:

A = [[1,2,3],
     [4,5,6]]


B = [[-1,-2,-3],
     [-4,-5,-6]]

我想将两者组合成一个普通的 python 列表,这样每个数组中的 (i,j) 元素都放在同一个列表中:

C= [[1,-1],[2,-2],[3,-3],[4,-4],[5,-5],[6,-6]]

有没有比天真的 O(n^2) 更好的方法?

您可以在 O(n) 中完成:

A = np.array([[1,2,3],
              [4,5,6]])
B = np.array([[-1,-2,-3],
              [-4,-5,-6]])

C = list(map(list, zip(A.ravel(), B.ravel())))

输出:

[[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]

如果您不介意元组:

C = list(zip(A.ravel(), B.ravel()))

输出:

[(1, -1), (2, -2), (3, -3), (4, -4), (5, -5), (6, -6)]

您可以将它们转换为 np.array、重塑和转置:

out = np.array([A,B]).reshape(2,-1).T.tolist()

或遍历子列表并使用 zip:

out = [list(tpl) for i in range(len(A)) for tpl in zip(A[i], B[i])]

输出:

[[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]

备选方案,仅限 NumPy,已接受答案的解决方案:

A = np.array([[1,2,3],
              [4,5,6]])

B = np.array([[-1,-2,-3],
              [-4,-5,-6]])

C = np.column_stack((A.ravel(),B.ravel())).tolist()

输出:

[[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]

首先,您显示两个列表,但称它们为数组。

In [102]: A = [[1,2,3],
     ...:      [4,5,6]]
     ...: B = [[-1,-2,-3],
     ...:      [-4,-5,-6]]

纯数组方法的一个版本:

In [103]: [[i,j] for a,b in zip(A,B) for i,j in zip(a,b)]
Out[103]: [[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]

还有一种 numpy 方法 - 这适用于列表或数组,因为 np.stack 根据需要将列表转换为数组。

In [104]: np.stack((A,B),axis=2).reshape(-1,2).tolist()
Out[104]: [[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]

np.array((A,B))也可以使用,但需要一些转置;但这很便宜。

O(n) 分析在评估此类备选方案时没那么有用。最大的区别是在 python 中迭代,就像双列表理解那样,或者使用 numpy 数组方法(在编译代码中迭代)。但这也有细微差别。数组的迭代速度较慢。从列表创建数组需要时间。还有一个缩放问题。数组方法通常具有较高的设置成本,但扩展性更好。

让我们比较一下时间:

In [105]: timeit [[i,j] for a,b in zip(A,B) for i,j in zip(a,b)]
1.69 µs ± 29.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [106]: timeit np.stack((A,B),axis=2).reshape(-1,2).tolist()
22.2 µs ± 1.37 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [107]: %%timeit A1=np.array(A); B1=np.array(B)
     ...: np.stack((A1,B1),axis=2).reshape(-1,2).tolist()
14.5 µs ± 65.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

对于这个小例子,纯列表方法是最快的。从数组而不是列表开始改进了数组方法,但它仍然较慢。

尝试更大的东西:

In [109]: AA = np.ones((200,300)).tolist()
In [110]: timeit [[i,j] for a,b in zip(AA,AA) for i,j in zip(a,b)]
10.4 ms ± 19.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [111]: %%timeit A1=np.array(AA); B1=np.array(AA)
     ...: np.stack((A1,B1),axis=2).reshape(-1,2).tolist()
13.4 ms ± 334 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

仍然不足以让阵列发挥优势。

但是如果我们放弃结果是列表的要求呢?

In [119]: %%timeit A1=np.array(AA); B1=np.array(AA)
     ...: np.stack((A1,B1),axis=2).reshape(-1,2)
144 µs ± 4.78 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

tolist() 已编译且相对较快,但对于足够大的数组来说仍然需要时间。

总而言之 - 如果您从列表开始,return 一个列表,那么纯列表方法仍然是最好的。但是以数组开始和结束可以更快。混合列表和数组会降低两者的速度。

接受答案中的映射:

In [120]: %%timeit A1=np.array(AA); B1=np.array(AA)
     ...: C = list(map(list, zip(A1.ravel(), B1.ravel())))
16.2 ms ± 44.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)