如何用Python生成与自定义分布数据集同分布的随机数值生成器?
自定义分布随机数生成的Python实现方案
完全可以通过Python的开源统计/数值库实现你的需求,以下是几种实用且贴合你需求的方案:
1. 基于核密度估计(KDE)的采样(匹配你的KDE图需求)
使用scipy.stats.gaussian_kde拟合原数据的核密度分布,生成的样本会和你图中的KDE曲线分布高度一致,同时可以限制采样结果在原数据的最小值和最大值范围内。
import numpy as np from scipy.stats import gaussian_kde def custom_dist_generator(data): # 拟合原数据的KDE模型 kde = gaussian_kde(data) data_min, data_max = data.min(), data.max() def generate(): while True: # 生成样本并过滤超出值域的部分 sample = kde.resample(1)[0][0] if data_min <= sample <= data_max: yield sample return generate # 使用示例 original_data = np.array([1.2, 3.5, 2.1, 4.8, 2.9, ...]) # 替换为你的原始数据 gen = custom_dist_generator(original_data) print(next(gen)) # 生成一个符合分布的随机数
2. 基于经验分布的采样(简单直接)
如果不需要严格拟合KDE,而是完全基于原数据的经验分布特征,可以通过分位数插值生成连续的随机样本,同样保证值域与原数据一致。
import numpy as np def empirical_dist_generator(data): data_sorted = np.sort(data) data_min, data_max = data_sorted[0], data_sorted[-1] n = len(data_sorted) def generate(): while True: # 生成0-1之间的均匀随机数,映射到经验分布的分位数 u = np.random.uniform(0, 1) idx = u * n lower_idx = int(np.floor(idx)) upper_idx = min(int(np.ceil(idx)), n-1) # 线性插值得到连续浮点样本 if lower_idx == upper_idx: sample = data_sorted[lower_idx] else: t = idx - lower_idx sample = (1 - t) * data_sorted[lower_idx] + t * data_sorted[upper_idx] # 确保样本在值域范围内 yield np.clip(sample, data_min, data_max) return generate
3. 自定义连续分布类(灵活扩展)
通过继承scipy.stats.rv_continuous,可以将原数据的经验分布封装为标准的统计分布类,支持采样、CDF、PPF等多种操作,同时严格限制值域。
from scipy.stats import rv_continuous import numpy as np class CustomEmpiricalDistribution(rv_continuous): def __init__(self, data, *args, **kwargs): super().__init__(a=data.min(), b=data.max(), *args, **kwargs) self.data_sorted = np.sort(data) self.n = len(self.data_sorted) def _cdf(self, x): # 实现经验累积分布函数 if x < self.a: return 0.0 if x >= self.b: return 1.0 return np.searchsorted(self.data_sorted, x, side='right') / self.n def _ppf(self, q): # 实现分位数函数,用于采样 if q <= 0: return self.a if q >= 1: return self.b idx = q * self.n lower_idx = int(np.floor(idx)) upper_idx = min(int(np.ceil(idx)), self.n-1) if lower_idx == upper_idx: return self.data_sorted[lower_idx] t = idx - lower_idx return (1 - t) * self.data_sorted[lower_idx] + t * self.data_sorted[upper_idx] def custom_dist_generator(data): dist = CustomEmpiricalDistribution(data) def generate(): while True: yield dist.rvs() return generate
内容的提问来源于stack exchange,提问作者Fabre Lambeau
相关产品推荐
相关产品推荐

