2011-09-15 180 views
11

重複卸下行我有一個(N,3)陣列numpy的值:在一個NumPy的陣列

>>> vals = numpy.array([[1,2,3],[4,5,6],[7,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]]) 
>>> vals 
array([[1, 2, 3], 
     [4, 5, 6], 
     [7, 8, 7], 
     [0, 4, 5], 
     [2, 2, 1], 
     [0, 0, 0], 
     [5, 4, 3]]) 

我想從具有一個重複的值的數組中刪除行。例如,對於上述陣列的結果應該是:

>>> duplicates_removed 
array([[1, 2, 3], 
     [4, 5, 6], 
     [0, 4, 5], 
     [5, 4, 3]]) 

我不知道如何與numpy的有效做到這一點沒有循環(數組可能會相當大)。任何人都知道我可以做到這一點?

+0

通過「無循環」你是什麼意思?你必須檢查數組中的每一項,所以無論你用什麼樣的技巧來隱藏循環都是O(m * n)。 – agf

+1

我認爲他意味着在Numpy中循環,而不是在Python中循環。編譯Numpy函數中的O(m * n)比Python for for循環中的O(m * n)快得多。當選項是編譯代碼和解釋代碼時,常量很重要。 –

+0

['From your comments'](https://stackoverflow.com/questions/7438438/removing-duplicates-in-each-row-of-a-numpy-array/45136720#comment8994361_7438505),因爲您正在尋找推廣這個來處理通用編號。的列,你可能會發現['this solution'](https://stackoverflow.com/a/45136720/)這個問題值得一讀。 – Divakar

回答

9

這是一個選項:

import numpy 
vals = numpy.array([[1,2,3],[4,5,6],[7,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]]) 
a = (vals[:,0] == vals[:,1]) | (vals[:,1] == vals[:,2]) | (vals[:,0] == vals[:,2]) 
vals = numpy.delete(vals, numpy.where(a), axis=0) 
+0

我正在努力解決這個問題,做得很好。但是你不需要|不是^? –

+1

這比列表理解方法快得多,所以我可能會接受。想知道是否有任何方法可以推廣到NxM? – jterrace

+0

^作品,但好奇爲什麼不使用| ? – jterrace

2
numpy.array([v for v in vals if len(set(v)) == len(v)]) 

請注意,這仍然在幕後循環。你無法避免這種情況。但即使對於數百萬行,它也能正常工作。

+0

如果Counter(item).most_common(1)[0] [1]是1],我想出了'[item中val的項目]'但是更好,特別是因爲您已經知道'len(v)'。然而,你仍然在「循環」,因爲你正在遍歷數組。 – agf

+0

儘管我需要重複索引位置,但對於大型數組來說,這實際上非常快,所以我喜歡@ Benjamin的解決方案 – jterrace

1

等同於馬塞洛,但我認爲使用numpy.unique()代替set()對面正是你所拍攝的內容可以得到。

numpy.array([v for v in vals if len(numpy.unique(v)) == len(v)]) 
+1

我認爲這是numpy.unique – jterrace

+0

那麼'set'也可以更快,也許會更快?'set'也有同樣的意圖,但'numpy.unique'更快? –

+0

實際上它似乎要慢很多 - 我的機器上有100萬行,numpy.unique()需要23秒,而set()需要3秒 – jterrace

2

這裏的處理列的通用號碼,仍然是一個矢量方法的方法 -

def rows_uniq_elems(a): 
    idx = a.argsort(1) 
    a_sorted = a[np.arange(idx.shape[0])[:,None], idx] 
    return a[(a_sorted[:,1:] != a_sorted[:,:-1]).all(-1)] 

步驟:

  • 相處的每一行argsort指數。

  • 使用advanced-indexing來排序每一行,給我們一個行排序的數組。

  • 查找每行中連續元素之間的差異。因此,具有至少一個零差異的任何行表示重複的元素。我們將使用它來獲得有效行的掩碼。所以,最後一步是使用掩碼簡單地從輸入數組中選擇有效的行。

採樣運行 -

In [90]: a 
Out[90]: 
array([[1, 2, 3, 7], 
     [4, 5, 6, 7], 
     [7, 8, 7, 8], 
     [0, 4, 5, 6], 
     [2, 2, 1, 1], 
     [0, 0, 0, 3], 
     [5, 4, 3, 2]]) 

In [91]: rows_uniq_elems(a) 
Out[91]: 
array([[1, 2, 3, 7], 
     [4, 5, 6, 7], 
     [0, 4, 5, 6], 
     [5, 4, 3, 2]]) 
2

其六年,但這個問題幫了我,所以我跑了速度由Divakar,本傑明,馬塞洛託斯和Curtis帕特里克給出的答案進行比較。

import numpy as np 
vals = np.array([[1,2,3],[4,5,6],[7,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]]) 

def rows_uniq_elems1(a): 
    idx = a.argsort(1) 
    a_sorted = a[np.arange(idx.shape[0])[:,None], idx] 
    return a[(a_sorted[:,1:] != a_sorted[:,:-1]).all(-1)] 

def rows_uniq_elems2(a): 
    a = (a[:,0] == a[:,1]) | (a[:,1] == a[:,2]) | (a[:,0] == a[:,2]) 
    return np.delete(a, np.where(a), axis=0) 

def rows_uniq_elems3(a): 
    return np.array([v for v in a if len(set(v)) == len(v)]) 

def rows_uniq_elems4(a): 
    return np.array([v for v in a if len(np.unique(v)) == len(v)]) 

結果:

​​3210

看來,使用setnumpy.unique。在我來說,我需要做這在更大的陣列:

bigvals = np.random.randint(0,10,3000).reshape([3,1000]) 

%timeit rows_uniq_elems1(bigvals) 
10000 loops, best of 3: 276 µs per loop 

%timeit rows_uniq_elems2(bigvals) 
10000 loops, best of 3: 192 µs per loop 

%timeit rows_uniq_elems3(bigvals) 
10000 loops, best of 3: 6.5 ms per loop 

%timeit rows_uniq_elems4(bigvals) 
10000 loops, best of 3: 35.7 ms per loop 

沒有列表解析的方法是要快得多。但是,行數是硬編碼的,很難擴展到三列以上,所以在我的情況下,至少對該列表的理解是最好的答案。

EDITED,因爲我感到困惑的行和列bigvals