2015-10-28 19 views
2

假設我有一些包含某些事件的數據,並且我想測量事件之間的時間間隔。但有時我有nan值,因爲沒有測量。我不想包括這些間隔,因爲我不知道那裏發生了什麼。掩蓋numpy/pandas中包含nan的事件間隔的優雅方式

例如,給定:

import numpy as np 
a = np.array([0, 1, 0, 0, 0, 1, 0, 0, np.nan, np.nan, 1, 0, 0, 0, 0, 1]) 

我想回去[4, 5]因爲第一組的人之間的間隔爲4個指數,第二組之間的間隔有NaN,並且因此被忽略,第三個和第四個之間的間隔是5個索引。作爲輸出也可以接受[4, nan, 5]

我可以做到以下幾點:

a_mod = a.copy() 
a_mod[np.isnan(a)] = -1e9 # some value I know is larger than my interval will ever be 
a_sum = np.cumsum(a_mod) 
a_sum_pts = a_sum[a == 1] 
mask = np.diff(a_sum_pts) > 0 
events = np.where(a == 1)[0] 
intervals = np.diff(events) 
good_intervals = intervals[mask] 

這確實給我我想要的答案。但它感覺像一個可怕的黑客。有一個更好的方法嗎?也許在熊貓的東西?

+0

要清楚:如果您的數據是[0,1,0,1,1,0,0,1],您需要[2,1,3]作爲輸出? – nneonneo

+0

是的,這是正確的 – MorganM

回答

2

儘量簡單

idx, = np.where(a==1) 
nanidx, = np.where(np.isnan(a)) 

intervals = np.diff(idx) 
good_intervals = np.delete(intervals, np.searchsorted(idx, nanidx)-1) 

這只是查找在1秒都以及其中nan s爲,然後刪除包含nan的時間間隔。

-1searchsorted佔帳戶的轉移np.diff;作爲一個小警告,如果在第一個1之前有nan秒(但這很容易解決),則此代碼無法正常工作。

0

您可以使用np.ufunc.reduceat,找出哪些領域包括男,並掩蓋起來:

>>> idx, = np.where(a == 1) 
>>> mask = np.logical_or.reduceat(np.isnan(a), idx)[:-1] 
>>> np.diff(idx)[~mask] 
array([4, 5]) 

這將線性執行,即O(n)

+0

我喜歡這個邏輯,但是我的速度比@nneonneo的答案低2倍。不過感謝您向我介紹'reduceat'!另一個隱藏在寶石中的寶石。 – MorganM