在numpy数组中查找唯一点

9

如何更快地在numpy数组中查找唯一的x、y点(去重)?例如:

points = numpy.random.randint(0, 5, (10,2))

我想将点转换为复数,然后检查唯一性,但这似乎过于复杂:

b = numpy.unique(points[:,0] + 1j * points[:,1])
points = numpy.column_stack((b.real, b.imag))

1
如果您不需要保留顺序,请使用元组(tuples)来表示点并将列表转换为集合(set)。 - wim
我需要的结果是一个numpy数组,所以这似乎需要进行很多转换。 - Benjamin
有没有真正的原因,解决方案 numpy.vstack([numpy.array(u) for u in set([tuple(p) for p in points])]) 不够快? - wim
当处理更长的点列表时,难道没有比列表推导更快的方法吗? - Benjamin
Wim的方法更快,特别是对于较大的数组。可能是因为它不会费心对结果进行排序。我在我的帖子中添加了一些timeit基准测试。也许Wim会将他的解决方案发布为答案? - unutbu
2个回答

8

我有一个类似的问题,这个方法非常有效,但是输出结果是未排序的,尽管输入数据已经排序。为什么会发生这种情况? - Warrick
1
由于set是一个无序集合,因此排序被破坏了。 - wim
没有什么可以阻止你对输出进行排序 :) 这里集合只是用作中间步骤来去重。 - wim

7
我认为您提出了一个非常好的想法。考虑用于表示“points”数据的基础内存块。我们告诉numpy将该块视为形状为(10,2)、dtype为int32(32位整数)的数组,但是告诉numpy将相同的内存块视为形状为(10,)、dtype为c8(64位复数)的数组几乎没有成本。
因此,唯一真正的成本是调用np.unique,然后再调用view和reshape,这些几乎没有成本。
import numpy as np
np.random.seed(1)
points = np.random.randint(0, 5, (10,2))
print(points)
print(len(points))

产量
[[3 4]
 [0 1]
 [3 0]
 [0 1]
 [4 4]
 [1 2]
 [4 2]
 [4 3]
 [4 2]
 [4 2]]
10

虽然(while)
cpoints = points.view('c8')
cpoints = np.unique(cpoints)
points = cpoints.view('i4').reshape((-1,2))
print(points)
print(len(points))

产量
[[0 1]
 [1 2]
 [3 0]
 [3 4]
 [4 2]
 [4 3]
 [4 4]]
7

如果您不需要结果排序,wim的方法更快(您可能要考虑接受他的答案...)
import numpy as np
np.random.seed(1)
N=10000
points = np.random.randint(0, 5, (N,2))

def using_unique():
    cpoints = points.view('c8')
    cpoints = np.unique(cpoints)
    return cpoints.view('i4').reshape((-1,2))

def using_set():
    return np.vstack([np.array(u) for u in set([tuple(p) for p in points])])

产生这些基准测试数据:
% python -mtimeit -s'import test' 'test.using_set()'
100 loops, best of 3: 18.3 msec per loop
% python -mtimeit -s'import test' 'test.using_unique()'
10 loops, best of 3: 40.6 msec per loop

2
np.unique对结果进行排序。您是否正在寻找一种方法来保持剩余元素的顺序? - unutbu
不,我的意思是我得到了错误的结果:cpoints.shape仍然为10,2,最终的点与原始数据不匹配。 - Benjamin
我已经编辑了这篇帖子并展示了它至少对于一个种子有效。你能否举出一个例子来证明它无效(提供一个种子以便问题可以重现)? - unutbu
不是我看到的...Python 2.7.1,numpy 2.0.0。我在Mac上使用Python 2.6.7和numpy 1.5.1以及Python 2.7.1和numpy 1.5.1时得到了相同的结果,即[[0,0],[1,0],[2,0],[3,0],[4,0]]...嗯。 - Benjamin
1
虽然不是每个人都会使用C语言,但recarrays可能比仅仅使用更大的dtype(并且更通用)更好。 - seberg
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接