scipy beta分布与numpy clip的数值问题

文章讨论了Beta分布的不同形态,包括在参数α和β取不同值时的表现,特别关注了0、1附近的数值问题。作者通过实例展示了如何使用scipy.stats.beta.pdf函数处理这些边界情况,并指出在编程中应限制x值在[ε,1-ε]之间以避免无限大值。此外,还通过numpy.clip函数验证了数值稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[1] 用到混合 Beta 分布,估计参数的方法见 [2]。由 [3] 可见 Beta 分布在其参数 α , β \alpha,\beta α,β 在不同取值范围时存在几种形态:

  • α , β < 0 \alpha,\beta < 0 α,β<0:不合法;
  • α = β = 1 \alpha=\beta=1 α=β=1:常数, B ( x ; 1 , 1 ) ≡ 1 \Beta(x;1,1)\equiv 1 B(x;1,1)1
  • α , β > 1 \alpha, \beta > 1 α,β>1:钟形(bell shape),即单峰(unimodal);
  • 0 < α < 1 ≤ β 0<\alpha<1\leq\beta 0<α<1β:L 形;
  • 0 < β < 1 ≤ α 0<\beta<1\leq\alpha 0<β<1α:J 形;
  • 0 < α , β < 1 0<\alpha,\beta<1 0<α,β<1:U 形。

其中后三种在 0、1 处会取到正无穷,可能在编程时引起问题,如:

invalid value encountered in divide

此处给出各种形状( α , β \alpha,\beta α,β 组合)下,变量 x 在各种取值时, B ( x ; α , β ) \Beta(x;\alpha,\beta) B(x;α,β) 的值(尤其是变量 x 在 0、1 附近时)作为参考:

import scipy.stats as stats
import numpy as np

# 临界 epsilon
eps1 = 1e-7
eps2 = 1e-8

# 变量
x = np.array([
    -1, # <<0
    - eps1, - eps2, 0, eps2, eps1, # near 0
    1 - eps1, 1 - eps2, 1, 1 + eps2, 1 + eps1, # near 1
    2, # >>1
], dtype=np.float32)
print(x)

print("\tinvalid: alpha, beta < 0")
print("alpha < 0:", stats.beta.pdf(x, -0.5, 1))
print("beta < 0:", stats.beta.pdf(x, 1, -0.5))

print("\tU-shape: 0 < alpha, beta < 1")
print(stats.beta.pdf(x, 0.5, 0.5))

print("\tL-shape: 0 < alpha < 1 <= beta")
print(stats.beta.pdf(x, 0.5, 1))

print("\tJ-shape: 0 < beta < 1 <= alpha")
print(stats.beta.pdf(x, 1, 0.5))

print("\tconstant: alpha = beta = 1")
print(stats.beta.pdf(x, 1, 1))

print("\tbell-shape (unimodal): 1 < alpha, beta")
print(stats.beta.pdf(x, 2, 2))

输出:

[-1, -1e-7, -1e-8, 0, 1e-8, 1e-7, 0.99999988, 1.0000000e+00, 1, 1.0000000e+00, 1.0000001, 2]

        invalid: alpha, beta < 0
alpha < 0: [nan nan nan nan nan nan nan nan nan nan nan nan]
beta < 0: [nan nan nan nan nan nan nan nan nan nan nan nan]

        U-shape: 0 < alpha, beta < 1
[0, 0, 0, inf, 5.1460, 4.0876, 4.0164, inf, inf, inf, 0, 0]

        L-shape: 0 < alpha < 1 <= beta
[0, 0, 0, inf, 6.2062, 4.9298, 0.1997, 0, 0, 0, 0, 0]

        J-shape: 0 < beta < 1 <= alpha
[0, 0, 0, 0, 0.1558, 0.1962, 4.8439, inf, inf, inf, 0, 0]

        constant: alpha = beta = 1
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]

        bell-shape (unimodal): 1 < alpha, beta
[0, 0, 0, 0, 5.99999990e-08, 5.99999947e-07, 7.15255652e-07, 0, 0, 0, 0, 0]

考察其中出现 inf 的位置,可以考虑在调用 scipy.stats.beta.pdf 时将 x 的值限定在 [ ϵ , 1 − ϵ ] [\epsilon, 1 - \epsilon] [ϵ,1ϵ] 之间,其中 ϵ \epsilon ϵ = 1e-7

除了上面的测试,此 ϵ \epsilon ϵ 还能如此验证:用 numpy.clip 重复实验,将 0/1 截断到 [ ϵ , 1 − ϵ ] [\epsilon, 1 - \epsilon] [ϵ,1ϵ] 之间,看从哪个精度开始数值开始不稳定。代码:

import numpy as np

zero = np.zeros([500], dtype=np.float32)
one = np.ones([500], dtype=np.float32)
# 有 0 有 1 的数据
x = np.concatenate([zero, one], axis=0)

