Python 删除NumPy数组中具有重复项的行
我有一个Python 删除NumPy数组中具有重复项的行,python,performance,numpy,vectorization,Python,Performance,Numpy,Vectorization,我有一个(N,3)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,
(N,3)
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(数组可能相当大)。有人知道我怎么做吗
numpy.array([v for v in vals if len(set(v)) == len(v)])
请注意,这仍然是幕后的循环。你无法避免。但它应该可以很好地工作,即使是数百万行
请注意,这仍然是幕后的循环。你无法避免。但即使对于数百万行,它也应该可以正常工作。这是一个选项:
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)
这是一个选项:
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)
与Marcelo相同,但我认为使用
numpy.unique()
而不是set()
可能会完全理解您的拍摄目的
numpy.array([v for v in vals if len(numpy.unique(v)) == len(v)])
与Marcelo相同,但我认为使用
numpy.unique()
而不是set()
可能会完全理解您的拍摄目的
numpy.array([v for v in vals if len(numpy.unique(v)) == len(v)])
这里有一种处理通用列数的方法,它仍然是一种矢量化方法-
def rows_uniq_elems(a):
a_sorted = np.sort(a,axis=-1)
return a[(a_sorted[...,1:] != a_sorted[...,:-1]).all(-1)]
步骤:
- 按每行排序
- 查找每行中连续元素之间的差异。因此,任何至少有一个零微分的行都表示重复的元素。我们将使用它来获得有效行的掩码。因此,最后一步是使用掩码从输入数组中简单地选择有效行
In [49]: a
Out[49]:
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 [50]: rows_uniq_elems(a)
Out[50]:
array([[1, 2, 3, 7],
[4, 5, 6, 7],
[0, 4, 5, 6],
[5, 4, 3, 2]])
这里有一种处理通用列数的方法,它仍然是一种矢量化方法-
def rows_uniq_elems(a):
a_sorted = np.sort(a,axis=-1)
return a[(a_sorted[...,1:] != a_sorted[...,:-1]).all(-1)]
步骤:
- 按每行排序
- 查找每行中连续元素之间的差异。因此,任何至少有一个零微分的行都表示重复的元素。我们将使用它来获得有效行的掩码。因此,最后一步是使用掩码从输入数组中简单地选择有效行
In [49]: a
Out[49]:
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 [50]: rows_uniq_elems(a)
Out[50]:
array([[1, 2, 3, 7],
[4, 5, 6, 7],
[0, 4, 5, 6],
[5, 4, 3, 2]])
六年过去了,但这个问题对我很有帮助,所以我对Divakar、Benjamin、Marcelo Cantos和Curtis Patrick给出的答案进行了速度比较
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)])
结果:
%timeit rows_uniq_elems1(vals)
10000 loops, best of 3: 67.9 µs per loop
%timeit rows_uniq_elems2(vals)
10000 loops, best of 3: 156 µs per loop
%timeit rows_uniq_elems3(vals)
1000 loops, best of 3: 59.5 µs per loop
%timeit rows_uniq_elems(vals)
10000 loops, best of 3: 268 µs per loop
似乎使用set
胜过numpy.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
没有列表理解的方法要快得多。然而,行的数量是硬编码的,并且很难扩展到三列以上,因此在我的例子中,至少对集合的列表理解是最好的答案
编辑了,因为六年过去了,我混淆了
bigvals
中的行和列,但这个问题帮助了我,所以我对Divakar、Benjamin、Marcelo Cantos和Curtis Patrick给出的答案进行了速度比较
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)])
结果:
%timeit rows_uniq_elems1(vals)
10000 loops, best of 3: 67.9 µs per loop
%timeit rows_uniq_elems2(vals)
10000 loops, best of 3: 156 µs per loop
%timeit rows_uniq_elems3(vals)
1000 loops, best of 3: 59.5 µs per loop
%timeit rows_uniq_elems(vals)
10000 loops, best of 3: 268 µs per loop
似乎使用set
胜过numpy.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
没有列表理解的方法要快得多。然而,行的数量是硬编码的,并且很难扩展到三列以上,因此在我的例子中,至少对集合的列表理解是最好的答案
编辑了,因为我混淆了
bigvals中的行和列
我提出了[VAL中的项对项如果计数器(项)。最常见的(1)[0][1]是1]
,但这更好,特别是因为你已经知道len(v)
。然而,你仍然在“循环”,因为你正在迭代数组。尽管我需要重复项的索引位置,但这对于一个大数组来说速度惊人,所以我喜欢@Benjamin的解决方案,我想出了[VAL if计数器中的项对项(项)。最常见的(1)[0][1]是1]
,但这更好,特别是因为你已经知道了len(v)。但是,你仍然在“循环”,因为你在数组上迭代。尽管我需要重复项的索引位置,但对于一个大数组来说,这实际上是惊人的快,所以我喜欢@Benjamin的solutionBy“无循环”你是什么意思?你必须检查数组中的每一项,所以不管你使用什么技巧来隐藏循环,它都是O(m*n)。我认为他的意思是在Numpy中循环,而不是在Python中循环。编译后的Numpy函数中的O(mn)比Pythonfor
循环中的O(mn)快得多。当选项是编译代码和解释代码时,常量很重要。因为,您希望将其推广到处理通用列数,所以您可能会发现这个问题值得一读。您所说的“无循环”是什么意思?你必须检查数组中的每一项,所以不管你使用什么技巧来隐藏循环,它都是O(m*n)。我认为他的意思是在Numpy中循环,而不是在Python中循环。编译后的Numpy函数中的O(mn)比Pythonfor
循环中的O(mn)快得多。当选项是编译代码和解释代码时,常量很重要。因为,您希望将其推广到处理通用列数,所以您可能会发现这个问题值得一读。好吧,set
也有同样的意图,但它是numpy.unique
更快,也许?它实际上似乎要慢得多-对于numpy.unique()来说是23秒,而对于set()来说是3秒。在我的机器上,有100万rowsWell,set
也达到了同样的目的,但它是numpy.unique
更快,也许?它实际上似乎要慢得多-对于numpy.unique()来说是23秒,对于set()来说是3秒在我的机器上,有一百万罗西,我正在努力解决这个问题,干得好。但是你不需要| not^吗?这比列表理解方法快得多,所以我可能会接受。想知道是否有任何方法可以推广到NxM吗?@Ned Batchelder:是的,尽管在这种情况下它不会改变任何东西。@jterrace你可以通过生成0-m的组合进行推广,在生成器表达式中使用它们进行比较,然后减少|得到a
。我正试图解决这个问题,干得好日分