有效地将3D Numpy阵列重塑为1D List Plus坐标向量

时间:2015-12-07 02:51:14

标签: python arrays numpy optimization

我有一个大型嵌套数组a(256x256x256),我需要将其重组为包含以下元素的列表:

[ (i,j,k), a[i,j,k] ]

我目前正在执行以下操作:

aflat = a.flatten().tolist()
coords = list(itertools.product(range(256), repeat=3))
thelist = [list(x) for x in zip(coords, aflat)]

这样可行,但速度相当慢。

我可以通过删除坐标向量的运行时生成并从文件中读取它们来节省大约一秒钟。然而,主要的减速似乎是在最后一行,时间超过6秒。

有没有更快的方法来生成我在Python中需要的数据结构?

2 个答案:

答案 0 :(得分:1)

正如@ P-i评论的那样,主要的问题是代码会创建大量的列表,而Python则花费大量时间进行内存管理。要消除这种情况,您可以使用numpy数组预分配数据,并使用其var selectCommand = "SELECT * FROM CashFlow WHERE userID=@userId ORDER BY TimeStamp"; var cmd = new MySqlCommand(readCommand); cmd.Parameters.AddWithValue("@userId", Session["New"].ToString()); repeat函数生成tile值:

i,j,k

这会产生一个数组,其中每一行都是# order='F' is important here so column-wise assignment can # occur with a stride of 1. Switching the order results # in a significant performance hit. coords = numpy.zeros([a.size,4],'d',order='F') NI, NJ, NK = a.shape # build columns for (i,j,k) tuples using repeat and tile coords[:,0] = numpy.repeat(range(NI),NJ*NK) coords[:,1] = numpy.tile(numpy.repeat(range(NJ),NK), NI) coords[:,2] = numpy.tile(range(NK), NI*NJ) coords[:,3] = a.flatten() 。它确实假设你的原始数组是row-major排序(C-ordered数组在numpy中)。

在我的计时中,基于2013年MacBook Pro上的Python 3.5中的十次迭代,每次转换需要大约20秒来运行OP的转换,并且使用此方法每次转换仅需要大约8秒。

输出格式实际上必须是一个列表,数组可以在最后一步转换成一个列表。但是,在我的测试中,每次转换的转换时间增加到13秒。

答案 1 :(得分:0)

要扩展上面的@ wii评论,您需要np.ndenumerate

通常,您将避免显式创建列表并使用迭代器。例如:

for (i,j,k), val in np.ndenumerate(your_3d_array):
    assert val == your_3d_array[i,j,k]

# Note that we also could have done:
for ind, val in np.ndenumerate(your_3d_array):
    assert val == your_3d_array[ind]

但是,如果您确实想要创建完整的中间列表,则可以使用:

list(np.ndenumerate(your_3d_array))

作为一个更完整的例子:

In [1]: import numpy as np

In [2]: x = np.arange(3*4*5).reshape(3, 4, 5)

In [3]: x
Out[7]:
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34],
        [35, 36, 37, 38, 39]],

       [[40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49],
        [50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59]]])

In  [4]: list(np.ndenumerate(x))
Out [4]: 
[((0, 0, 0), 0),
 ((0, 0, 1), 1),
 ((0, 0, 2), 2),
 ((0, 0, 3), 3),
...
 ((2, 3, 1), 56),
 ((2, 3, 2), 57),
 ((2, 3, 3), 58),
 ((2, 3, 4), 59)]