Python 与astype(int)相比,numpy环绕/打印速度较慢
所以如果我有类似于Python 与astype(int)相比,numpy环绕/打印速度较慢,python,c,assembly,numpy,sse,Python,C,Assembly,Numpy,Sse,所以如果我有类似于x=np.random.rand(60000)*400-200的东西。iPython的%timeit说: x.astype(int)需要0.14毫秒 np.rint(x)和np.around(x)需要1.01ms 请注意,在rint和around情况下,您仍然需要花费额外的0.14毫秒来完成最后的astype(int)(假设这是您最终想要的) 问题:我认为大多数现代硬件都能在相同的时间内完成这两项操作,对吗。如果是这样,为什么numpy的取整时间要长8倍 碰巧,我对算法的精
x=np.random.rand(60000)*400-200的东西。iPython的%timeit
说:
x.astype(int)
需要0.14毫秒
np.rint(x)
和np.around(x)
需要1.01ms
请注意,在rint
和around
情况下,您仍然需要花费额外的0.14毫秒来完成最后的astype(int)
(假设这是您最终想要的)
问题:我认为大多数现代硬件都能在相同的时间内完成这两项操作,对吗。如果是这样,为什么numpy的取整时间要长8倍
碰巧,我对算法的精确性并不过分挑剔,但我看不出如何利用numpy(我在做凌乱的生物学而不是粒子物理学)。正如@jme在评论中指出的那样,rint
和around
函数必须确定是将分数向上舍入还是向下舍入到最接近的整数。相反,astype
函数将始终向下取整,以便可以立即丢弃十进制信息。还有许多其他函数可以做同样的事情。此外,您还可以通过为整数使用较低的位数来提高速度。但是,您必须小心,以适应输入数据的全部范围
%%timeit
np.int8(x)
10000 loops, best of 3: 165 µs per loop
注意,这不会存储-128到127范围之外的值,因为它是8位的。示例中的某些值不在此范围内
在我尝试的所有其他方法中,np.intc
似乎是最快的:
%%timeit
np.int16(x)
10000 loops, best of 3: 186 µs per loop
%%timeit
np.intc(x)
10000 loops, best of 3: 169 µs per loop
%%timeit
np.int0(x)
10000 loops, best of 3: 170 µs per loop
%%timeit
np.int_(x)
10000 loops, best of 3: 188 µs per loop
%%timeit
np.int32(x)
10000 loops, best of 3: 187 µs per loop
%%timeit
np.trunc(x)
1000 loops, best of 3: 940 µs per loop
您的示例,在我的机器上:
%%timeit
np.around(x)
1000 loops, best of 3: 1.48 ms per loop
%%timeit
np.rint(x)
1000 loops, best of 3: 1.49 ms per loop
%%timeit
x.astype(int)
10000 loops, best of 3: 188 µs per loop
np.around(x).astype(int)
和x.astype(int)
不会产生相同的值。前几轮甚至(与((x*x>=0+0.5)+(x*x)相同)我承认我对CPU的算术能力不太熟悉:为什么它们能够在相同的时间内完成?aType只是切掉一些位,舍入操作需要检查切掉多少位(确定是否舍入到较低的整数或较高的整数)。好的,一件事是,从浮点转换为整数类型只需要丢弃小数部分,这相当于向零舍入,而np.rint
舍入到最接近的整数(这是额外的工作)因此,np.trunc
与np.astype(int)更具可比性
。在我的speedtests中,np.trunc
仍然比较慢,但看看,这可能是因为它是根据天花板和地板来实现的,而不是简单的强制转换。似乎有一些低级标志来控制舍入模式,请参见示例:。感谢提供详细信息。我刚刚尝试了将x
设为单色并使用>int32
代替了int
…但运气不好。我还注意到rint
有一个out
参数,可以将其设置为空int32
数组,但这对速度也没有帮助。(我不知道我的numpy是用哪个SSE版本编译的,但可能是SSE2或SSE3,因为这是一台足够好的机器,windows installer应该没有SSE、SSE2和SSE3二进制文件。)@dan man,是的,我试过np.float32和np.int32以及其他版本,但没有改进。但这真的是你的问题吗?“过早优化是万恶之源”。这是numpy开发人员应该担心的问题。我希望numpy开发人员会出现,告诉我一个快速破解或指向我一个已知的错误…如果是这样的话,那是值得的,因为我有一个花费1秒(总时间>50%)的函数在rint
上,我需要调用该函数数百次。但是,是的,我可能应该承认有一定程度的过早优化。(虽然,当我发现这种差异时,我突然想到,可能有一整类这样的事情,其中numpy比它应该慢一个数量级……如果是这样,就值得了解它们。)“丹曼,在这种情况下,你可能想在C.上发布你的函数,看看你得到了什么答案。我通常在我们的工作中,我们中的一些人也使用PyopCopl。你可能想考虑一下。我以前使用过这个,但是我现在可以用C上的OpenMP和SIMD得到足够好的结果。
y = np.trunc(x).astype(int)
z = x.astype(int)
In [165]: x.dtype
Out[165]: dtype('float64')
In [168]: y.dtype
Out[168]: dtype('int64')
_mm_round_pd(a, 0); //round: round even
_mm_round_pd(a, 1); //floor: round towards minus infinity
_mm_round_pd(a, 2); //ceil: round towards positive infinity
_mm_round_pd(a, 3); //trunc: round towards zero
_mm_cvtpd_epi32(a); //round double to int32 then expand to int64
_mm_cvttpd_epi32(a); //trunc double to int32 then expand to int64
_mm_cvtps_epi32(a); //round single to int32
_mm_cvttps_epi32(a) //trunc single to int32