灵感来自: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
所以我的问题有两个:
为什么np.isnan(arr - arr)
技巧比"显而易见"更快? ~np.isfinite(arr)
版本?是否有输入不起作用?
是否有更快的方法来查找所有非有限值?
答案 0 :(得分:4)
这很难回答,因为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#
**/
这些函数是根据编译时常量(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版本)