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 次迭代。这意味着对于 运行 程序 1 秒,numpy 列表中的项目不会超过 2500。
我已经实现了一个基本算法,我不确定它是否是计算速度最快的方法 bonus
:
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.vstack
、np.stack
或者 np.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 列表上构建一个队列结构. (Queue 库怎么样?在这种操作中它比 numpy 列表快吗?)
抱歉,如果我的问题太多太复杂了。我只是想在速度上获得最佳性能。
忽略 modify
函数,循环的核心是:
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
处插入值。速度与列表附加方法大致相同。该模型可以移动到 cython
和 typed memoryviews
以获得(潜在的)大速度提升。
大约晚了四年,但是像我这样的人可能会偶然发现这一点,
如果可能,您想使用列表推导式等方法,通常如果您想要速度,这是最好的方法之一,但您最终可能会为了速度而牺牲可读性。
如果附加到文件,证明列表理解比标准 for 循环更快:
https://towardsdatascience.com/speeding-up-python-code-fast-filtering-and-slow-loops-8e11a09a9c2f
例如,如果你想附加到一个列表,你可以做[append_item for append_item in range(range)]
虽然额外的好处(牺牲了可读性)允许您在代码中添加第二个 for 循环:
my_list = [append_item for append_item in range(repetitions) for _ in range(repeat)]
或更整齐:
my_list = [append_item
for append_item in range(repetitions)
for _ in range(repeat)]
然而,此函数可能更有趣的是,您可以在列表定义中执行大量计算的函数。
my_list = [
append_item
for append_item in range(repetitions)
for heavy_comp_item in [function_call]
for _ in range(x)
]
我在此处添加了“for _ in range(x)”,以允许相同值(找到的 heavy_comp_item)的副本 x 次。
抱歉,如果我刚刚给你的东西不能转化为你的代码,但希望这对未来的项目有所帮助:)。
我编写了一些程序,在每次迭代中更新 numpy
列表并对其进行一些操作。迭代次数取决于时间。例如在 1 秒内,可能有 1000 到 2500 次迭代。这意味着对于 运行 程序 1 秒,numpy 列表中的项目不会超过 2500。
我已经实现了一个基本算法,我不确定它是否是计算速度最快的方法 bonus
:
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.vstack
、np.stack
或者np.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 列表上构建一个队列结构. (Queue 库怎么样?在这种操作中它比 numpy 列表快吗?)
抱歉,如果我的问题太多太复杂了。我只是想在速度上获得最佳性能。
忽略 modify
函数,循环的核心是:
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
处插入值。速度与列表附加方法大致相同。该模型可以移动到 cython
和 typed memoryviews
以获得(潜在的)大速度提升。
大约晚了四年,但是像我这样的人可能会偶然发现这一点,
如果可能,您想使用列表推导式等方法,通常如果您想要速度,这是最好的方法之一,但您最终可能会为了速度而牺牲可读性。
如果附加到文件,证明列表理解比标准 for 循环更快: https://towardsdatascience.com/speeding-up-python-code-fast-filtering-and-slow-loops-8e11a09a9c2f
例如,如果你想附加到一个列表,你可以做[append_item for append_item in range(range)]
虽然额外的好处(牺牲了可读性)允许您在代码中添加第二个 for 循环:
my_list = [append_item for append_item in range(repetitions) for _ in range(repeat)]
或更整齐:
my_list = [append_item
for append_item in range(repetitions)
for _ in range(repeat)]
然而,此函数可能更有趣的是,您可以在列表定义中执行大量计算的函数。
my_list = [
append_item
for append_item in range(repetitions)
for heavy_comp_item in [function_call]
for _ in range(x)
]
我在此处添加了“for _ in range(x)”,以允许相同值(找到的 heavy_comp_item)的副本 x 次。
抱歉,如果我刚刚给你的东西不能转化为你的代码,但希望这对未来的项目有所帮助:)。