# 测试 numpy.clip 对各 epsilon 的稳定性
for eps in (1e-7, 1e-8):
    print(eps)
    for _ in range(100):
        y = np.clip(x.copy(), eps, 1 - eps) # deep copy, then clip
        # 若成功截断,则不应再有 0/1
        assert (0 != y).all() and (1 != y).all()

实验表明,1e-7 能让 numpy.clip 稳定截断,而 1e-8 却不能。

(2024.12.2)本文所讲的数值问题在 [5] 早已发现(cvpr’24 deadline 早于本文首发时间),而在方法中只是一笔带过。

References

  1. (CVPR 2023) BiCro: Noisy Correspondence Rectification for Multi-modality Data via Bi-directional Cross-modal Similarity Consistency - paper, code
  2. EM算法估计beta混合模型参数
  3. 贝塔分布
  4. Beta Distribution | MIT Mathlets
  5. (cvpr’24) Learning to Rematch Mismatched Pairs for Robust Cross-Modal Retrieval - paper, code
<think>嗯,用户问的是0到65之间的随机数正态分布表。首先,我需要明确正态分布表通常指的是标准正态分布的累积概率表,但用户可能想要的是生成符合正态分布且范围在0到65之间的随机数,或者如何根据正态分布来创建一个数值表。 首先,正态分布理论上范围是负无穷到正无穷,但实际应用中数值集中在均值附近。如果用户想要在0-65之间生成随机数,可能需要截断正态分布,或者调整参数使得大部分数值落在这个区间内。例如,选择一个均值在中间值,比如32.5,然后调整标准差,使得99.7%的数据在0-65之间。根据经验法则,三个标准差覆盖大部分数据,所以标准差大约是(65/2)/3 ≈ 10.83。这样,均值32.5,标准差约10.83的正态分布可能适合。 接下来,生成这样的随机数可能需要使用Python中的numpy库,用truncated normal distribution的方法,或者直接生成后裁剪数值。但用户可能更关心如何构造这样的表格,比如分位数对应的数值,或者如何查表。不过通常正态分布表是标准化的,用户可能需要自定义均值和标准差的表。 另外,用户可能是想要一个具体的表格,比如不同z值对应的数值在0-65之间。这时候可能需要将z分数转换为实际数值,通过X = μ + zσ。例如,z=0对应32.5,z=1对应32.5+10.83≈43.33,z=-1对应21.67等。 但用户提到的是“随机数正态分布表”,可能是指生成随机数的参考表,或者是概率密度表。可能需要进一步澄清,但考虑到用户可能的需求,提供一个生成此类随机数的方法会更实用。比如在Python中使用numpy.random.normal,然后设置参数和截断。 也可能用户需要的是离散的正态分布表,列出每个整数点的概率,但正态分布是连续的,转为离散可能需要积分每个区间的概率,或者近似计算。这比较复杂,可能用户更需要的是生成方法而不是表格。 总结下来,用户可能需要的是如何在0-65之间生成正态分布的随机数,以及对应的参数设置和代码示例。需要解释均值和标准差的选择,以及如何处理超出范围的情况,比如截断或重新生成。同时,可能需要提醒正态分布在此范围的应用限制,比如严格限制在0和65可能导致分布不完全正态,但近似可行。</think>以下是对0-65范围内正态分布随机数的介绍及生成方法: ### 1. 核心概念 - **正态分布**:数据呈钟形对称分布,由均值(μ)和标准差(σ)决定形态。 - **范围约束**:需将理论上的无限范围(-∞, +∞)压缩到[0, 65],需通过参数调整实现。 ### 2. 参数设定建议 - **均值(μ)**:建议设为区间中点32.5 - **标准差(σ)**:推荐设为约10.83 (计算逻辑:65/6≈10.83,确保99.7%数据在±3σ内) ### 3. 生成方法(Python示例) ```python import numpy as np mu, sigma = 32.5, 10.83 nums = np.random.normal(mu, sigma, 1000) # 强制限定范围(简单截断法) truncated = np.clip(nums, 0, 65) # 精确截断法(推荐) from scipy.stats import truncnorm a, b = (0 - mu)/sigma, (65 - mu)/sigma trunc_nums = truncnorm.rvs(a, b, loc=mu, scale=sigma, size=1000) ``` ### 4. 典型数值参考表 | Z值 | 对应数值 | 累积概率 | |--| | -3σ | 0.01 | 0.1% | | -2σ | 11.84 | 2.3% | | -1σ | 21.67 | 15.9% | | 0 | 32.5 | 50% | | +1σ | 43.33 | 84.1% | | +2σ | 54.16 | 97.7% | | +3σ | 64.99 | 99.9% | ### 5. 注意事项 - 严格截断会轻微影响分布形态 - 需要超过99.7%数据在范围内时,可适当缩小σ - 极端场景建议改用Beta分布等有限区间分布 实际应用中,建议结合具体需求调整参数,并通过直方图验证分布形态是否满足要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值