2011-09-15 145 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