如何将无符号整数(表示用户 ID)转换为看起来随机但实际上是确定性可重复的选择?必须以相等的概率选择该选项(无论输入整数的分布如何)。例如,如果我有 3 个选择,即[0, 1, 2]
例如,用户ID 123可以总是被随机分配选择2,而用户ID 234可以总是被分配选择1。
跨语言和跨平台的算法再现性是可取的。我倾向于使用哈希函数和模,除非有更好的方法。这是我所拥有的:
>>> num_choices = 3
>>> id_num = 123
>>> int(hashlib.sha256(str(id_num).encode()).hexdigest(), 16) % num_choices
2
我正在使用最新的稳定Python 3。请注意,这个问题与相关问题类似但不完全相同将字符串转换为随机但确定性可重复的均匀概率 https://stackoverflow.com/questions/44556105/convert-string-to-random-but-deterministically-repeatable-uniform-probability.
使用哈希和模数
import hashlib
def id_to_choice(id_num, num_choices):
id_bytes = id_num.to_bytes((id_num.bit_length() + 7) // 8, 'big')
id_hash = hashlib.sha512(id_bytes)
id_hash_int = int.from_bytes(id_hash.digest(), 'big') # Uses explicit byteorder for system-agnostic reproducibility
choice = id_hash_int % num_choices # Use with small num_choices only
return choice
>>> id_to_choice(123, 3)
0
>>> id_to_choice(456, 3)
1
Notes:
内置的hash https://docs.python.org/3/reference/datamodel.html#object.__hash__不得使用该方法,因为它可以保留输入的
分布,例如和hash(123)
。或者,它可以在 Python 重新启动时返回不同的值,例如和hash('123')
.
要将 int 转换为字节,bytes(id_num)
可以工作,但效率非常低,因为它返回一个空字节数组,因此不能使用它。使用int.to_bytes https://docs.python.org/library/stdtypes.html#int.to_bytes更好。使用str(id_num).encode()
有效但浪费了一些字节。
诚然,使用模并不能提供完全一致的概率,[1] https://stackoverflow.com/questions/13104478/uniformity-of-random-numbers-taken-modulo-n[2] https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator但这对于这个应用程序来说应该不会有太大偏差,因为id_hash_int
预计会非常大并且num_choices
被假定为很小。
使用随机
The random https://docs.python.org/library/random.html模块可与id_num
作为其种子,同时解决围绕两者的担忧线程安全 https://stackoverflow.com/questions/10021882/make-the-random-module-thread-safe-in-python和连续性。使用randrange
这种方式与散列种子和取模相当并且更简单。
使用这种方法,不仅需要考虑跨语言的可重复性,而且跨多个未来版本的 Python 的可重复性也可能是一个问题。因此不建议这样做。
import random
def id_to_choice(id_num, num_choices):
localrandom = random.Random(id_num)
choice = localrandom.randrange(num_choices)
return choice
>>> id_to_choice(123, 3)
0
>>> id_to_choice(456, 3)
2
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)