转换数据,使中位数周围的范围更加准确

问题描述 投票:0回答:2

假设我有一些在 0 附近呈正态分布的浮点数。我需要将其序列化为 uint8,但我想将 uint8“给予更多”到分布的中心,并在边缘周围失去分辨率。

例如:

127
对应于
0.0
255
对应于
1.0
。但是
191
不会0.5
 — 相反,它会类似于 
0.3
,因为我们正在拉伸它,以便大多数数字对应于接近 0 的值。

实际上,我实际上会生成一个随机的

uint32

 并将其转换为 
float
。但在测试线性映射时,极端值(-1.0 和 1.0 附近)出现得太频繁,我想将其集中在 
0.0
 周围。

我知道我可以使用

Box–Muller transform

,但这实际上不适合这里,因为:

  1. 我们可以将上限设置为 -1.0 和 1.0,不需要无限制的输出。

  2. 我们只有一个数字可供抽样,而不是两个。

谢谢

algorithm math random normal-distribution
2个回答
1
投票
分位数函数

(也称为逆 CDF)将 [0, 1] 中的均匀随机数映射到遵循分布(例如正态分布)的数字。 但是,在

正态分布

的情况下,有一些事情需要了解(从现在起调用分位数函数 Q(u)):

分位数函数的范围是从 0 到 1,而不是从 -1 到 1 或从 0 到 255。
  • 正态分布可以呈现任何实数。事实上,对于这个分布,Q(0) 和 Q(1) 将等于无穷大。
  • 正态分布的分位数涉及逆误差函数。分位数可能容易实现,也可能不容易实现,具体取决于您的编程环境是否已经具有可用的逆误差函数。
  • 出于上述原因,只要允许所需范围内的值作为端点,您就必须缩放分位数函数以适合您所需的范围并避免无穷大,例如从 [0.001, 0.999] 到 [0, 255] 。下面是伪代码的示例。
  • for k in 0..255 c=0.001+(0.999-0.001)*(k*1.0/256) print([k, Q(c)]) // print the uint8 value followed by the quantile end


1
投票
erf

和相应的逆。但如果你只想接近,你可以采用任何你喜欢的S形函数。 前向和后向映射的一些 Python 示例可能是:

def map_fwd( x, s ):
    return  x / np.sqrt( 1 + s**2 * ( 1 - x**2 ) )
 
def map_bwd( y, s ):
    x = np.sqrt( 1 + s**2 ) * y / np.sqrt( 1 + (s * y)**2 )
    return x

def map_fwd( x, s ): return np.arctanh( np.tanh( s ) * x ) / s def map_bwd( y, s ): x = np.tanh( s * y ) / np.tanh( s ) return x

或者一些极端的喜欢

def map_fwd( x, m ): return ellipkinc( np.pi * x / 2.0, m ) / ellipkinc( np.pi / 2.0, m ) def map_bwd( y, m ): u = ellipkinc( np.pi / 2.0, m ) * y phi = ellipj( u, m )[-1] x = phi * 2 / np.pi return x

其中 
s

m
是描述线性映射偏差的参数。
我猜有无限的可能性,选择取决于精度与计算量。

© www.soinside.com 2019 - 2024. All rights reserved.