2014-07-17 40 views
0

只有當這些元素位於掩碼數組內時,我才需要在numpy數組「標籤」中找到最頻繁的元素。這裏是蠻力的方法:在掩碼數組中找到最頻繁的元素

def getlabel(mask, label): 
    # get majority label 
    assert label.shape == mask.shape 

    tmp = [] 
    for i in range(mask.shape[0]): 
     for j in range(mask.shape[1]): 
      if mask[i][j] == True: 
       tmp.append(label[i][j]) 
    return Counter(tmp).most_common(1)[0][0] 

但我不認爲這是最優雅和最快的方法呢。我應該使用哪些其他數據結構? (hasing,字典等...)?

+0

你的數組中有什麼? –

回答

1

假設你mask是一個布爾數組:

import numpy as np 

cnt = np.bincount(label[mask].flat) 

這給你值0,1,2,... MAX(標籤)的出現次數的矢量

你可以找到最常見然後通過

most_frequent = np.argmax(cnt) 

,自然,在你輸入數據,這些元素的數量是

cnt[most_frequent] 

通常,np.bincount是快。讓我們試着用的999(即1000個箱)最大數量的標籤和一個10 000 000元件陣列由8個000 000值掩蔽:

data = np.random.randint(0, 1000, (1000, 10000)) 
mask = np.random.random((1000, 10000)) < 0.8 

# time this section 
cnt = np.bincount(data[mask].flat) 

用我機這需要80毫秒。 argmax可能需要2 ns/bin,所以即使您的標籤整數有點分散,也沒關係。

這種方法可能是最快的方法,如果下列條件成立:

  • 標籤是範圍0..N,其中N是不小於輸入陣列的尺寸更內的整數
  • 輸入數據是NumPy數組

此解決方案可能適用於其他一些情況,但它更多的是如何以及是否有更好的解決方案可用的問題。 (請參閱metaperture的答案。)例如,將Python列表簡單轉換爲ndarray代價相當​​高,如果輸入是Python列表,並且數據量不大,則bincount獲得的速度優勢將會丟失。

整數空間中標籤的稀疏不是問題本身。創建和歸零輸出矢量的速度相對較快,並且使用np.nonzero來壓縮容易且快速。但是,如果最大標籤值與輸入數組的大小相比較大,則速度優勢可能會丟失。

1

np.bincount不是的一般方法。對於有限的低熵離散分佈,np.bincount將更快。然而,將失敗:

  • 如果分佈是無界的,所使用的存儲器是無界的(可以是任意小的輸入數組任意大)
  • 如果分佈是連續的,bincount的argmax是不模式(技術上它是KDE的MAP,其中KDE是使用類似直方圖的方法生成的)
  • 如果分佈具有高熵/散佈,則基於bin的表示np.bincount沒有意義(不會失敗,但會變得更糟)

Fo R A通用的解決方案,你應該做的一個:

cnt = Counter((l for m, l in zip(mask.flat, label.flat) if m)) # or... 
cnt = Counter(label[mask].flat) 

或者:

scipy.stats.mode(label[mask].flat) 

在我的測試,前者〜快20倍。如果您知道分佈具有相對較低的邊界和熵,則計數將更快。

如果上面是不是足夠快,比bincount更好的一般的方法是取樣資料

collections.Counter(np.random.choice(data[mask], 1000)).most_common(1) 
scipy.stats.mode(np.random.choice(data[mask], 1000)) 

以上兩者是一個數量級比未採樣版本速度更快,迅速收斂到模式即使是最具病態的分佈。

+0

這些都是不錯的Python解決方案,沒有太多的NumPy。但是,表現並不好,第一個需要6.95 s(= 85x),第二個需要3.59 s(= 45x)。當然,有時候你的瘋狂標籤會帶有負值或數十億的值,然後你必須做點什麼。 (我會創建一個轉換數組,但有幾個選項。) – DrV

+0

對於您測試中的狹義用例,我同意'bincount'更有效。但是,由於上述原因,這不是一個很好的通用解決方案。 – metaperture

相關問題