首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >np.empty、np.zeros和np.ones的性能

np.empty、np.zeros和np.ones的性能
EN

Stack Overflow用户
提问于 2019-03-13 15:29:21
回答 1查看 1K关注 0票数 5

我很好奇使用np.empty而不是np.zeros有多大的区别,以及与np.ones的区别。我运行这个小脚本来基准测试每一个创建一个大数组所花费的时间:

代码语言:javascript
复制
import numpy as np
from timeit import timeit

N = 10_000_000
dtypes = [np.int8, np.int16, np.int32, np.int64,
          np.uint8, np.uint16, np.uint32, np.uint64,
          np.float16, np.float32, np.float64]
rep= 100
print(f'{"DType":8s} {"Empty":>10s} {"Zeros":>10s} {"Ones":>10s}')
for dtype in dtypes:
    name = dtype.__name__
    time_empty = timeit(lambda: np.empty(N, dtype=dtype), number=rep) / rep
    time_zeros = timeit(lambda: np.zeros(N, dtype=dtype), number=rep) / rep
    time_ones = timeit(lambda: np.ones(N, dtype=dtype), number=rep) / rep
    print(f'{name:8s} {time_empty:10.2e} {time_zeros:10.2e} {time_ones:10.2e}')

并得到了下表:

代码语言:javascript
复制
DType         Empty      Zeros       Ones
int8       1.39e-04   1.76e-04   5.27e-03
int16      3.72e-04   3.59e-04   1.09e-02
int32      5.85e-04   5.81e-04   2.16e-02
int64      1.28e-03   1.13e-03   3.98e-02
uint8      1.66e-04   1.62e-04   5.22e-03
uint16     2.79e-04   2.82e-04   9.49e-03
uint32     5.65e-04   5.20e-04   1.99e-02
uint64     1.16e-03   1.24e-03   4.18e-02
float16    3.21e-04   2.95e-04   1.06e-02
float32    6.31e-04   6.06e-04   2.32e-02
float64    1.18e-03   1.16e-03   4.85e-02

从中我得出了两个有点令人惊讶的结论:

  • np.emptynp.zeros的性能几乎没有差别,可能除了int8的一些差异外。我不明白为什么会这样。创建空数组应该更快,实际上我已经看到了这方面的报告(例如Speed of np.empty vs np.zeros)。
  • np.zerosnp.ones有很大的不同。我怀疑这与内存零化的高性能手段有关,这些方法不适用于用常量填充内存区域,但我不知道如何或在哪一级工作。

这些结果的解释是什么?

我在Windows 10上使用NumPy 1.15.4和Python3.6Anaconda(用MKL),我有一个IntelCorei7-7700KCPU。

编辑:根据评论中的一项建议,我尝试运行基准测试,将每一次试验交织在一起,并在结束时进行平均,但我看不到结果的显著差异。不过,在一个相关的问题上,我不知道NumPy中是否有任何机制来重用刚刚删除的数组的内存,这将使度量变得不现实(尽管时间似乎与数据类型的大小相关,甚至对于空数组也是如此)。

EN

回答 1

Stack Overflow用户

发布于 2019-03-13 16:04:41

这真的应该是一个评论,但它不适合。这里是您的脚本的一个小扩展。一些“手工”版本的zerosones

代码语言:javascript
复制
import numpy as np
from timeit import timeit

N = 10_000_000
dtypes = [np.int8, np.int16, np.int32, np.int64,
          np.uint8, np.uint16, np.uint32, np.uint64,
          np.float16, np.float32, np.float64]
rep= 100
print(f'{"DType":8s} {"Empty":>10s} {"Zeros":>10s} {"Ones":>10s}')
for dtype in dtypes:
    name = dtype.__name__
    time_empty = timeit(lambda: np.empty(N, dtype=dtype), number=rep) / rep
    time_zeros = timeit(lambda: np.zeros(N, dtype=dtype), number=rep) / rep
    time_ones = timeit(lambda: np.ones(N, dtype=dtype), number=rep) / rep
    time_full_zeros = timeit(lambda: np.full(N, 0, dtype=dtype), number=rep) / rep
    time_full_ones = timeit(lambda: np.full(N, 1, dtype=dtype), number=rep) / rep
    time_empty_zeros = timeit(lambda: np.copyto(np.empty(N, dtype=dtype), 0), number=rep) / rep
    time_empty_ones = timeit(lambda: np.copyto(np.empty(N, dtype=dtype), 1), number=rep) / rep
    print(f'{name:8s} {time_empty:10.2e} {time_zeros:10.2e} {time_ones:10.2e} {time_full_zeros:10.2e} {time_full_ones:10.2e}  {time_empty_zeros:10.2e} {time_empty_ones:10.2e} ')

时间是有暗示性的。

代码语言:javascript
复制
DType         Empty      Zeros       Ones
int8       1.37e-06   6.33e-04   5.73e-04   5.76e-04   5.73e-04    6.05e-04   5.82e-04 
int16      1.61e-06   1.55e-03   3.54e-03   3.54e-03   3.56e-03    3.54e-03   3.54e-03 
int32      7.22e-06   6.99e-06   1.24e-02   1.20e-02   1.25e-02    1.19e-02   1.21e-02 
int64      8.26e-06   8.06e-06   2.62e-02   2.64e-02   2.61e-02    2.62e-02   2.62e-02 
uint8      1.32e-06   6.30e-04   5.85e-04   5.86e-04   5.77e-04    5.70e-04   5.83e-04 
uint16     1.32e-06   1.63e-03   3.61e-03   3.65e-03   4.08e-03    4.08e-03   3.58e-03 
uint32     7.08e-06   7.20e-06   1.48e-02   1.41e-02   1.63e-02    1.44e-02   1.32e-02 
uint64     7.14e-06   7.13e-06   2.69e-02   2.67e-02   2.82e-02    2.68e-02   2.72e-02 
float16    1.31e-06   1.55e-03   3.56e-03   3.79e-03   3.54e-03    3.53e-03   3.55e-03 
float32    7.11e-06   6.95e-06   1.36e-02   1.35e-02   1.37e-02    1.35e-02   1.37e-02 
float64    7.27e-06   7.33e-06   3.13e-02   3.00e-02   2.75e-02    2.80e-02   2.75e-02 

Re zerosones更快,我似乎记得,正如注释中所建议的,zeros确实使用了calloc,这是一个系统例程,其唯一目的是分配零位块,这可能是很好的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55145592

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档