我必须在数据处理管道中做很多<< >>产品。因此,我正在试验以下两段代码,其中一段代码的效率是最慢的3倍(就运行时而言)。最慢的方法(动态创建数组)
In [33]: %timeit np.dot(np.arange(200000), np.arange(200000, 400000))
352 µs ± 958 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
最快的方法(带有静态数组)
In [34]: vec1_arr = np.arange(200000)
In [35]: vec2_arr = np.arange(200000, 400000)
In [36]: %timeit np.dot(vec1_arr, vec2_arr)
121 µs ± 90.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
为什么数组的第一种方法比第二种方法慢3倍?是否是因为在第一种方法中,这些额外时间中有很多是花在为元素分配内存上?还是其他一些导致这种降解的因素?动态生成
In [42]: %timeit sum(map(operator.mul, range(200000), range(200000, 400000)))
12.5 ms ± 71.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
:纯Python隐式表示。只是为了使自己确信数组分配可能是导致拖累的因素。这并不是要与NumPy实现进行比较。我必须在我的数据处理管道中做很多点产品。因此,我正在试验以下两段代码,其中一段代码与...In [38]: vec1 = range(200000) In [39]: vec2 = range(200000, 400000) In [40]: %timeit sum(map(operator.mul, vec1, vec2)) 12.5 ms ± 27.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
纯Python情况下的行为很明显,因为range
函数实际上并未创建所有这些元素。它会进行惰性评估(即即时生成)。Note
np.arange(200000)
实际上返回数组,而range(200000)
仅返回生成器。因此,这两种方法都可以动态创建数组。import operator
%timeit sum(map(operator.mul, range(200000), range(200000, 400000)))
# 15.1 ms ± 45.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
vec1 = range(200000)
vec2 = range(200000, 400000)
%timeit sum(map(operator.mul, vec1, vec2))
# 15.2 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
vec1 = list(range(200000))
vec2 = list(range(200000, 400000))
%timeit sum(map(operator.mul, vec1, vec2))
# 12.4 ms ± 716 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit
的输出,该输出考虑了两种情况下数组的分配。 OP的timeit命令仅在较慢的情况下考虑分配,而在较快的情况下不考虑分配。