numpy 数组的唯一标识符?
Unique identifier for numpy array?
我的情况是我有一些二维数组 A
,我的代码中 classes 中的一个方法使用了它,然后我需要检查一个数组是否通过了不同的方法具有相同的值。
明显的解决方法是将 A
另存为 class 属性,但由于 A
可能变得非常大,我想避免将其添加为属性以避免内存问题。
我想做的是为这个数组保存某种唯一标识符并检查它。我的第一个想法是使用 id(A)
,但这是对象的唯一标识符,而不是数组,所以如果我有一些 B = A.copy()
,它会有不同的 id
.
另一个想法是保存 A 的一些稀疏版本,例如,对一些随机索引进行采样并检查等价性,但这似乎比我需要的这样的东西更混乱和深入。
有人有什么建议吗?
使用 hash function 例如SHA-256 通过 hashlib
模块。下面是生成 hash-based ID 的示例。 array_id()
函数 returns 对于固定长度为 64 个符号的数组字符串是唯一的。相同内容的数组会产生相同的id,而即使改变一小部分,它也将是完全不同的id。
请注意,不同类型的数组可能会产生不同的结果,例如如果您有两个具有相同整数值的整数数组,但一个具有类型 np.int32
另一个是 np.int64
那么您将获得不同的 ID,在这种情况下,您只需要将数组更改为一种常见类型,例如做 res_id = array_id(a.astype(np.int64))
。但不同的类型并不总是意味着哈希 ID 会不同,例如如果所有整数都是 non-negative 且小于 2^31,则 np.int32
和 np.uint32
类型都将给出相同的哈希值。
因此,如果您希望 hash-IDs 对于相同值的数字相同,则始终将数组类型更改为某些常见类型,例如 array_id(a.astype(common_type))
,其中 common_type
可能是例如np.int64
用于所有整数类型,np.float64
用于所有浮点类型。相反,如果您希望不同的类型总是产生不同的结果,则将类型名称包含到散列中,例如 hashlib.sha256(str(a.dtype).encode('ascii') + a.tobytes()).hexdigest().upper()
.
在接下来的代码中,如果您传递标志 include_dtype = True
,那么数据类型将包含在 ID 计算中。如果 include_shape = True
也会包含形状。 algo
参数(sha256
或 xxhash
)选择要使用的哈希算法。
代码需要通过命令安装一次模块python -m pip install numpy xxhash
。
# Needs: python -m pip install numpy xxhash
def array_id(a, *, include_dtype = False, include_shape = False, algo = 'xxhash'):
data = bytes()
if include_dtype:
data += str(a.dtype).encode('ascii')
data += b','
if include_shape:
data += str(a.shape).encode('ascii')
data += b','
data += a.tobytes()
if algo == 'sha256':
import hashlib
return hashlib.sha256(data).hexdigest().upper()
elif algo == 'xxhash':
import xxhash
return xxhash.xxh3_64(data).hexdigest().upper()
else:
assert False, algo
# Test
import numpy as np, timeit
a = np.array([[1,2,3],[4,5,6]])
print(array_id(a))
print(array_id(a, include_shape = True))
print(array_id(a, include_shape = True, include_dtype = True))
# Speed Measure
a = np.ones((10000, 10000,), dtype = np.uint32)
for algo in ['sha256', 'xxhash']:
print(algo, round(timeit.timeit(lambda: array_id(a, algo = algo), number = 1), 3), 'sec')
输出:
17A96F5E5826D66A
E201378DF28CB280
0FDFAE47334C986A
sha256 3.774 sec
xxhash 1.356 sec
我的情况是我有一些二维数组 A
,我的代码中 classes 中的一个方法使用了它,然后我需要检查一个数组是否通过了不同的方法具有相同的值。
明显的解决方法是将 A
另存为 class 属性,但由于 A
可能变得非常大,我想避免将其添加为属性以避免内存问题。
我想做的是为这个数组保存某种唯一标识符并检查它。我的第一个想法是使用 id(A)
,但这是对象的唯一标识符,而不是数组,所以如果我有一些 B = A.copy()
,它会有不同的 id
.
另一个想法是保存 A 的一些稀疏版本,例如,对一些随机索引进行采样并检查等价性,但这似乎比我需要的这样的东西更混乱和深入。
有人有什么建议吗?
使用 hash function 例如SHA-256 通过 hashlib
模块。下面是生成 hash-based ID 的示例。 array_id()
函数 returns 对于固定长度为 64 个符号的数组字符串是唯一的。相同内容的数组会产生相同的id,而即使改变一小部分,它也将是完全不同的id。
请注意,不同类型的数组可能会产生不同的结果,例如如果您有两个具有相同整数值的整数数组,但一个具有类型 np.int32
另一个是 np.int64
那么您将获得不同的 ID,在这种情况下,您只需要将数组更改为一种常见类型,例如做 res_id = array_id(a.astype(np.int64))
。但不同的类型并不总是意味着哈希 ID 会不同,例如如果所有整数都是 non-negative 且小于 2^31,则 np.int32
和 np.uint32
类型都将给出相同的哈希值。
因此,如果您希望 hash-IDs 对于相同值的数字相同,则始终将数组类型更改为某些常见类型,例如 array_id(a.astype(common_type))
,其中 common_type
可能是例如np.int64
用于所有整数类型,np.float64
用于所有浮点类型。相反,如果您希望不同的类型总是产生不同的结果,则将类型名称包含到散列中,例如 hashlib.sha256(str(a.dtype).encode('ascii') + a.tobytes()).hexdigest().upper()
.
在接下来的代码中,如果您传递标志 include_dtype = True
,那么数据类型将包含在 ID 计算中。如果 include_shape = True
也会包含形状。 algo
参数(sha256
或 xxhash
)选择要使用的哈希算法。
代码需要通过命令安装一次模块python -m pip install numpy xxhash
。
# Needs: python -m pip install numpy xxhash
def array_id(a, *, include_dtype = False, include_shape = False, algo = 'xxhash'):
data = bytes()
if include_dtype:
data += str(a.dtype).encode('ascii')
data += b','
if include_shape:
data += str(a.shape).encode('ascii')
data += b','
data += a.tobytes()
if algo == 'sha256':
import hashlib
return hashlib.sha256(data).hexdigest().upper()
elif algo == 'xxhash':
import xxhash
return xxhash.xxh3_64(data).hexdigest().upper()
else:
assert False, algo
# Test
import numpy as np, timeit
a = np.array([[1,2,3],[4,5,6]])
print(array_id(a))
print(array_id(a, include_shape = True))
print(array_id(a, include_shape = True, include_dtype = True))
# Speed Measure
a = np.ones((10000, 10000,), dtype = np.uint32)
for algo in ['sha256', 'xxhash']:
print(algo, round(timeit.timeit(lambda: array_id(a, algo = algo), number = 1), 3), 'sec')
输出:
17A96F5E5826D66A
E201378DF28CB280
0FDFAE47334C986A
sha256 3.774 sec
xxhash 1.356 sec