You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python基于指定统计分布生成带上下限范围随机数的方法

限定上下界的指定分布随机数生成方案(Python)

所有定义在无界区间或[0,1]标准区间的概率分布,都可以通过截断+线性映射的方式适配任意自定义上下限,不需要手动枚举区间值、也不需要手写权重数组,完全适配2000000~1800000000微秒的取值区间要求。

前置依赖

推荐用numpy实现批量/单个样本生成,比原生random模块效率高1~2个数量级,需要严格正态分布场景可搭配scipy使用:

pip install numpy scipy

首先定义全局区间常量,后续所有分布函数直接复用:

import numpy as np
from scipy.stats import truncnorm

# 区间上下限,单位:微秒
LOWER_BOUND = 2_000_000
UPPER_BOUND = 1_800_000_000
INTERVAL_RANGE = UPPER_BOUND - LOWER_BOUND

各目标分布实现

1. Beta分布(最灵活,优先推荐)

Beta分布原生取值范围固定为[0,1],不需要额外做截断处理,直接线性映射到目标区间即可。仅调整Alpha、Beta两个参数即可生成各类对称、偏态、U型分布形态:

  • alpha=beta=1:等价于均匀分布,和random.randint效果一致
  • alpha=beta>1:对称钟形分布(类正态),参数值越大分布越窄,越向区间中点集中
  • alpha>beta:右偏(负偏)分布,峰值靠近区间上限
  • beta>alpha:左偏(正偏)分布,峰值靠近区间下限
  • alpha<1, beta<1:U型分布,概率集中在区间两端

实现代码:

def sample_beta(alpha: float, beta: float, size: int = 1) -> int | np.ndarray:
    raw_samples = np.random.beta(alpha, beta, size=size)
    mapped = (LOWER_BOUND + raw_samples * INTERVAL_RANGE).round().astype(np.int64)
    return mapped[0] if size == 1 else mapped

# 调用示例
left_skew_num = sample_beta(alpha=2, beta=5)  # 左偏(正偏),小值概率更高
narrow_norm_num = sample_beta(alpha=10, beta=10)  # 窄对称钟形分布,集中在区间中点
wide_norm_num = sample_beta(alpha=2, beta=2)  # 宽对称钟形分布,取值更分散
right_skew_num = sample_beta(alpha=5, beta=2)  # 右偏(负偏),大值概率更高

2. 截断正态分布(严格正态特性)

如果需要严格符合正态分布的概率密度特性(而非Beta类钟形近似),使用截断正态分布,自动丢弃超出上下限的样本,保证所有返回值都在目标区间内:

def sample_trunc_normal(mean: float, std: float, size: int = 1) -> int | np.ndarray:
    # 计算上下限对应的标准化分位数
    a = (LOWER_BOUND - mean) / std
    b = (UPPER_BOUND - mean) / std
    samples = truncnorm.rvs(a, b, loc=mean, scale=std, size=size)
    mapped = samples.round().astype(np.int64)
    return mapped[0] if size == 1 else mapped

# 调用示例
mid_point = (LOWER_BOUND + UPPER_BOUND) / 2
narrow_norm_num = sample_trunc_normal(mean=mid_point, std=INTERVAL_RANGE/10)  # 窄正态
wide_norm_num = sample_trunc_normal(mean=mid_point, std=INTERVAL_RANGE/3)  # 宽正态

3. 指数分布/逆指数分布

指数分布原生取值范围为[0, +∞),通过逆变换采样截断到[0,1]区间后映射到目标范围即可:

  • 普通指数分布:取值越小概率越高,靠近2秒的样本占比最高
  • 逆指数分布:取值越大概率越高,靠近30分钟的样本占比最高

实现代码:

def sample_exponential(lam: float = 2, size: int = 1) -> int | np.ndarray:
    u = np.random.uniform(size=size)
    raw = -np.log(1 - u * (1 - np.exp(-lam))) / lam
    mapped = (LOWER_BOUND + raw * INTERVAL_RANGE).round().astype(np.int64)
    return mapped[0] if size == 1 else mapped

def sample_inverse_exponential(lam: float = 2, size: int = 1) -> int | np.ndarray:
    u = np.random.uniform(size=size)
    raw = 1 + np.log(u * (1 - np.exp(-lam)) + np.exp(-lam)) / lam
    mapped = (LOWER_BOUND + raw * INTERVAL_RANGE).round().astype(np.int64)
    return mapped[0] if size == 1 else mapped

# 调用示例
exp_num = sample_exponential()  # 指数分布
inv_exp_num = sample_inverse_exponential()  # 逆指数分布

补充说明

  • 如果需要纯Python实现(不依赖numpy/scipy),将代码中numpy的随机数调用替换为random模块对应方法即可,仅在批量生成百万级以上样本时速度会明显降低
  • 所有函数默认返回整数微秒值,如果需要浮点精度,去掉.round().astype(np.int64)转换即可
  • 单样本调用时默认返回单个int值,需要批量生成时传入size参数即可返回对应长度的数组,不需要循环调用

内容的提问来源于stack exchange,提问作者Sal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 04:15:55