假设我有一些在 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
,但这实际上不适合这里,因为:
(也称为逆 CDF)将 [0, 1] 中的均匀随机数映射到遵循分布(例如正态分布)的数字。 但是,在
正态分布的情况下,有一些事情需要了解(从现在起调用分位数函数 Q(u)):
分位数函数的范围是从 0 到 1,而不是从 -1 到 1 或从 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
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
是描述线性映射偏差的参数。我猜有无限的可能性,选择取决于精度与计算量。