将字符串转换为随机但确定性可重复的均匀概率

时间:2017-06-14 23:16:06

标签: python random hashlib

如何转换字符串,例如用户ID加盐,在半开放范围[0.0,1.0]中随机查看但实际上是确定性可重复的均匀概率?这个means表示输出≥0.0且< 1.0。无论输入分布如何,输出分布必须是均匀的。例如,如果输入字符串是'a3b2Foobar',则输出概率可以重复为0.40341504。

需要跨语言和跨平台的算法再现性。除非有更好的方法,否则我倾向于使用哈希函数。这就是我所拥有的:

Report.bulk_insert(:account_owner_id, ignore: true) do |worker|

我正在使用最新稳定的Python 3.请注意,这个问题与convert an integer to a random but deterministically repeatable choice的相关问题相似但不完全相同。

1 个答案:

答案 0 :(得分:17)

使用哈希

加密散列可以是[0,MAX_HASH]范围内的均匀分布整数。因此,可以通过将其除以MAX_HASH + 1将其缩放到[0,1]范围内的浮点数。

import hashlib

Hash = hashlib.sha512
MAX_HASH_PLUS_ONE = 2**(Hash().digest_size * 8)

def str_to_probability(in_str):
    """Return a reproducible uniformly random float in the interval [0, 1) for the given string."""
    seed = in_str.encode()
    hash_digest = Hash(seed).digest()
    hash_int = int.from_bytes(hash_digest, 'big')  # Uses explicit byteorder for system-agnostic reproducibility
    return hash_int / MAX_HASH_PLUS_ONE  # Float division

>>> str_to_probability('a3b2Foobar')
0.3659629991207491

注意:

  • 内置 hash 不能使用方法,因为它可以保留输入 分发,例如与hash(123)。或者,它可以返回重新启动Python时不同的值,例如与hash('123')
  • 因为浮动分割就足够了,所以不需要使用模数。

使用随机

random模块可以与in_str一起用作种子,同时解决围绕thread safety和连续性的问题。

通过这种方法,跨语言的可重复性不仅是一个问题,而且Python的多个未来版本的可重复性也可能是一个问题。因此不建议这样做。

import random

def str_to_probability(in_str):
    """Return a reproducible uniformly random float in the interval [0, 1) for the given seed."""
    return random.Random(in_str).random()

>>> str_to_probability('a3b2Foobar')
0.4662507245848473