如何快速存储numpy对象(矩阵)?

2024-04-20 07:08:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我必须存储numpy矩阵列表。我试过两种方法:

1.创建一个list并附加到它:

ls_ws=[]
for ind in range(iterations):
    ...
    ls_ws.append(ls_w) # ls_w is a matrix of size 6,1

问题:开始时快,结束时慢。你知道吗

2.创建一个零矩阵并进行修改:

for ind in range(iterations):
    ...
    ls_ws=np.matrix(np.zeros((6,iterations))) 

问题:我不太确定,但无论每次迭代的速度如何,似乎都是一样的。
奇怪的是,如果我把迭代次数设为小数值,速度会很快。但是如果我把它设置为大的数字,比如1500,那么每次迭代(甚至第一次迭代)都非常慢。你知道吗


第二种方法应该是快速的,但是如果我将迭代次数设置为一个大的数字,则速度会非常慢。为什么?如何解决?你知道吗


Tags: 方法innumpyforwsnprange矩阵
2条回答

使用列表的裸体版本:

def foo1(N):
    alist = []
    for _ in range(N):
        alist.append([1,2,3,4,5,6])
    return np.array(alist)

时间以N表示

In [4]: timeit foo1(100)
10000 loops, best of 3: 123 µs per loop
In [5]: timeit foo1(1000)
1000 loops, best of 3: 1.23 ms per loop
In [6]: timeit foo1(10000)
100 loops, best of 3: 12.3 ms per loop
In [7]: timeit foo1(100000)
10 loops, best of 3: 129 ms per loop
In [8]: timeit foo1(1000000)
1 loop, best of 3: 1.29 s per loop
In [9]: timeit foo1(10000000)
1 loop, best of 3: 12.9 s per loop

List append有可能在使用大型列表时变慢。列表使用一个缓冲区来保存指针,再加上一些扩展空间。当它超出这个空间时,它必须得到更多。如果不能“就地”展开,就必须请求新的空间并复制所有指针。这可能会减慢非常大的列表接近填满内存的速度。随着时间从123点到129点,我可能看到了一些暗示

def foo2(N):
    out = np.zeros((N,6),int)
    for i in range(N):
        out[i,:] = [1,2,3,4,5,6]
    return out

时间也以N为单位,是列表大小写的两倍:

In [15]: timeit foo2(100)
1000 loops, best of 3: 242 µs per loop
In [16]: timeit foo2(1000)
100 loops, best of 3: 2.52 ms per loop
In [17]: timeit foo2(10000)
10 loops, best of 3: 24.6 ms per loop
In [18]: timeit foo2(100000)
1 loop, best of 3: 249 ms per loop
In [19]: timeit foo2(1000000)
1 loop, best of 3: 2.52 s per loop
In [20]: timeit foo2(10000000)
1 loop, best of 3: 25.2 s per loop

迭代最后一个维度在时间上没有区别

def foo3(N):
    out = np.zeros((6,N),int)
    for i in range(N):
        out[:,i] = [1,2,3,4,5,6]
    return out

一次只分配/创建6个元素而迭代1000次是很糟糕的numpy实践。如果必须迭代,最好循环几次,每次都执行大型操作。例如6个循环,有1000个项目数组。你知道吗

如果我将迭代向下移动到编译代码,时间会快得多

def foo4(N):
    out = np.zeros((N,6),int)
    out[...] = [1,2,3,4,5,6]
    return out

In [28]: timeit foo4(1000)
.... cached.
10000 loops, best of 3: 20.4 µs per loop
In [29]: timeit foo4(100000)
1000 loops, best of 3: 1.45 ms per loop

你谈到保存一个矩阵,甚至分配一个np.matrix。让我们看看它有什么影响:

def foo1m(N):
    alist = []
    for _ in range(N):
        alist.append(np.matrix([1,2,3,4,5,6]).T)
    return np.concatenate(alist, axis=1)

def foo2m(N):
    out = np.matrix(np.zeros((6,N),int))
    for i in range(N):
        out[:,i] = np.matrix([1,2,3,4,5,6]).T
    return out

In [62]: timeit foo1(1000)
1000 loops, best of 3: 1.32 ms per loop
In [63]: timeit foo1m(1000)
100 loops, best of 3: 18 ms per loop
In [64]: timeit foo2(1000)
100 loops, best of 3: 2.75 ms per loop
In [65]: timeit foo2m(1000)
10 loops, best of 3: 28.2 ms per loop

这使得每次迭代的时间延长了10倍。matrixndarray的一个子类,需要更多的处理(强制它到2d等)。你知道吗

我认为这里有一个很好的解决方案,但是您对列和行的处理可能会影响性能:

ls_ws=np.matrix(np.zeros((6,iterations))) 
for ind in range(iterations):
    ...
    ls_ws[:,ind]=ls_w

您应该在第一个维度而不是最后一个维度中进行迭代。您可以交换尺寸,或者只需执行以下操作:

ls_ws=np.matrix(np.zeros((6,iterations), order='F')) 

当数组较大时,这可能会有所帮助,因为您将访问由6个元素组成的连续块,而不是每个迭代中分散的位。你知道吗

相关问题 更多 >