【问题标题】:How to hash a large object (dataset) in Python?如何在 Python 中散列一个大对象(数据集)?
【发布时间】:2023-03-22 00:35:01
【问题描述】:

我想计算一个包含机器学习数据集的 Python 类的哈希值。哈希是用来缓存的,所以我在想md5sha1。 问题是大部分数据都存储在 NumPy 数组中;这些不提供__hash__() 成员。目前我为每个成员做一个pickle.dumps() 并根据这些字符串计算一个哈希值。但是,我发现以下链接表明同一个对象可能导致不同的序列化字符串:

为包含 Numpy 数组的 Python 类计算哈希的最佳方法是什么?

【问题讨论】:

  • 不是一个经验丰富的 python 程序员,但是,序列化对象和散列会起作用吗?

标签: python hash numpy sha1 pickle


【解决方案1】:

使用 Numpy 1.10.1 和 python 2.7.6,如果数组是 C 连续的,您现在可以使用 hashlib 简单地对 numpy 数组进行哈希处理(如果不是,则使用 numpy.ascontiguousarray()),例如

>>> h = hashlib.md5()
>>> arr = numpy.arange(101)
>>> h.update(arr)
>>> print(h.hexdigest())
e62b430ff0f714181a18ea1a821b0918

【讨论】:

    【解决方案2】:

    最快的似乎是:

    哈希(iter(a))

    a 是一个 numpy ndarray。

    显然不安全散列,但它应该有利于缓存等。

    【讨论】:

    • 在 python 3.3+ 下,由于安全性的改进,你不会在不同的 python 运行中获得相同的哈希值。
    【解决方案3】:

    有一个用于记忆函数的包,它使用 numpy 数组作为输入 joblib。从this 问题中找到。

    【讨论】:

      【解决方案4】:

      这是我在jug 中的做法(回答时为 git HEAD):

      e = some_array_object
      M = hashlib.md5()
      M.update('np.ndarray')
      M.update(pickle.dumps(e.dtype))
      M.update(pickle.dumps(e.shape))
      try:
          buffer = e.data
          M.update(buffer)
      except:
          M.update(e.copy().data)
      

      原因是e.data 仅适用于某些数组(连续数组)。与a.view(np.uint8) 相同(如果数组不连续,则会失败并出现非描述性类型错误)。

      【讨论】:

        【解决方案5】:

        array.data 始终是可散列的,因为它是一个缓冲区对象。容易:)(除非您关心具有完全相同数据的不同形状数组之间的差异等。(即这是合适的,除非形状、字节顺序和其他数组“参数”也必须计入散列)

        【讨论】:

        • array.data 从 numpy 1.6.2 和 python 2.7 起不可散列
        【解决方案6】:

        感谢 John Montgomery,我想我找到了一个解决方案,而且我认为它比将可能 huge 数组中的每个数字转换为字符串的开销更少:

        我可以创建数组的字节视图并使用它们来更新哈希。不知何故,这似乎给出了与使用数组直接更新相同的摘要:

        >>> import hashlib
        >>> import numpy
        >>> a = numpy.random.rand(10, 100)
        >>> b = a.view(numpy.uint8)
        >>> print a.dtype, b.dtype # a and b have a different data type
        float64 uint8
        >>> hashlib.sha1(a).hexdigest() # byte view sha1
        '794de7b1316b38d989a9040e6e26b9256ca3b5eb'
        >>> hashlib.sha1(b).hexdigest() # array sha1
        '794de7b1316b38d989a9040e6e26b9256ca3b5eb'
        

        【讨论】:

        • 你能用这种技术从缓存中重新创建对象吗?看来您只能取回 uint8 类型的数组(牺牲数组的准确性)。
        • 使用约翰蒙哥马利的解决方案,看起来你会得到一个 float64 数组。
        • @tgray:有时准确性并不重要。无论如何,实验数据,尤其是大数据,往往具有很大的不确定性。显然这取决于上下文,但一般规则是双精度对计算很重要,而不是存储数据或最终答案。
        【解决方案7】:

        数组中数据的格式是什么?难道你不能遍历数组,将它们转换为字符串(通过一些可重现的方式),然后通过更新将其输入到你的哈希中吗?

        例如

        import hashlib
        m = hashlib.md5() # or sha1 etc
        for value in array: # array contains the data
            m.update(str(value))
        

        尽管 numpy 数组不会提供 __hash__(),但不要忘记,因为它们是可变的。因此,请注意不要在计算哈希后修改数组(因为它不再相同)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-08
          • 2018-09-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-12
          相关资源
          最近更新 更多