在python中,我有一个形状为n*2的数组(其中n是正整数(。从本质上讲,这是一个对数组。我希望删除此数组中的所有镜像对。例如,以下数组 A 的形状为 10*2。对 [0,55] 和 [55, 0] 将构成 A 中的一个这样的镜像对,我希望从这两个镜像中保留一个。
A = np.array([[ 0, 55], [ 5, 25], [12, 62], [27, 32], [25, 73],
[55, 0], [25, 5], [62, 12], [32, 27], [99, 95]])
对于上述示例,我希望结果数组如下所示:
B = np.array([[ 0, 55], [ 5, 25], [12, 62], [27, 32], [25, 73], [99,95])
因为有 6 个唯一对(排除 4 个镜像对后(。
我意识到我可以使用两个嵌套的 for 循环来实现这一点,但我希望使用最快的方法实现这一目标,因为对于手头的实际问题,我将处理巨大的数组。我会很感激能得到一些帮助。
一个神秘的单行:
In [301]: A
Out[301]:
array([[ 0, 55],
[ 5, 25],
[12, 62],
[27, 32],
[25, 73],
[55, 0],
[25, 5],
[62, 12],
[32, 27],
[99, 95]])
In [302]: np.unique(np.sort(A, axis=1).view(','.join([A.dtype.char]*2))).view(A.dtype).reshape(-1, 2)
Out[302]:
array([[ 0, 55],
[ 5, 25],
[12, 62],
[25, 73],
[27, 32],
[95, 99]])
将其分解为步骤...
首先,创建一个沿第二个轴排序的副本。 在排序数组中,我们要删除重复的行。
In [303]: a = np.sort(A, axis=1)
In [304]: a
Out[304]:
array([[ 0, 55],
[ 5, 25],
[12, 62],
[27, 32],
[25, 73],
[ 0, 55],
[ 5, 25],
[12, 62],
[27, 32],
[95, 99]])
numpy.unique()
可用于查找数组的唯一元素,但它仅适用于一维数据。 因此,我们将创建一个b
的一维视图,其中每一行都成为具有两个字段的单个结构。 定义我们想要的新数据类型的一种方法是字符串:
In [305]: dt = ','.join([A.dtype.char]*2)
In [306]: dt
Out[306]: 'l,l'
b
是一个结构化数组;它是a
的一维视图:
In [307]: b = a.view(dt)
In [308]: b
Out[308]:
array([[( 0, 55)],
[( 5, 25)],
[(12, 62)],
[(27, 32)],
[(25, 73)],
[( 0, 55)],
[( 5, 25)],
[(12, 62)],
[(27, 32)],
[(95, 99)]],
dtype=[('f0', '<i8'), ('f1', '<i8')])
现在我们用numpy.unique()
来寻找b
的独特元素:
In [309]: u = np.unique(b)
In [310]: u
Out[310]:
array([( 0, 55), ( 5, 25), (12, 62), (25, 73), (27, 32), (95, 99)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
接下来,使用原始数组A
的数据类型创建 u
的视图。 这将是一维的:
In [311]: v = u.view(A.dtype)
In [312]: v
Out[312]: array([ 0, 55, 5, 25, 12, 62, 25, 73, 27, 32, 95, 99])
最后,整形v
以恢复二维数组:
In [313]: w = v.reshape(-1, 2)
In [314]: w
Out[314]:
array([[ 0, 55],
[ 5, 25],
[12, 62],
[25, 73],
[27, 32],
[95, 99]])
如果您使用的是纯 python 列表,请尝试以下代码。
>>> list(set([tuple(i) for i in map(sorted, b)]))
[(27, 32), (5, 25), (12, 62), (95, 99), (25, 73), (0, 55)]
我假设对的顺序无关紧要(例如:[1,2] = [2,1](。如果是这种情况,您可以翻转所有对,以便第一个数字始终小于第二个数字。
[[1,2], [4,3], [1,7], [10,2]]
成为
[[1,2], [3,4], [1,7], [2,10]]
然后,您可以按第一个数字对所有对进行排序,然后按第二个数字排序:
[[1,2], [1,7], [2,10], [3,4]]
最后,您可以遍历列表并删除任何重复的对。如果你使用一种高效的排序算法,比如合并排序,整个过程将有O(n*log(n((工作,这比O(n^2(工作(你通过嵌套的for循环得到的(要好得多。
我会告诉你我的方式(因为它有一个我最喜欢的技巧将 1D 列表转换为 nD(,即使可能有更简单的方法:
A = [[ 0, 55], [ 5, 25], [12, 62], [27, 32], [25, 73],
[55, 0], [25, 5], [62, 12], [32, 27], [99, 95]]
B=[]
long = int(len(A)/2)
for i in range(long):
if A[i][0] == A[i+long][1] and A[i][1] == A[i+long][0]:
B.append(A[i][0])
B.append(A[i][1])
else:
B.append(A[i][0])
B.append(A[i][1])
B.append(A[i+long][0])
B.append(A[i+long][1])
#Now we created an 1D list and then we convert it to 2D!
B=[B[i:i+2] for i in range(0,len(B),2)]