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