2013-11-09 54 views
4

下面是一個算法我想實現使用numpy的:剪切波峯和波谷

對於給定的一維數組,計算最大和最小通過滑動窗口。 創建一個新的數組,第一個數值等於給定數組中的第一個數值。 對於每個後續值,從滑動窗口中剪切插入新數組中的最小值和最大值之間的上一個值。

舉個例子,讓我們的陣列a=[3, 4, 5, 4, 3, 2, 3, 3]和大小3的滑動窗口,我們找到了最大分鐘:

min = [3, 4, 3, 2, 2, 2] 
max = [5, 5, 5, 4, 3, 3] 

現在我們輸出數組將開始從a的第一個元素,所以它的3。對於下一個值,我在4和5之間剪輯3(最後插入的值)(在索引1處找到最小值和最大值)。結果是4.對於下一個值,我在3和5之間剪輯4。它仍然是4.依此類推。所以我們終於有:

output = [3, 4, 4, 4, 3, 3] 

我找不到一種方法來避免在我的代碼中使用python for循環。這是我目前所擁有的:

def second_window(array, samples): 
    sample_idx = samples - 1 
    output = np.zeros_like(array[0:-sample_idx]) 
    start, stop = 0, len(array) 
    last_value = array[0] 
    # Sliding window is a deque of length 'samples'. 
    sliding_window = deque(array[start : start+sample_idx], samples) 
    for i in xrange(stop - start - sample_idx): 
     # Get the next value in sliding window. After the first loop, 
     # the left value gets discarded automatically. 
     sliding_window.append(array[start + i + sample_idx]) 
     min_value, max_value = min(sliding_window), max(sliding_window) 
     # Clip the last value between sliding window min and max 
     last_value = min(max(last_value, min_value), max_value) 
     output[start + i] = last_value 
    return output 

只有numpy才能達到這個結果嗎?

回答

2

我不認爲你可以。你有時候可以用無緩衝的ufunc來做這種迭代計算,但事實並非如此。但是,讓我ellaborate ...

OK,先開窗的最小值/最大值計算可以更快地完成:

>>> a = np.array([3, 4, 5, 4, 3, 2, 3, 3]) 
>>> len_a = len(a) 
>>> win = 3 
>>> win_a = as_strided(a, shape=(len_a-win+1, win), strides=a.strides*2) 
>>> win_a 
array([[3, 4, 5], 
     [4, 5, 4], 
     [5, 4, 3], 
     [4, 3, 2], 
     [3, 2, 3], 
     [2, 3, 3]]) 
>>> min_ = np.min(win_a, axis=-1) 
>>> max_ = np.max(win_a, axis=-1) 

現在,讓我們創建和填寫您的輸出數組:

>>> out = np.empty((len_a-win+1,), dtype=a.dtype) 
>>> out[0] = a[0] 

如果np.clip其中ufunc,我們可能會嘗試做:

>>> np.clip(out[:-1], min_[1:], max_[1:], out=out[1:]) 
array([4, 3, 3, 3, 3]) 
>>> out 
array([3, 4, 3, 3, 3, 3]) 

但這母鹿沒有工作,因爲np.clip不是一個ufunc,並且似乎有一些緩衝涉及。

如果你申請np.minimumnp.maximum分開,那麼它並不總是工作:

>>> np.minimum(out[:-1], max_[1:], out=out[1:]) 
array([3, 3, 3, 3, 3]) 
>>> np.maximum(out[1:], min_[1:], out=out[1:]) 
array([4, 3, 3, 3, 3]) 
>>> out 
array([3, 4, 3, 3, 3, 3]) 

雖然你的具體情況扭轉了其他不工作:

>>> np.maximum(out[:-1], min_[1:], out=out[1:]) 
array([4, 4, 4, 4, 4]) 
>>> np.minimum(out[1:], max_[1:], out=out[1:]) 
array([4, 4, 4, 3, 3]) 
>>> out 
array([3, 4, 4, 4, 3, 3]) 
+0

我讀到有關as_strided之前,但當我遇到其他問題時,我把它放在一邊,忘了它。很高興你能向我展示一個可行的例子。 我仍然想知道np.roll是否會有一些潛力。 – Dan737