Numpy唯一的2D子数组

7
我有一个3D numpy数组,我只想要独特的2D子数组。
输入:
[[[ 1  2]
  [ 3  4]]

 [[ 5  6]
  [ 7  8]]

 [[ 9 10]
  [11 12]]

 [[ 5  6]
  [ 7  8]]]

输出:

[[[ 1  2]
  [ 3  4]]

 [[ 5  6]
  [ 7  8]]

 [[ 9 10]
  [11 12]]]

我试着将子数组转换为字符串(使用tostring()方法),然后使用np.unique,但在转换为numpy数组后,它删除了\x00的最后一个字节,因此我无法使用np.fromstring()将其转换回来。
例如:
import numpy as np
a = np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]],[[5,6],[7,8]]])
b = [x.tostring() for x in a]
print(b)
c = np.array(b)
print(c)
print(np.array([np.fromstring(x) for x in c]))

输出:

[b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00', b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00', b'\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c\x00\x00\x00', b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00']
[b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04'
 b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08'
 b'\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c'
 b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08']

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-86-6772b096689f> in <module>()
      5 c = np.array(b)
      6 print(c)
----> 7 print(np.array([np.fromstring(x) for x in c]))

<ipython-input-86-6772b096689f> in <listcomp>(.0)
      5 c = np.array(b)
      6 print(c)
----> 7 print(np.array([np.fromstring(x) for x in c]))

ValueError: string size must be a multiple of element size

我也尝试过使用view,但我真的不知道如何使用它。你能帮帮我吗?

1
这是即将发布的1.13版本中的一个新功能,称为 np.unique(a, axis=0)。由于1.13尚未发布,您可以简单地复制新实现并将其用于您的代码中。 - Eric
3个回答

4

使用@Jaime的帖子,来解决我们找到唯一的2D子数组的情况,我想出了这个解决方案,基本上在view步骤中添加了重新整形 -

def unique2D_subarray(a):
    dtype1 = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:])))
    b = np.ascontiguousarray(a.reshape(a.shape[0],-1)).view(dtype1)
    return a[np.unique(b, return_index=1)[1]]

样例运行 -

In [62]: a
Out[62]: 
array([[[ 1,  2],
        [ 3,  4]],

       [[ 5,  6],
        [ 7,  8]],

       [[ 9, 10],
        [11, 12]],

       [[ 5,  6],
        [ 7,  8]]])

In [63]: unique2D_subarray(a)
Out[63]: 
array([[[ 1,  2],
        [ 3,  4]],

       [[ 5,  6],
        [ 7,  8]],

       [[ 9, 10],
        [11, 12]]])

谢谢你的回答! 所以,如果我理解正确,dtype指定了一个字节序列(不是真正的任何类型),大小为a.dtype.itemsize *子数组的大小? 并且需要连续的数组,因为dtype被指定为一个字节序列? 非常抱歉重复问题,但我无法从@Jaime的帖子中理解。 - Petr
@Peťan,你对第一部分是正确的。至于第二部分需要“连续”的需求,我也不太清楚。或许在那篇文章下发表评论会更好吧。如果我要猜的话,我会说你的第二部分似乎是有道理的,但是这两个部分确实是相关的。 - Divakar

2

numpy_indexed 包(免责声明:我是它的作者)旨在以高效和向量化的方式执行以下操作:

import numpy_indexed as npi
npi.unique(a)

1
一种解决方案是使用集合来跟踪您已经看到的子数组:
seen = set([])
new_a = []

for j in a:
    f = tuple(list(j.flatten()))
    if f not in seen:
        new_a.append(j)
        seen.add(f)

print np.array(new_a)

或者仅使用numpy:

print np.unique(a).reshape((len(unique) / 4, 2, 2))

>>> [[[ 1  2]
      [ 3  4]]

     [[ 5  6]
      [ 7  8]]

     [[ 9 10]
      [11 12]]]

2
所以这个来自上面链接的答案 - Eric
你用那个答案输了子数组的顺序。 - kezzos
如果只是将数组复制到一个集合中,然后再复制回数组,那么顺序就会丢失,这是正确的,但是在上面的代码中所做的方式,顺序不会丢失。 - Haroldo_OK

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