使用Numpy从两个均匀分布生成双峰分布的实现问题排查
问题:生成双峰分布样本时出现超出[0,1]范围的值,代码哪里错了?
我尝试复现某博客中的bimodalSample函数,以下是我的实现代码:
import numpy as np def bimodal_pdf(distance: float, weight: float) -> np.ndarray: r = np.random.rand() if r < weight: return np.random.normal(r) * (1 - distance) else: return np.random.normal(r) * (1 - distance) + distance n_samples = 100000 distance = 0.7 weight = 0.5 pdf = np.array([ bimodal_pdf(distance=distance, weight=weight) for s in range(n_samples) ])
但生成的样本值出现小于0或大于1的情况,请问我的实现哪里出错了?
分析与修正
你的代码有两个核心错误:
正态分布参数使用错误
np.random.normal(r)的写法完全不符合需求:该函数的第一个参数是均值,第二个是标准差(默认1)。你把r(0-1的随机数)当成均值传入,导致每个样本的正态分布均值都在随机变化,完全偏离了双峰分布(两个固定中心)的设计。采样逻辑错误
原目标函数应该是生成两个固定中心的正态分布混合样本:一个中心在0,另一个中心在distance,通过weight控制两个分布的采样比例。你的计算逻辑(乘以1-distance再加偏移)完全打乱了分布的中心和范围控制。
修正后的代码
import numpy as np def bimodal_sample(distance: float, weight: float) -> float: # 用(1-distance)/3作为标准差,确保99.7%的样本落在[0,1]范围内 std_dev = (1 - distance) / 3 if np.random.rand() < weight: # 从中心为0的正态分布采样 return np.random.normal(loc=0, scale=std_dev) else: # 从中心为distance的正态分布采样 return np.random.normal(loc=distance, scale=std_dev) n_samples = 100000 distance = 0.7 weight = 0.5 samples = np.array([bimodal_sample(distance, weight) for _ in range(n_samples)]) # 可选:过滤极端小概率出现的超出范围值 samples = np.clip(samples, 0, 1)
说明
- 设定标准差为
(1-distance)/3:这样中心在0的分布,99.7%的样本会落在0 ± 3*std_dev = 0 ± (1-distance),即0到1-distance,不会小于0;中心在distance的分布,99.7%的样本会落在distance ± (1-distance),即2distance-1到1(当distance=0.7时,下限为0.4),刚好不会超出1。 - 函数更名:
bimodal_pdf改为bimodal_sample,因为该函数是生成样本而非计算概率密度,命名更准确。 - 可选的
np.clip:用于处理极端小概率出现的超出范围值,进一步确保样本落在[0,1]区间。
内容的提问来源于stack exchange,提问作者HJA24
相关产品推荐
相关产品推荐

