速度比较。numpy与python标准

速度比较。numpy与python标准,python,numpy,random,Python,Numpy,Random,我做了一些实验,发现python的标准random和math库比对应的numpy库更快 我认为有一种趋势,python的标准库对于小规模操作大约快10倍,而对于大规模(向量)操作,numpy则快得多。我的猜测是,numpy有一些开销,这在小案例中占主导地位 我的问题是:我的直觉正确吗?对于小型(通常为标量)操作,一般建议使用标准库而不是numpy 例子如下 import math import random import numpy as np 对数和指数 %timeit math.log(1

我做了一些实验,发现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)
使用大数组

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)

numpy
实际上只是对大数据块的性能改进。在将
ndarray
注入c编译的
numpy
函数之前,确保内存块正确排列的开销通常会压倒数组相对较小时的任何时间优势。这就是为什么如此多的
numpy
问题基本上都是“我如何处理这个循环代码并使其快速运行”,以及为什么在这个标签中它被认为是一个有效的问题,而几乎任何其他标签都会在它们通过标题之前将您抛向它


所以,是的,你的观察是可以概括的。矢量化是
numpy
的全部要点<代码>numpy未矢量化的代码总是比裸
python
代码慢,而且可以说就像用手提钻敲打一颗核桃一样“错误”。要么找到合适的工具,要么多找些螺母。

NumPy主要用于阵列的性能。这依赖于使用连续内存块和更高效的低级迭代。对标量应用NumPy数学函数或计算随机数不是可向量化的操作。这就解释了你所看到的行为

另见

一般来说,使用标准库而不是 对于小型(通常为标量)操作,是否比NumPy更适合

很少有程序的瓶颈是由标量操作引起的。在实践中,这些差异可以忽略不计。所以两种方法都可以。如果您已经在使用NumPy,那么继续在标量上使用NumPy操作是没有害处的

值得做一个计算随机数的特例。正如您所料,通过
random
vs 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
。因此,随机数的推导方式和可用功能存在差异。出于测试或其他目的,您可能希望能够生成一致的“随机”数字。

看起来您回答了自己的问题…@Julien表面上看,但也许numpy专家可以插话并连接一些点。@Julien很好,我想知道我的实验是否可以推广。我不是专家,但使用numpy确实会有一些开销:原生到numpy对象(c++)转换/额外的安全检查/规则等等。。。如果您使用的是小型阵列,那么使用numpy通常不会更快,关键点在哪里很大程度上取决于您正在做什么。像您这样的定时测试通常是确定您应该使用numpy还是保持原生状态的唯一方法(如果性能是您唯一关心的问题,numpy功能可以是一个奖金,而不管性能如何)…无论如何,我有这样的观察,我想得到一些确认。谢谢你的提问!所以,如果你有足够的核桃,手提钻是打碎核桃的合适工具?;-)@PaulPanzer更像一个程序员,这是创造隐喻的错误工具。谢谢。我同意这种瓶颈严重的情况很少发生。我碰巧经历了一次,因为我需要编写一个基于树的算法,在向下遍历树的过程中,我在每个节点上进行一个小的计算,其中矢量化是不直接的,甚至是不可能的。当我从numpy切换到python标准时,我看到整个算法的运行速度快了几倍。我还注意到标准库中还有
random.seed
。我不认为这对于麻木是特别的。“KotaMori,你应该考虑<代码> NUBA。如果您可以将循环放在JIT编译的函数中,您可能会看到性能的巨大改进。