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

4

我有一个4列的数组:

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

我希望提取唯一的行(或第一次出现的行),并且对于行,没有其他行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]])

感谢您的帮助!

你使用的整数范围是什么,或者你需要它完全通用吗? - tom10
整数将会增加到大约100,000。 - user3357979
第二个和第四个元素是否总是相等的? - tom10
是的,第二个和第四个元素将始终相等。 - user3357979
3个回答

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

我得到了以下错误: Traceback(最近的调用最后): File“<interactive input>”,第1行,在<module>中 文件“C:\ Python26 \ lib \ site-packages \ numpy \ lib \ arraysetops.py”,第178行,独特的 perm = ar.argsort(kind ='mergesort') TypeError:请求的排序类型不可用 - user3357979
type(A)是什么?还有np.__version__呢? - askewchan
有趣。我想知道numpy 1.6是否无法对结构化数组进行排序? - askewchan
我给这个答案点了一个赞,但我认为一些解释也会很有帮助。例如,我没有完全跟进问题和示例,但是A[i,:] == A[j,[2,1,0,3]]部分怎么样? - tom10
@tom,“A[i,:] == A[j,[2,1,0,3]]”只是意味着行i与行j匹配,即使列02已经交换(或未交换),因此我在比较之前只需对每行进行排序。由于列1和3始终相同,因此我可以忽略它们的移动效果。 - askewchan
显示剩余2条评论

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列表以对A中每行进行操作。我还没有时间想出如何将其表示为Python而不是视觉流程图。也许它可以作为一组字典工作,但我不确定。

{A[0]:{A[1]:{A[2]:{A[3]:True}}}}

这样做不起作用,因为它会覆盖键的值。也许可以为每个键和子键创建一个字典列表,为键A[1]提供一组字典,为键A[2]提供一个字典列表。

当读取每个条目时,如果在特定列表中尚未找到A[3],则将其附加。如果找到了,则是重复项。我认为基础应该是类似于以下顺序的东西:

{A[0]:({A[1]:({A[2]:(A[3])})})}

我不知道这个概念是否可行,但需要适当的循环和追加,可能设置起来太复杂了。


是的,你理解了第二部分。这个方法可以工作,但唯一的问题是对于非常大的数组(约500万行),速度较慢。有什么加速的想法吗?感谢您的帮助! - user3357979
@user3357979 也许一个字典列表的字典可以允许一种树和分支的方法。但也许不行。我没有时间真正分析它或尝试构建代码。 - sabbahillel

0

对于唯一的行,您可以使用Python集合来删除重复项。由于np数组(或列表)是不可哈希的,因此在选择时可能需要将行转换为元组,然后再转换回数组:

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)

这个程序运行良好,但唯一的问题是对于非常大的数组(约5,000,000行)速度较慢。有什么加速的想法吗?感谢您的帮助! - user3357979

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