这的灵感来自: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)
所以我的问题是双重的:
为什么这个np.isnan(arr - arr)技巧比"明显" ~np.isfinite(arr)版本更快?是否有输入它不起作用?
是否有更快的方法来查找所有非有限值?
这很难回答,因为np.isnan它np.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)