【问题标题】:Fancy indexing much faster than numpy.take?花式索引比 numpy.take 快得多?
【发布时间】:2017-08-01 14:41:40
【问题描述】:

我在许多不同的地方读到numpy.take 是一种比花哨索引更快的替代方案,例如herehere

但是,我发现情况并非如此……完全没有。以下是我在调试期间查看代码时的示例:

knn_idx
Out[2]: 
array([ 3290,  5847,  7682,  6957, 22660,  5482, 22661, 10965,     7,
        1477,  7681,     3, 17541, 15717,  9139,  1475, 14251,  4400,
        7680,  9140,  4758, 22289,  7679,  8407, 20101, 15718, 15716,
        8405, 15710, 20829, 22662], dtype=uint32)
%timeit X.take(knn_idx, axis=0)
100 loops, best of 3: 3.14 ms per loop
%timeit X[knn_idx]
The slowest run took 60.61 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 5.48 µs per loop
X.shape
Out[5]: 
(23011, 30)
X.dtype
Out[6]: 
dtype('float64')

这表明花式索引要快得多!使用numpy.arange 生成索引我得到了类似的结果:

idx = np.arange(0, len(X), 100)
%timeit X.take(idx, axis=0)
100 loops, best of 3: 3.04 ms per loop
%timeit X[idx]
The slowest run took 9.41 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 20.7 µs per loop

为什么花式索引比现在使用numpy.take 快得多?我遇到了某种极端情况吗?

我通过 Anaconda 使用 Python 3.6,如果相关,这是我的 numpy 信息:

np.__version__
Out[11]: 
'1.11.3'
np.__config__.show()
blas_mkl_info:
    libraries = ['mkl_core_dll', 'mkl_intel_lp64_dll', 'mkl_intel_thread_dll']
    library_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\include']
blas_opt_info:
    libraries = ['mkl_core_dll', 'mkl_intel_lp64_dll', 'mkl_intel_thread_dll']
    library_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\include']
openblas_lapack_info:
  NOT AVAILABLE
lapack_mkl_info:
    libraries = ['mkl_core_dll', 'mkl_intel_lp64_dll', 'mkl_intel_thread_dll']
    library_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\include']
lapack_opt_info:
    libraries = ['mkl_core_dll', 'mkl_intel_lp64_dll', 'mkl_intel_thread_dll']
    library_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['C:/Users/pbreach/Continuum/Anaconda3\\Library\\include']

【问题讨论】:

    标签: python arrays performance numpy indexing


    【解决方案1】:

    在我的测试中,take 稍微快一些;但是由于时间短和“缓存”警告,我并没有在差异中投入大量库存:

    In [192]: timeit X.take(idx2, axis=0).shape
    The slowest run took 23.29 times longer than the fastest. This could mean that an intermediate result is being cached.
    100000 loops, best of 3: 3.66 µs per loop
    In [193]: timeit X[idx2,:].shape
    The slowest run took 16.75 times longer than the fastest. This could mean that an intermediate result is being cached.
    100000 loops, best of 3: 5.58 µs per loop
    

    但是你的索引数组是uint32。这对索引很有效,但是 take 给了我一个转换错误;所以我的idx2astype(int)

    使用 arange idx,时间分别为 11.5 µs、16 µs。

    请注意,我正在使用 .shape 进行计时;我不完全确定这会有所不同。

    我不知道您为什么会收到ms 次。感觉更像是时间问题,而不是take 的实际差异。

    我不认为图书馆、BLAS 等会有所作为。底层任务基本相同——单步执行数据缓冲区并复制选定的字节。没有复杂的计算可以解决。但是我没有研究过take的C代码。

    Numpy 版本“1.12.0”,Linux,4gb 翻新桌面。

    【讨论】:

    • 奇怪,在我的第二个问题测试中,我使用了int32 的索引数组,但仍然得到与第一个相似的时间。
    • 即使在最慢的运行中,使用int32 索引仍然快 15 倍左右。
    • 好点现在我想知道take 在我的具体情况下可能有什么问题,而不是一般情况下。我也会尝试在时间中包含shape
    猜你喜欢
    • 2013-01-07
    • 2013-01-01
    • 2017-12-30
    • 2012-12-27
    • 2012-08-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多