Python 检查numpy数组窗口中的元素是否有限的更快方法
我有一个非常长的NumPy数组,其中包含Python 检查numpy数组窗口中的元素是否有限的更快方法,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,我有一个非常长的NumPy数组,其中包含1\u 000\u 000元素,我想在数组中滑动50元素窗口,询问窗口中的所有元素是否都是有限的。如果50元素窗口中的所有元素都是有限的,则返回True(对于该窗口),否则,如果50元素窗口中的一个或多个元素不是有限的,则返回False(对于该窗口)。继续此评估,直到评估完所有窗口。一个很好的方法是: import numpy as np def rolling_window(a, window): a = np.asarray(a) s
1\u 000\u 000
元素,我想在数组中滑动50
元素窗口,询问窗口中的所有元素是否都是有限的。如果50
元素窗口中的所有元素都是有限的,则返回True
(对于该窗口),否则,如果50
元素窗口中的一个或多个元素不是有限的,则返回False
(对于该窗口)。继续此评估,直到评估完所有窗口。一个很好的方法是:
import numpy as np
def rolling_window(a, window):
a = np.asarray(a)
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
if __name__ == "__main__":
a = np.random.rand(100_000_000) # This is 10x shorter than my real data
w = 50
idx = np.random.randint(0, len(a), size=len(a)//10) # Simulate having np.nan in my array
a[idx] = np.nan
print(np.all(rolling_window(np.isfinite(a), w), axis=1))
但是,当我的数组长度为1\u 000\u 000
时,速度会很慢。是否有一种更快的方法可以完成这项任务,而不需要大量内存?方法#1:将跨步窗口直接插入分配的isfinite掩码中-
def strided_allfinite(a, w):
m = np.isfinite(a)
p = rolling_window(m, w)
nmW = ~m[:w]
if nmW.any():
m[:np.flatnonzero(nmW).max()] = False
p[~m[w-1:]] = False
return m[:-w+1]
给定样本数据的计时:
In [323]: N = 100_000_000
...: w = 50
...:
...: np.random.seed(0)
...: a = np.random.rand(N) # This is 10x shorter than my real data
...: idx = np.random.randint(0, len(a), size=len(a)//10) # Simulate...
...: a[idx] = np.nan
# Original soln
In [324]: %timeit np.all(rolling_window(np.isfinite(a), w), axis=1)
1.61 s ± 14.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [325]: %timeit strided_allfinite(a, w)
556 ms ± 87.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
方法#2
我们可以利用-
方法#3
与-
在我的测试中,as_stried
的速度是convolve
的两倍。我的咖啡用完了,无法理解stried\u allfinite
背后的逻辑。但是np.all(stripped\u allfinite(a,w)==np.all(滚动窗口(a,w,axis=1))
给了我False
@QuangHoang这是检查相等性的错误方法。尝试np.array\u equal(跨步有限(a,w),np.all(滚动窗口(np.isfinite(a,w),axis=1))
。可能还要咖啡吗?:)我不明白,这可能不是最好的方法,但肯定是正确的方法,因为两个数组都不包含nan。你能解释一下原因吗?@QuangHoang那么你应该做np.all(跨步有限(a,w)==np.all(滚动窗口(np.isfinite(a,w),axis=1))
。现在,我需要咖啡。无限元素的频率/稀疏度是多少?如果它们是稀疏的,那么最好先获取更大的块,仅当存在无限元素时才细分它们
np.convolve(np.isfinite(a), np.ones(w),'valid')==w
from scipy.ndimage.morphology import binary_erosion
m = np.isfinite(a)
out = binary_erosion(m, np.ones(w, dtype=bool))[w//2:len(a)-w+1+w//2]