python - 为什么 np.compress 比 bool 索引更快?

标签 python arrays numpy

np.compress 在内部做了什么使其比 bool 索引更快?

在此示例中,compress 快了约 20%,但节省的时间因 a 的大小和 True 的数量而异 bool 数组 b 中的值,但在我的机器上 compress 总是更快。

import numpy as np

a = np.random.rand(1000000,4)
b = (a[:,0]>0.5)

%timeit a[b]
#>>> 10 loops, best of 3: 24.7 ms per loop
%timeit a.compress(b, axis=0)
#>>> 10 loops, best of 3: 20 ms per loop

documentation for boolean indexing

What is returned is a copy of the data, not a view as one gets with slices

相比之下,compress docs

Return selected slices of an array along given axis".

但是,使用 method provided here用于确定两个数组是否共享同一数据缓冲区表明这两种方法都没有与其父 a 共享数据,我认为这意味着这两种方法都没有返回实际的切片。

def get_data_base(arr):
    base = arr
    while isinstance(base.base, np.ndarray):
        base = base.base
    return base

def arrays_share_data(x, y):
    return get_data_base(x) is get_data_base(y) 

arrays_share_data(a, a.compress(b, axis=0))
#>>> False
arrays_share_data(a, a[b])
#>>> False

我只是好奇,因为我在工作中经常进行这些操作。我运行 python 3.5.2,numpy v 1.11.1,通过 Anaconda 安装。

最佳答案

numpy github 上通过几层函数调用跟踪 a.compress 我到了

/numpy/core/src/multiarray/item_selection.c
PyArray_Compress(PyArrayObject *self, PyObject *condition, int axis,
             PyArrayObject *out)
    # various checks
    res = PyArray_Nonzero(cond);
    ret = PyArray_TakeFrom(self, PyTuple_GET_ITEM(res, 0), axis,
                       out, NPY_RAISE);

对于您的示例数组,compress 与执行where 获取索引数组,然后take 相同:

In [135]: a.shape
Out[135]: (1000000, 4)
In [136]: b.shape
Out[136]: (1000000,)
In [137]: a.compress(b, axis=0).shape
Out[137]: (499780, 4)
In [138]: a.take(np.nonzero(b)[0], axis=0).shape
Out[138]: (499780, 4)
In [139]: timeit a.compress(b, axis=0).shape
100 loops, best of 3: 14.3 ms per loop
In [140]: timeit a.take(np.nonzero(b)[0], axis=0).shape
100 loops, best of 3: 14.3 ms per loop

事实上,如果我在 [] 索引中使用这个索引数组,我会得到可比较的时间:

In [141]: idx=np.where(b)[0]
In [142]: idx.shape
Out[142]: (499780,)
In [143]: timeit a[idx,:].shape
100 loops, best of 3: 14.6 ms per loop
In [144]: timeit np.take(a,idx, axis=0).shape
100 loops, best of 3: 9.9 ms per loop

np.take 代码涉及更多,因为它包括 clipwrap 模式。

[] 索引被翻译成一个 __getitem__ 调用,并通过各个层。我没有追踪到代码差异很大,但我认为可以肯定地说 compress(或者更确切地说是 take)只是采取了更直接的任务路径,因此获得适度的速度提升。 30-50% 的速度差异表明编译代码细节存在差异,而不是像 viewscopys 或解释与编译这样的主要差异。

关于python - 为什么 np.compress 比 bool 索引更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44487889/

相关文章:

python - Flask - 将表单输入传递给 url_for

Java 数组 : Attribute size?

python - 获取 3D 空间中某个点的 26 个最近邻点 - 矢量化

c# - 将python模块转换成DLL文件

java - 有人能告诉我为什么这个方法会进入无限循环吗?

unix - 在没有 sudo 的情况下安装 numpy

python - type(obj) 和 obj.__class__ 的区别

python - 向 numpy 数组添加噪声的最快方法

python - 有没有办法在 Python 中遍历列表的子部分

Java:如何将用户定义的属性的值放入数组中?