2012-03-10 23 views
1

我試圖擴展一個我寫的函數來查找「足夠接近」字典的前3個值也都低於閾值(這裏N = 70)。 :確定高頻區間

d = { 
1: {0: 222, 2:44, 18: 44, 20: 22, 21:72, 105:22, 107:9, 115: 66}, 
2: {0: 61.0, 993: 65.0, 1133: 84.0, 1069: 48.0, 105:22, 107:9, 115: 24, 214:22, 206:9,  225: 241,412: 83.0, 364: 68.0, 682: 64.0, 172: 58.0} 
}#nested dictionary 

def ff(d): 
    G = [] 
    for k,v in sorted(d.iteritems()): 
     G.append((k,v)) 
     #print G 
    for i in range(len(G)-2): 
     if (G[i+2][0] - G[i][0] < 20) & (G[i][1] <= 70) & (G[i+1][1] <=70) & (G[i+2][1]<=70): 
      return i, G[i], G[i+1], G[i+2] 

for idnum, ds in sorted(d.iteritems()): 
    print ff(ds) 

輸出:

[(0, 222), (2, 44), (18, 44), (20, 22), (21, 72), (105, 22), (107, 9), (115, 66)] 
(1, (2, 44), (18, 44), (20, 22)) 
[(0, 61.0), (105, 22), (107, 9), (115, 24), (172, 58.0), (206, 9), (214, 22), (225, 241),  (364, 68.0), (412, 83.0), (682, 64.0), (993, 65.0), (1069, 48.0), (1133, 84.0)] 
(1, (105, 22), (107, 9), (115, 24)) #first interval fitting criteria 

我想怎麼辦,實際上是找到長度爲20的所有窗口,並跟蹤它有多少價值有< = 70。任何關於如何開始的想法都會很棒。我似乎不能用「我」要弄清楚如何從狀態移動:

if (G[i+2][0] - G[i][0] < 20) & (G[i][1] <= 70) & (G[i+1][1] <=70) & (G[i+2][1]<=70): 

的東西基於長度20,而不是索引?

最終,而不是「前三個」我想保持所有較高頻率的軌道其最小值爲「按順序值< = 70至少3個,連續*和長度爲20間隔」。

期望輸出繼電器:

如果我們有

d[3] = {0: 61.0, 993: 65.0, 1133: 84.0, 1069: 48.0, 105:22, 107:9, 115: 24, 117:22, 200:100, 225: 241,412: 83.0, 420: 68.0, 423: 64.0, 430: 58.0} 

會導致輸出:

[(105, 22), (107, 9), (115, 24),(117,22)], [(420, 68.0),(423,63),(430,58)] 
# These can be of any length as long as the overall interval of the list is <=20. 
+1

可以跳過一個大於70的值嗎?所以,如果不是'(0,222)'你有'(9,222)',那麼'(2,44),(18,44),(20,22)'仍然是正確的嗎? – 2012-03-10 17:36:57

+0

好問題。不,我需要他們**連續**。 – 2012-03-10 19:00:32

+0

如果有重疊的候選窗口怎麼辦? (0,55),(1,55),(2,55),(3,55):前三位,後三位和四位一起似乎都滿足條件。在這種情況下應該發生什麼? – DSM 2012-03-10 19:09:30

回答

1

這裏的東西這可能會幫助你開始。它是基於循環的,甚至不使用壓縮,但希望將意義(更itertools.takewhile!):

def find_windows(d, min_elements=3,upper_length=20,max_value=70): 
    G = sorted(d.items()) 
    for start_index in range(len(G)): 
     for width in range(min_elements, len(G)-start_index+1): 
      window = G[start_index:start_index+width] 
      if not all(v <= max_value for k,v in window): 
       break 
      if not window[-1][0] - window[0][0] < upper_length: 
       break 
      yield window 

我用「破發」,因爲只要我們有任何值> MAX_VALUE或我們> = upper_length從start_index開始沒有更多可能的窗口。

