如何从数据表抽取两个100行样本,使age均值正态分布在25、height均值接近175
原始数据表
name height age personA 180 21 personB 190 37 personC 168 27 personD 182 56 ...
抽样实现方案
核心用加权随机抽样实现需求,基于二维高斯分布给每行计算权重,离age=25、height=175越近的样本权重越高,刚好满足目标值附近样本抽中概率最高的要求,同时不会强制必须选中目标值样本。
1. 权重计算逻辑
- 权重公式参考二维正态分布概率密度,可简化忽略两个维度的协方差,独立计算得分后相乘:
权重 = exp( - ( (age-25)^2/(2*σ_age²) + (height-175)^2/(2*σ_height²) ) ) - 其中
σ_age、σ_height是可调整的标准差参数:σ越小,对偏离目标值的惩罚越高,样本均值会越集中在目标值附近;σ越大,抽样结果越接近完全随机。可根据实际数据分布调整,常规参考值为σ_age=5、σ_height=8。
2. 抽样步骤
- 第一步:给全表所有行按上述公式计算每行权重
- 第二步:用加权无放回抽样抽取100行,得到第一个样本
- 第三步:如果允许两个样本有重复行,直接重新对全表加权抽取100行得到第二个样本;如果要求无重复,先删掉第一个样本的行,再从剩余数据里加权抽100行即可(要求原表总行数≥200)。
3. Python 实现代码
import pandas as pd import numpy as np # 读取原始数据表,可替换为自己的读取逻辑 df = pd.read_csv("original_table.csv") # 配置目标值和标准差参数 target_age = 25 target_height = 175 sigma_age = 5 sigma_height = 8 # 计算每行抽样权重 df["weight"] = np.exp( - ( (df["age"] - target_age)**2 / (2 * sigma_age**2) ) - ( (df["height"] - target_height)**2 / (2 * sigma_height**2) ) ) # 抽取第一个样本,random_state可自行修改保证结果可复现 sample1 = df.sample(n=100, replace=False, weights="weight", random_state=42) # 抽取第二个样本(允许重复的写法) sample2 = df.sample(n=100, replace=False, weights="weight", random_state=123) # 抽取第二个样本(不允许重复的写法) # sample2 = df.drop(sample1.index).sample(n=100, replace=False, weights="weight", random_state=123) # 校验样本均值 print("样本1 age均值:", sample1["age"].mean().round(2)) print("样本1 height均值:", sample1["height"].mean().round(2)) print("样本2 age均值:", sample2["age"].mean().round(2)) print("样本2 height均值:", sample2["height"].mean().round(2))
内容的提问来源于stack exchange,提问作者Shahin
相关产品推荐
相关产品推荐

