我做了一些实验,发现许多情况下python的标准random
和math
库比numpy
对应库快。
我认为,对于小规模的操作,python的标准库有大约10倍的速度增长,而对于大规模(矢量)操作,numpy
则有更快的趋势。我的猜测是numpy
有一些开销,在小情况下会占主导地位。
我的问题是:我的直觉正确吗?在小型(通常是标量)操作中,通常建议使用标准库而不是numpy
吗?
示例如下。
import math
import random
import numpy as np
日志和指数
%timeit math.log(10)
# 158 ns ± 6.16 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit np.log(10)
# 1.64 µs ± 93.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit math.exp(3)
# 146 ns ± 8.57 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit np.exp(3)
# 1.72 µs ± 78.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
生成正态分布
%timeit random.gauss(0, 1)
# 809 ns ± 12.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit np.random.normal()
# 2.57 µs ± 14.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
选择随机元素
%timeit random.choices([1,2,3], k=1)
# 1.56 µs ± 55.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit np.random.choice([1,2,3], size=1)
# 23.1 µs ± 1.04 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
与numpy数组相同
arr = np.array([1,2,3])
%timeit random.choices(arr, k=1)
# 1.72 µs ± 33.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit np.random.choice(arr, size=1)
# 18.4 µs ± 502 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
大阵列
arr = np.arange(10000)
%timeit random.choices(arr, k=1000)
# 401 µs ± 6.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit np.random.choice(arr, size=1000)
# 41.7 µs ± 1.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
答案 0 :(得分:5)
numpy
实际上只是对大数据块的性能改进。如果将数组ndarray
插入c编译的numpy
函数中,确保数组正确对齐的开销通常会浪费很多时间,如果数组不是相对较大的话。这就是为什么如此多的numpy
问题基本上是“我如何使用此循环代码并使之快速运行”的原因,以及为什么在几乎所有其他标签都将您扔向{{3 }},直到他们超越标题。
所以,是的,您的观察是可概括的。向量化是numpy
的重点。未向量化的numpy
代码总是比裸python
代码要慢,并且可以说与用手提钻破解单个胡桃木一样“错误”。找到合适的工具,或者得到更多的螺母。
答案 1 :(得分:4)
NumPy主要用于数组的性能。这依赖于使用连续的内存块和更有效的低级迭代。在标量上应用NumPy数学函数或计算随机数不是矢量化操作。这说明了您所看到的行为。
另请参阅What are the advantages of NumPy over regular Python lists?
通常建议使用标准库而不是 比NumPy小(通常是标量)运算?
很少有程序的瓶颈是由标量运算引起的。实际上,差异可以忽略不计。所以这两种方法都很好。如果您已经在使用NumPy,则继续在标量上使用NumPy操作没有任何危害。
值得一提特殊情况下计算随机数。如您所料,通过random
和NumPy选择的随机数可能不同:
assert random.gauss(0, 1) == np.random.normal() # AssertionError
assert random.choices(arr, k=1)[0] == np.random.choice(arr, size=1)[0] # AssertionError
您在NumPy中具有其他功能,可以使随机数“可预测”。例如,重复运行以下脚本只会产生相同的结果:
np.random.seed(0)
np.random.normal()
np.random.choice
也是如此。因此,方法的不同之处在于随机数的导出方式和可用功能。为了测试或其他目的,您可能希望能够产生一致的“随机”数字。