检查numpy数组中所有行是否唯一

4 投票
3 回答
1866 浏览
提问于 2025-04-17 21:51

我有一个四列的数组:

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 个回答

0

对于唯一的行,你可以使用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)
0

我不太明白问题的第二部分是什么意思(从 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 循环和添加操作,可能会太复杂而难以设置。

3
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]])

撰写回答