带权重的三分布1000万随机样本抽取实现求助
高效实现带权重的混合分布抽样(1000万样本)
问题需求
现有三个统计分布disbn_1、disbn_2、disbn_3,需按照权重w_1=0.75、w_2=0.2、w_3=0.05抽取总计1000万个随机变量。此前尝试两种方案均失败:
- 方案一:为每个分布预生成1000万样本,再用
np.random.choice按权重选择样本,未达到预期效果; - 方案二:尝试用生成器动态生成样本,但无法获取新样本。
要求实现高效抽样,兼顾速度与内存占用。
错误原因分析
- 方案一问题:直接使用
np.random.choice选择三个数组的元素时,默认逻辑是从数组索引中抽样,而非按权重分配各分布的样本数量。同时预生成3×1000万样本会占用大量不必要的内存。 - 方案二问题:当前代码中
generators列表存储的是单个样本(rvs()无参数时默认生成1个样本),而非可重复调用的生成逻辑,因此无法生成新样本。
高效解决方案
核心思路:先按权重分配各分布的样本数量,再批量生成对应样本,最后合并打乱。批量生成样本是scipy/numpy的最优操作方式,内存占用低且速度快。
具体步骤
- 用
np.random.multinomial按权重分配1000万样本到三个分布,确保样本总数准确; - 针对每个分布,批量生成对应数量的样本,应用
clip截断和偏移处理; - 合并所有样本并打乱顺序(若不需要随机顺序可省略打乱步骤)。
完整实现代码
import numpy as np import scipy.stats as sp # 定义分布参数与权重 min_1 = 10_000_000 max_1 = 8_000_000_000 par_1 = 1000 w_1 = 0.75 disbn_1 = sp.expon(scale=par_1) min_2 = 2000000 max_2 = max_1 par_2 = 1.6 w_2 = 0.2 disbn_2 = sp.pareto(par_2, scale=min_2) min_3 = 1000000 max_3 = max_1 par_3 = 455555 w_3 = 0.05 disbn_3 = sp.expon(scale=par_3) total_samples = 10_000_000 # 按权重分配各分布的样本数量 counts = np.random.multinomial(total_samples, [w_1, w_2, w_3]) count_1, count_2, count_3 = counts # 批量生成各分布的样本 samples_1 = np.clip(disbn_1.rvs(count_1) + min_1, a_min=0, a_max=max_1) samples_2 = np.clip(disbn_2.rvs(count_2), a_min=0, a_max=max_2) samples_3 = np.clip(disbn_3.rvs(count_3) + min_3, a_min=0, a_max=max_3) # 合并所有样本并打乱顺序 final_samples = np.concatenate([samples_1, samples_2, samples_3]) np.random.shuffle(final_samples) # 验证样本数量与权重分布 print(f"总样本数:{len(final_samples)}") print(f"各分布实际样本数:{count_1}, {count_2}, {count_3}") print(f"实际权重:{count_1/total_samples:.3f}, {count_2/total_samples:.3f}, {count_3/total_samples:.3f}")
方案优势
- 内存高效:仅生成所需数量的样本,避免预生成冗余数据;
- 速度快:利用scipy的批量
rvs()方法,比单个生成样本效率高几个数量级; - 准确性高:通过
multinomial确保样本总数严格为1000万,权重分布符合预期。
内容的提问来源于stack exchange,提问作者user144464
相关产品推荐
相关产品推荐

