找到非有限值的最快方法

时间:2017-08-18 12:37:44

标签: python numpy

灵感来自:python: Combined masking in numpy

任务是创建一个非限定的所有值的布尔数组。例如:

>>> arr = np.array([0, 2, np.inf, -np.inf, np.nan])
>>> ~np.isfinite(arr)
array([False, False,  True,  True,  True], dtype=bool)

对我来说,这似乎是找到非有限值的最快方法,但似乎有更快的方法。具体来说,np.isnan(arr - arr)也应该这样做:

>>> np.isnan(arr - arr)
array([False, False,  True,  True,  True], dtype=bool)

我们发现它的速度是它的两倍!

arr = np.random.rand(100000)

%timeit ~np.isfinite(arr)
10000 loops, best of 3: 198 µs per loop

%timeit np.isnan(arr - arr)
10000 loops, best of 3: 85.8 µs per loop

所以我的问题有两个:

  1. 为什么np.isnan(arr - arr)技巧比"显而易见"更快? ~np.isfinite(arr)版本?是否有输入不起作用?

  2. 是否有更快的方法来查找所有非有限值?

1 个答案:

答案 0 :(得分:4)

这很难回答,因为np.isnannp.isfinite可以使用不同的C函数,具体取决于构建。根据这些C函数的性能(很可能取决于编译器,系统以及NumPy本身的构建方式),时序会有所不同。

两者的ufunc都引用了内置的npy_ func(source (1.11.3)):

/**begin repeat1
 * #kind = isnan, isinf, isfinite, signbit, copysign, nextafter, spacing#
 * #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit, npy_copysign, nextafter, spacing#
 **/

这些函数是根据编译时常量(source (1.11.3))的存在来定义的:

/* use builtins to avoid function calls in tight loops
 * only available if npy_config.h is available (= numpys own build) */
#if HAVE___BUILTIN_ISNAN
    #define npy_isnan(x) __builtin_isnan(x)
#else
    #ifndef NPY_HAVE_DECL_ISNAN
        #define npy_isnan(x) ((x) != (x))
    #else
        #if defined(_MSC_VER) && (_MSC_VER < 1900)
            #define npy_isnan(x) _isnan((x))
        #else
            #define npy_isnan(x) isnan(x)
        #endif
    #endif
#endif

/* only available if npy_config.h is available (= numpys own build) */
#if HAVE___BUILTIN_ISFINITE
    #define npy_isfinite(x) __builtin_isfinite(x)
#else
    #ifndef NPY_HAVE_DECL_ISFINITE
        #ifdef _MSC_VER
            #define npy_isfinite(x) _finite((x))
        #else
            #define npy_isfinite(x) !npy_isnan((x) + (-x))
        #endif
    #else
        #define npy_isfinite(x) isfinite((x))
    #endif
#endif

所以可能只是在你的情况下np.isfinite必须比np.isnan做更多的工作。但同样可能的是,在另一台计算机上或另一台构建np.isfinite更快或两者同样快。

所以,最快的方法可能并不是一个很难的规则。是。这取决于太多因素。就个人而言,我会选择np.isfinite,因为可以更快(即使在你的情况下也不会太慢),这使得意图更加清晰。

为了防止您真正优化性能,您可以随时进行取消。这可能会通过避免一个临时数组来减少时间和内存:

import numpy as np
arr = np.random.rand(1000000)

def isnotfinite(arr):
    res = np.isfinite(arr)
    np.bitwise_not(res, out=res)  # in-place
    return res

np.testing.assert_array_equal(~np.isfinite(arr), isnotfinite(arr))
np.testing.assert_array_equal(~np.isfinite(arr), np.isnan(arr - arr))

%timeit ~np.isfinite(arr)
# 3.73 ms ± 4.16 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit isnotfinite(arr)
# 2.41 ms ± 29.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit np.isnan(arr - arr)
# 12.5 ms ± 772 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

另请注意,我的计算机上np.isnan解决方案 更慢(Windows 10 64位Python 3.5 NumPy 1.13.1 Anaconda版本)