如果单个整数具有 python 原生 int 类型,则将单个整数添加到 numpy 数组会更快

bpr*_*auf 7 python arrays integer numpy

我将一个整数添加到包含 1000 个元素的整数数组中。当我第一次将单个整数转换为numpy.int64python-native时,速度提高了 25% int。

\n

为什么?作为一般经验法则,我是否应该将单个数字转换为本机 python 格式,以便对大约此大小的数组进行单个数字到数组的操作?

\n

注意:可能与我之前的问题Conjugating a complex number much fast if number has python-native complex type 有关。

\n
import numpy as np\n\nnnu = 10418\nnnu_use = 5210\na = np.random.randint(nnu,size=1000)\nb = np.random.randint(nnu_use,size=1)[0]\n\n%timeit a + b                            # --> 3.9 \xc2\xb5s \xc2\xb1 19.9 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 100000 loops each)\n%timeit a + int(b)                       # --> 2.87 \xc2\xb5s \xc2\xb1 8.07 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 100000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

请注意,对于标量到标量操作,加速也可能是巨大的(因子 50),如下所示:

\n
np.random.seed(100)\n\na = (np.random.rand(1))[0]\na_native = float(a)\nb = complex(np.random.rand(1)+1j*np.random.rand(1))\nc = (np.random.rand(1)+1j*np.random.rand(1))[0]\nc_native = complex(c)\n\n%timeit a * (b - b.conjugate() * c)                # 6.48 \xc2\xb5s \xc2\xb1 49.7 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 100000 loops each)\n%timeit a_native * (b - b.conjugate() * c_native)  # 283 ns \xc2\xb1 7.78 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n%timeit a * b                                      # 5.07 \xc2\xb5s \xc2\xb1 17.7 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 100000 loops each)\n%timeit a_native * b                               # 94.5 ns \xc2\xb1 0.868 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

更新:最新的 numpy 版本是否修复了速度差异?numpy 的发行说明1.23提到标量操作现在要快得多,请参阅https://numpy.org/devdocs/release/1.23.0-notes.html#performance-improvements-and-changes和https://github.com /numpy/numpy/pull/21188。我在用python 3.7.6, numpy 1.21.2。

\n

Jér*_*ard 1

在装有 CPython 3.8.1 的 Windows PC 上,我得到:

\n
[Old] Numpy 1.22.4:\n - First test: 1.65 \xc2\xb5s VS 1.43 \xc2\xb5s\n - Second:     2.03 \xc2\xb5s VS 0.17 \xc2\xb5s\n\n[New] Numpy 1.23.1:\n - First test: 1.38 \xc2\xb5s VS 1.24 \xc2\xb5s    <----  A bit better than Numpy 1.22.4\n - Second:     0.38 \xc2\xb5s VS 0.17 \xc2\xb5s    <----  Much better than Numpy 1.22.4\n
Run Code Online (Sandbox Code Playgroud)\n\n

虽然新版本的 Numpy 提供了良好的提升,但本机类型应该始终比使用(默认)CPython解释器的Numpy 更快。事实上,解释器需要调用Numpy的C函数。本机类型不需要这样做。此外,Numpy 检查和包装并不是最优的,但 Numpy 最初并不是为快速标量计算而设计的(尽管以前的开销并不合理)。事实上,标量计算效率非常低,并且解释器会阻止任何快速执行。

\n

如果您计划执行许多标量操作,则需要使用本机编译的代码,可能使用 Cython、Numba,甚至原始 C/C++ 模块。请注意,Cython 不会优化/内联 Numpy 调用,但可以更快地对本机类型进行操作。本机代码当然可以在一个甚至两个数量级的时间内完成此操作。

\n

请注意,在第一种情况下,Numpy 函数中的路径不相同,并且 Numpy 会进行额外的检查,这比该值不是 CPython 对象要昂贵一些。尽管如此,它应该是一个恒定的开销(现在相对较小)。否则,这将是一个错误(并且应该报告)。

\n

相关:为什么np.sum(range(N))很慢?

\n