在Python中的随机四舍五入整数

8
我正在寻找一种方法,根据小数点后的数字推导出概率,将浮点数四舍五入为下一个整数。例如,浮点数6.1可以舍入为6或7。被舍入为7的概率是0.1,被舍入为6的概率是1-0.1。因此,如果我无限次运行这个舍入实验,所有整数结果的平均值应该再次是6.1。我不知道是否有一个名称来描述这种过程,也不知道Python中是否已经实现了该函数。
当然,如果可能的话,以相同的方式对小数点后的数字舍入到2位数也会非常好。您是否明白我的意思? 有什么想法吗?

我无法看出这个尝试的意义 (-: - 但这是可能的; 获取您的有效数字作为整数,并使用 numpy.random.rand() 进行乘法以进行舍入决策,我猜。 - Faultier
这种过程有一个名称,即:随机舍入,参见:https://en.wikipedia.org/wiki/Rounding#Stochastic_rounding - Mas A
6个回答

9

这里有一个优美的一行代码。通过使用 floor 函数,只有在随机数在 0 和 1 之间且足以使其上升到下一个最高整数时才会对其进行四舍五入。该方法对正负数同样适用。

def probabilistic_round(x):
    return int(math.floor(x + random.random()))

考虑一个负输入的情况x = -2.25。随机数有75%的概率大于或等于0.25,此时floor函数的结果为-2。其他25%的时间,数字将四舍五入为-3。

要将其舍入到不同的小数位数,可以进行以下修改:
def probabilistic_round(x, decimal_places=0):
    factor = 10.0**decimal_places
    return int(math.floor(x*factor + random.random()))/factor

8
你要寻找的概率是x-int(x)
使用这个概率进行采样,可以做到random.random() < x-int(x)
import random
import math
import numpy as np

def prob_round(x):
    sign = np.sign(x)
    x = abs(x)
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return sign * round_func(x)

x = 6.1
sum( prob_round(x) for i in range(100) ) / 100.
=> 6.12

编辑:添加一个可选的prec参数:

def prob_round(x, prec = 0):
    fixup = np.sign(x) * 10**prec
    x *= fixup
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return round_func(x) / fixup

x = 8.33333333
[ prob_round(x, prec = 2) for i in range(10) ]
=> [8.3399999999999999,
 8.3300000000000001,
 8.3399999999999999,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3399999999999999,
 8.3399999999999999]

这个能否在不使用分支的情况下实现? - étale-cohomology
@étale-cohomology,当然可以。你可以这样做:math.floor(x) + (random.random() < x-int(x))。哪个版本更易读是有争议的。 - shx2

6

对于非负数x,最简洁的方法是:

int(x + random.random())

如果例如 x == 6.1,那么 random.random() 有 10% 的概率足够大,使得 x + random.random() >= 7
请注意,如果 x == 6,那么这个表达式保证返回6,因为 random.random() 始终在 [0, 1) 范围内。
更新:此方法仅适用于非负输入。对于适用于负数的解决方案,请查看 Chris Locke 的答案。

2

要将正数四舍五入为整数,您可以非常简洁地执行以下操作:

x = int(x) + (random.random() < x - int(x))

这是因为Python的bool类型是int的子类。值True等于1,而False等于0。

1
我也想到了一种基于随机二项式函数和shx2已经提供的代码的解决方案:
def prob_round(x, prec = 0):
    fixup = np.sign(x) * 10**prec
    x *= fixup 
    round_func = int(x) + np.random.binomial(1,x-int(x))
    return round_func/fixup

-2

这里有一个简单的方法:

x = round(random.random()*100)

*100 位表示从1到100。
如果是 *200,则表示从1到200。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接