找到非有限值的最快方法

Jon*_*ler 6 python numpy

这的灵感来自:python:numpy中的组合掩蔽.

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

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

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

>>> np.isnan(arr - arr)
array([False, False,  True,  True,  True], dtype=bool)
Run Code Online (Sandbox Code Playgroud)

定时它我们看到它快两倍!

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
Run Code Online (Sandbox Code Playgroud)

所以我的问题是双重的:

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

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

MSe*_*ert 6

这很难回答,因为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#
 **/
Run Code Online (Sandbox Code Playgroud)

这些函数是根据编译时常量(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
Run Code Online (Sandbox Code Playgroud)

因此,可能只是在您的情况下,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)
Run Code Online (Sandbox Code Playgroud)

另请注意,该np.isnan解决方案在我的计算机上慢得多(Windows 10 64bit Python 3.5 NumPy 1.13.1 Anaconda build)