【问题标题】:how to hash numpy arrays to check for duplicates如何散列numpy数组以检查重复项
【发布时间】:2017-02-02 13:53:07
【问题描述】:

我已经搜索了一些教程等来帮助解决这个问题,但似乎找不到任何东西。

我有两个 n 维 numpy 数组列表(某些图像的 3D 数组形式),我想检查每个列表中的重叠图像。让我们说列表 a 是训练集,列表 b 是验证集。 一种解决方案是使用嵌套循环并使用np.array(a[i], b[j]) 检查每对数组是否相等,但这很慢(每个列表中有大约 200,000 个 numpy 数组)并且坦率地说非常恶心。

我在想一种更优雅的实现方式是对每个列表中的每个 numpy 数组进行哈希处理,然后使用这些哈希表比较每个条目。

首先,这个解决方案是否正确,其次,我将如何实现这一目标?
下面是一些数据的示例。

train_dataset[:3]
array([[[-0.5       , -0.49607843, -0.5       , ..., -0.5       ,
         -0.49215686, -0.5       ],
        [-0.49607843, -0.47647059, -0.5       , ..., -0.5       ,
         -0.47254902, -0.49607843],
        [-0.49607843, -0.49607843, -0.5       , ..., -0.5       ,
         -0.49607843, -0.49607843],
        ..., 
        [-0.49607843, -0.49215686, -0.5       , ..., -0.5       ,
         -0.49215686, -0.49607843],
        [-0.49607843, -0.47647059, -0.5       , ..., -0.5       ,
         -0.47254902, -0.49607843],
        [-0.5       , -0.49607843, -0.5       , ..., -0.5       ,
         -0.49607843, -0.5       ]],

       [[-0.5       , -0.5       , -0.5       , ...,  0.48823529,
          0.5       ,  0.1509804 ],
        [-0.5       , -0.5       , -0.5       , ...,  0.48431373,
          0.14705883, -0.32745099],
        [-0.5       , -0.5       , -0.5       , ..., -0.32745099,
         -0.5       , -0.49607843],
        ..., 
        [-0.5       , -0.44901961,  0.1509804 , ..., -0.5       ,
         -0.5       , -0.5       ],
        [-0.49607843, -0.49607843, -0.49215686, ..., -0.5       ,
         -0.5       , -0.5       ],
        [-0.5       , -0.49607843, -0.48823529, ..., -0.5       ,
         -0.5       , -0.5       ]],

       [[-0.5       , -0.5       , -0.5       , ..., -0.5       ,
         -0.5       , -0.5       ],
        [-0.5       , -0.5       , -0.5       , ..., -0.5       ,
         -0.5       , -0.5       ],
        [-0.5       , -0.5       , -0.49607843, ..., -0.5       ,
         -0.5       , -0.5       ],
        ..., 
        [-0.5       , -0.5       , -0.5       , ..., -0.48823529,
         -0.5       , -0.5       ],
        [-0.5       , -0.5       , -0.5       , ..., -0.5       ,
         -0.5       , -0.5       ],
        [-0.5       , -0.5       , -0.5       , ..., -0.5       ,
         -0.5       , -0.5       ]]], dtype=float32)

提前感谢您的帮助。

【问题讨论】:

  • 向我们展示一下您对成对比较所做的工作。在这种情况下,我不知道您所说的disgusting 是什么意思。
  • 查看最近的stackoverflow.com/questions/39674863/…。另请查看有关唯一行或已排序行的问题。
  • 基本上我在尝试这个:duplicates = [] for i in train_dataset: for j in valid_dataset: duplicates.append(np.equal(i,j) 抱歉格式化,这些 cmets 很奇怪。
  • np.equal 对浮点数的表现如何?通常我们推荐np.allclose 在相互测试浮点数组时。 (或np.isclose
  • 显然不是很好,因为我让它运行了大约 30 分钟,它还没有完成哈哈。我现在试试这两个选项。

标签: python arrays numpy hash


【解决方案1】:

numpy_indexed 包(声明:我是它的作者)为此提供了高效的单行代码:

import numpy_indexed as npi
duplicate_images = npi.intersection(train_dataset, test_dataset) 

还有很多相关功能,您可能会发现在这种情况下很有用。

【讨论】:

    【解决方案2】:

    您可以使用 numpy 的 intersect1d(一维集合相交)函数在数组之间查找重复项。

    duplicate_images = np.intersect1d(train_dataset, test_dataset) 
    

    我使用来自tensorflow tutorials 之一的训练集和测试集(分别为 55000 和 10000 个数组)来计时,我猜这与您的数据相似。使用intersect1d,在我的机器上完成大约需要2.4秒(使用参数assume_unique=True只需要1.3秒)。像你描述的成对比较需要几分钟。

    编辑

    这个答案(上面)不比较每个“图像”数组,正如@mbhall88 在 cmets 中指出的那样,它比较的是数组中的元素,而不是数组本身。为了确保它比较数组,您仍然可以使用intersect1d,但您必须首先处理 dtypes,如here 所述。但是,该答案中的示例处理 2d 数组,并且由于您正在使用 3d 数组,因此您应该首先展平第二个二维。您应该能够执行以下操作:

    def intersect3d(A,B, assume_unique=False):
        # get the original shape of your arrays
        a1d, a2d, a3d = A.shape
        # flatten the 2nd and 3rd dimensions in your arrays
        A = A.reshape((a1d,a2d*a3d))
        B = B.reshape((len(B),a2d*a3d))
        # define a structured dtype so you can treat your arrays as single "element"
        dtype=(', '.join([str(A.dtype)]*ncols))
        # find the duplicate elements
        C = np.intersect1d(A.view(dtype), B.view(dtype), assume_unique=assume_unique)
        # reshape the result and return
        return C.view(A.dtype).reshape(-1, ncols).reshape((len(C),a2d,a3d))
    

    【讨论】:

    • 这种方法的问题是它会在数组找到相同的元素。我对哪些 arrays 相同感兴趣,即数组中的所有元素都完全相同,而不仅仅是一个元素。
    • 你是绝对正确的。我相信this answer 展示了如何以您需要的方式使用intersect1d。我也会用链接更新答案。
    【解决方案3】:

    想出东西并不难:

    from collections import defaultdict
    import numpy as np
    
    def arrayhash(arr):
        u = arr.view('u' + str(arr.itemsize))
        return np.bitwise_xor.reduce(u.ravel())
    
    def do_the_thing(a, b, hashfunc=arrayhash):
        table = defaultdict(list)
        for i, a_i in enumerate(a):
            table[hashfunc(a_i)].append(i)
    
        indices = []
        for j, b_j in enumerate(b):
            candidates = table[hashfunc(b_j)]
            for i in candidates:
                if np.array_equiv(a[i], b_j):
                    indices.append((i,j))
    
        return indices
    

    但请注意:

    • 检查浮点相等性通常是一个坏主意,因为有限的精度和舍入误差。著名例子:

      >>> 0.1 + 0.2 == 0.3
      False
      
    • NaN 的比较不等于它们自己:

      >>> np.nan == np.nan
      False
      
    • 上面的简单散列函数考虑浮点数的位表示,但是在存在负零和信号 NaN 的情况下这是有问题的。

    另请参阅此问题中的讨论:Good way to hash a float vector?

    【讨论】:

      猜你喜欢
      • 2021-08-07
      • 2020-04-05
      • 2011-07-24
      • 2015-03-26
      • 2019-06-28
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多