如果您之前沒有看過yield,它會將該功能變爲生成器功能;它就像是一個return函數發回(yield)的值,然後可以繼續而不是停止。 (見的答案this question以獲取更多信息。)

>>> Ds = { 
...  1: {0: 222, 2:44, 18: 44, 20: 22, 21:72, 105:22, 107:9, 115: 66}, 
...  2: {0: 61.0, 993: 65.0, 1133: 84.0, 1069: 48.0, 105:22, 107:9, 115: 24, 214:22, 206:9, 225: 241,412: 83.0, 364: 68.0, 682: 64.0, 172: 58.0} 
...  } 
>>> 
>>> for idnum, d in sorted(Ds.items()): 
...  print idnum, list(find_windows(d)) 
... 
1 [[(2, 44), (18, 44), (20, 22)], [(105, 22), (107, 9), (115, 66)]] 
2 [[(105, 22), (107, 9), (115, 24)]] 
>>> mydict = dict([(0,55),(1,55),(2,55),(3,55)]) 
>>> 
>>> for window in find_windows(mydict): 
...  print window 
... 
[(0, 55), (1, 55), (2, 55)] 
[(0, 55), (1, 55), (2, 55), (3, 55)] 
[(1, 55), (2, 55), (3, 55)] 
>>> list(find_windows(mydict)) 
[[(0, 55), (1, 55), (2, 55)], [(0, 55), (1, 55), (2, 55), (3, 55)], [(1, 55), (2, 55), (3, 55)]] 

它仍然是不完全清楚,我要與重疊窗口做什麼,但目前發現所有這些,你可以在函數中或決定後處理你想如何處理。

將代碼修改爲而不是測試所有值是否爲< = max_value並對它們進行計數應該是微不足道的,所以我將保留這一點。

+0

謝謝你的「收益」信息,我還沒有使用過。當我嘗試構建這個功能時,我會研究它。我編輯了上面所需的輸出。基本上,我想要有20個長度的間隔。這些間隔可以具有所需的所有值,以捕獲在該間隔中記錄的y值<= 70的所有x值。我希望這是有道理的... – 2012-03-10 23:33:28

1

我把問題分成兩部分。這第一個生成器將ds這樣的詞典分解爲有序的(key, value)列表,使得每個列表的值不超過70個。同時,我放棄其中少於3個項目的塊。正如你看到的,我只得到儘可能大的窗口

from bisect import bisect_right 

def ff(d): 
    for chunk in split_iter(d): 
     last_end_i = 0 
     for i, (k, v) in enumerate(chunk): 
      end_i = bisect_right(chunk, (k + 20, 0)) 
      if end_i - i < 3: 
       continue 
      if last_end_i != end_i: 
       yield chunk[i:end_i] 
       last_end_i = end_i 
      if end_i == len(chunk): 
       break 

:現在

def split_iter(d, limit=70): 
    G = list(sorted(d.iteritems())) 
    start = 0 
    for i, (k, v) in enumerate(G): 
     if v > limit: 
      if i - start >= 3: 
       yield G[start:i] 
      start = i + 1 
    G_tail = G[start:] 
    if len(G_tail) >= 3: 
     yield G_tail 

我會連同bisect_right使用從bisect模塊快速找到開始與每個項目的最大可能的窗口。現在我們把它放在一起,像這樣:

for idnum, ds in sorted(d.iteritems()): 
    for r in ff(ds): 
     print idnum, repr(r) 

希望我說得對。輸出是這樣的:

1 [(2, 44), (18, 44), (20, 22)] 
1 [(105, 22), (107, 9), (115, 66)] 
2 [(105, 22), (107, 9), (115, 24)] 
+0

這是一個稍微不同的方式比我想的但很有用。感謝您使用Bisect,這對我來說是一項新功能,我很高興現在知道它。順便說一句,你的解釋非常好。 – 2012-03-10 23:53:39