关于python:哪个是更快的np.vstack,np.append,np.concatenate或cython中的手动函数?

which one is faster np.vstack, np.append, np.concatenate or a manual function made in cython?

我编写了一些程序,该程序在每次迭代中都会更新numpy列表并对其进行一些操作。迭代次数取决于时间。例如1秒内,可能会有1000到2500次迭代。这意味着numpy列表中的项目在运行1秒钟时不会超过2500。

我已经实现了一个基本算法,我不确定这是否是计算bonus的最快方法:

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
import numpy as np

cdef int[:, :] pl_list
cdef list pl_length
cdef list bonus
pl_list = np.array([[8, 7]], dtype=np.int32)

def modify(pl_list, pl_length):
    cdef int k_const = 10
    mean = np.mean(pl_list, axis=0)
    mean = np.subtract(mean, pl_length)
    dev = np.std(pl_list, axis=0)
    mean[0] / dev[0] if dev[0] != 0 else 0
    mean[1] / dev[1] if dev[1] != 0 else 0

    bonus = -1 + (2 / (1 + np.exp(-k_const * mean)))
    return list(bonus)


for i in range(2499): # I just simplified the loop. the main loop works like startTime - time.clock() < seconds
    rand = np.random.randint(8, 64)
    pl_length = [rand, rand-1]

    pl_list = np.append(pl_list, [pl_length], axis=0)
    bonus = modify(pl_list, pl_length)

我当时正在考虑使用以下思路来加速该程序:

  • 使用np.vstacknp.stacknp.concatenate而不是np.append(pl_list, [pl_length])。(哪个可能更快?)
  • 使用自制函数来计算np.std,np.mean(因为在cython中在内存视图中迭代如此之快):

    cdef int i,sm = 0
    for i in range(pl_list.shape[0]):
    sm += pl_list[i]
    mean = sm/pl_list.shape[0]

  • 我还考虑为内存视图定义一个静态长度(例如2500),所以我不需要使用np.append,并且可以在该numpy列表上建立队列结构。 (队列库怎么样?在这种操作中,它比numpy列表快吗?)

  • 对不起,如果我的问题太多且太复杂。我只是想在速度上获得最佳性能。


    忽略modify函数,循环的核心是:

    1
    2
    3
    4
    5
    6
    7
    pl_list = np.array([[8, 7]], dtype=np.int32)
    ....

    for i in range(2499):
        ....
        pl_list = np.append(pl_list, [pl_length], axis=0)
        ...

    作为一般规则,我们不建议在循环中使用np.concatenate及其派生词。追加到列表,并在最后一次连接一次,速度更快。 (稍后会详细介绍)

    pl_list是列表还是数组?顾名思义,它是一个列表,但创建时它是一个数组。我还没有研究modify来查看它是否需要数组或列表。

    查看诸如np.append之类的功能的源代码。基本函数是np.concatenate,它接受一个列表,并将它们沿指定的轴连接到新数组中。换句话说,它适用于一长串数组。

    np.append用2个参数替换该列表输入。因此,必须迭代地应用它。那太慢了。每个追加都会创建一个新数组。

    np.hstack仅确保列表元素至少为1d,np.vstack使它们为2d,stack添加一个尺寸,依此类推。因此,基本上它们都做相同的事情,只是对输入做了些微调整。 >

    另一个模型是分配一个足够大的数组作为开始,例如res = np.zeros((n,2)),并在res[i,:] = new_value处插入值。速度与列表附加方法大致相同。可以将此模型移至cythontyped memoryviews,以(可能)大大提高速度。