Python中如何以Data Frame原始值为均值按20%标准差做正态分布随机化仿真
逐单元格绑定原值为正态分布均值的仿真实现方案
之前两种实现的问题根源
- 直接调用
np.random.normal(avg, std_dev, num_reps)时,传入的均值是固定全局值,没有把DataFrame每个单元格自身的x值作为对应位置的分布均值,生成的随机数和原表单元格位置没有绑定关系 - 采用
df.applymap(np.random.normal(avg, std_dev, num_reps))做逐单元格映射时,相当于提前把np.random.normal的均值、标准差、输出尺寸参数全部写死,applymap逐单元格传入的当前值x反而没有被作为正态分布的均值参数,所有位置的随机数都基于固定参数生成,完全丢失了原表单元格值的绑定关系
可完全匹配需求的实现方法
逐单元格直观版本(适合小表快速验证逻辑)
该版本逻辑和需求一一对应,无需额外理解NumPy广播规则即可快速上手:
- 规则对齐:每个单元格生成的随机数满足正态分布,均值为单元格原始值x,标准差为x的20%,即
scale = 0.2 * x - 定义逐单元格的映射函数:
import pandas as pd import numpy as np def gen_random_from_cell(x): # x为当前单元格读取到的原始值 return np.random.normal(loc=x, scale=0.2 * x) - 单次生成1份仿真用随机DataFrame,仅需执行一次映射:
# base_df为用户提供的原始基础DataFrame random_df = base_df.applymap(gen_random_from_cell) - 10000次重复仿真仅需循环调用上述生成逻辑,每次取出新生成的
random_df开展后续计算即可。
向量化高性能版本(适合大尺寸表+10000次重复仿真的场景)
逐单元格apply的方式在表尺寸较大、重复仿真次数较多时运行效率极低,可直接利用NumPy的数组广播能力实现,运行速度可提升2~3个数量级:
- 提取原表的数值矩阵:
# 仅选取数值型列,避免文本列触发计算错误 base_values = base_df.select_dtypes(include='number').values - 单次生成随机数据集的核心逻辑——NumPy的
np.random.normal本身支持传入数组作为均值和标准差参数,无需循环逐单元格计算:# 生成和原表数值同尺寸的随机数组,每个位置的均值为原位置的x值,标准差为0.2*x random_values = np.random.normal(loc=base_values, scale=0.2 * base_values) # 转回和原表索引、列名一致的DataFrame random_df = pd.DataFrame(random_values, index=base_df.index, columns=base_df.columns) - 批量生成10000次仿真的全部数据集,可进一步省去循环开销:
# 一次性生成全部仿真样本,输出维度为[仿真总次数, 原表行数, 原表列数] all_sim_samples = np.random.normal( loc=base_values, scale=0.2 * base_values, size=(10000, *base_values.shape) ) # 后续每次仿真仅需取出对应维度的数组,转成DataFrame即可开展计算
注意事项:
- 如果原DataFrame包含非数值类型的列(比如文本标签、分类字段),生成随机数时仅选取数值列计算即可
- 如果原DataFrame里存在值为0的单元格,0值对应20%标准差的随机数生成结果永远是0,不会触发计算错误
- 如果存在负值单元格,需要提前确认是否允许负向波动的标准差,避免生成偏离业务规则的数值
内容的提问来源于stack exchange,提问作者Jahanvi
相关产品推荐
相关产品推荐

