检查numpy数组中所有行是否唯一
我有一个四列的数组:
A=array([[100,1,500,1],
[100,1,501,1],
[101,1,501,1],
[102,2,502,2],
[500,1,100,1],
[100,1,500,1],
[502,2,102,2],
[502,1,102,1]])
我想提取出那些独特的行(或者说是第一次出现的行),并且对于某一行 i
,在这个数组中没有其他行 j
满足 A[i,:]==A[j,[2,1,0,3]]
的条件(或者说是第一次出现的)。
所以对于数组 A
,我希望得到一个看起来像这样的数组:
B=array([[100,1,500,1],
[100,1,501,1],
[101,1,501,1],
[102,2,502,2],
[502,1,102,1]])
谢谢你的帮助!
3 个回答
对于唯一的行,你可以使用Python中的集合来去掉重复的内容。因为numpy数组(或者列表)是不能被哈希的,所以在选择行的时候,你可能需要先把行转换成元组,然后再转换回数组:
B = np.array(list(set([tuple(x) for x in A])))
至于你问题的第二部分,你需要自己实现一个选择循环:
B = []
for row in A:
lrow = list(row)
if lrow not in B and [lrow[2], lrow[1], lrow[0], lrow[3]] not in B:
B.append(lrow)
B = np.array(B)
我不太明白问题的第二部分是什么意思(从 A[i:] 开始的那部分)。不过,作为一个简单的循环,你也可以使用
B = []
for data in A:
if data not in B:
B.append(data)
tuple(B)
这个代码会遍历 A,检查它是否已经在 B 中,如果没有就把它加进去。虽然这样做不是最有效的方法,因为每次都需要遍历 B,但它简单明了。
你是在问,如果数据是 [0, 1, 2, 3],是否不存在像 [2, 0, 1, 3] 这样的行吗?
如果是这样的话,就在 if 语句中添加条件
and [data[2], data[0], data[1], data[3]] not in B
我觉得把这个设置成树形结构和分支处理可能会有效。也就是说,在 A[0] 创建分支,然后根据 A[1] 的值来分支。接着为 A[2] 创建分支,最后在 A[3] 处形成叶子节点。如果最后的叶子节点已经存在,就不再添加。树形结构建立好后,再回过头来把所有的分支和叶子节点收集到数组结构中,这样它们就会是唯一的。无论如何,这样做只需要读取初始列表一次,而不需要每次都完全读取 B 列表。我还没时间想怎么用 Python 表达这个,而不是用可视化的流程图。也许可以用字典的集合来实现,但我不太确定。
{A[0]:{A[1]:{A[2]:{A[3]:True}}}}
这样做是行不通的,因为它会覆盖键的值。也许可以为每个键和子键使用字典列表,这样就能得到一个以 A[1] 为键的字典集合,以及一个以 A[2] 为键的字典列表。
在读取每个条目时,如果在特定列表中找不到 A[3],就把它加进去。如果找到了,那就是重复的。我觉得基础的结构大概是这样的
{A[0]:({A[1]:({A[2]:(A[3])})})}
我不知道这个概念是否可行,但需要合适的 for 循环和添加操作,可能会太复杂而难以设置。
A[np.unique(np.sort(A,1).view("int, int, int, int"), return_index=True)[1]]
步骤如下:
In [385]: A
Out[385]:
array([[100, 1, 500, 1],
[100, 1, 501, 1],
[101, 1, 501, 1],
[102, 2, 502, 2],
[500, 1, 100, 1],
[100, 1, 500, 1],
[502, 2, 102, 2],
[502, 1, 102, 1]])
我们可以通过对每一行进行排序,来避免交换第0列和第2列的需要(就是把 A[i] = A[j, [2,1,0,3]
这样的操作)。我们不需要担心交换第1列和第3列,因为在 A
的所有行中,第1列和第3列的值是相等的:A[:, 1] == A[:, 3]
。
In [386]: As = np.sort(A,1)
In [387]: As
Out[387]:
array([[ 1, 1, 100, 500],
[ 1, 1, 100, 501],
[ 1, 1, 101, 501],
[ 2, 2, 102, 502],
[ 1, 1, 100, 500],
[ 1, 1, 100, 500],
[ 2, 2, 102, 502],
[ 1, 1, 102, 502]])
找到 As
(已经排序的数组)中的唯一行。可以把它看作一个结构化数组,每一行都是一个单独的元素(因为 np.unique
否则会先把数组压平)。
In [388]: As.view('int, int, int, int')
Out[388]:
array([[(1, 1, 100, 500)],
[(1, 1, 100, 501)],
[(1, 1, 101, 501)],
[(2, 2, 102, 502)],
[(1, 1, 100, 500)],
[(1, 1, 100, 500)],
[(2, 2, 102, 502)],
[(1, 1, 102, 502)]],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8')])
In [389]: u, i = np.unique(As.view('int, int, int, int'), return_index=True)
In [390]: i
Out[390]: array([0, 1, 2, 7, 3])
然后用这些唯一的行,从原始数组 A
中获取那些在 As
中是唯一的行:
In [391]: A[i]
Out[391]:
array([[100, 1, 500, 1],
[100, 1, 501, 1],
[101, 1, 501, 1],
[502, 1, 102, 1],
[102, 2, 502, 2]])