如何从非均匀分布数据集抽取匹配目标分布的样本?
从非均匀分布数据集抽取匹配目标分布的样本问题
我们需要从数据集ds2中抽取样本,使样本的「mass」变量分布与数据集ds1的「mass」分布完全一致。当ds2的「mass」为均匀分布时,使用ds1的KDE作为权重(通过Pandas的ds2.sample(...,weights=ds1_kde))进行采样,能成功匹配目标分布;但当ds2的「mass」呈非均匀分布时,采样得到的样本会保留ds2的偏斜特性,无法匹配ds1的分布。
成功场景:ds2为均匀分布
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import numpy as np from scipy import stats # 数据集1(目标分布) ds1 = pd.DataFrame({'mass':[0,1,1,2,2,2,2,3,3,3,4,4,5,6,7,7,8,8,8,8,9,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,12,13,14,15]}) # 计算ds1的KDE ds1_kde = stats.gaussian_kde(ds1.mass.to_list()) ds1_kde.set_bandwidth(bw_method=0.2) # 均匀分布的数据集2 ds2 = pd.DataFrame({'mass':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]}) ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0]) # 按ds1的KDE权重采样 smpl = ds2.sample(200, weights='ds1_kde', replace=True) # 计算样本的KDE smpl_kde = stats.gaussian_kde(smpl.mass.to_list()) smpl_kde.set_bandwidth(bw_method=0.2) # 绘图对比分布 bins = np.linspace(0, 16, 15) fig = plt.figure() xs = np.linspace(0,15,100) sns.histplot(ds2.mass.to_list(), stat='density', bins=bins, color='blue', label='ds2', alpha=0.5) sns.histplot(ds1.mass.to_list(), stat='density', bins=bins, color='orange', label='ds1(目标分布)', alpha=0.5) sns.histplot(smpl.mass.to_list(), stat='density', bins=bins, color='green', label='从ds2抽取的样本', alpha=0.5) sns.lineplot(x=xs, y=ds1_kde(xs), color='orange', label='ds1_kde') sns.lineplot(x=xs, y=smpl_kde(xs), color='green', label='样本_kde') plt.xlabel("mass") plt.title("ds2为均匀分布时采样成功") plt.legend() plt.show()
结果说明:
从ds2抽取的样本「mass」分布与ds1的目标分布高度吻合,样本KDE曲线与ds1的KDE曲线几乎重合。
失败场景:ds2为非均匀分布
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import numpy as np from scipy import stats # 数据集1(目标分布) ds1 = pd.DataFrame({'mass':[0,1,1,2,2,2,2,3,3,3,4,4,5,6,7,7,8,8,8,8,9,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,12,13,14,15]}) # 计算ds1的KDE ds1_kde = stats.gaussian_kde(ds1.mass.to_list()) ds1_kde.set_bandwidth(bw_method=0.2) # 非均匀分布的数据集2(mass偏向左端) ds2 = pd.DataFrame({'mass':[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,4,4,5,6,7,8,9,10,11,12,13,14,15]}) # 添加ds1的KDE作为采样权重 ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0]) smpl = ds2.sample(200, weights='ds1_kde', replace=True) # 计算样本的KDE smpl_kde = stats.gaussian_kde(smpl.mass.to_list()) smpl_kde.set_bandwidth(bw_method=0.2) # 绘图对比分布 bins = np.linspace(0, 16, 15) fig = plt.figure() xs = np.linspace(0,15,100) sns.histplot(ds2.mass.to_list(), stat='density', bins=bins, color='blue', label='ds2', alpha=0.5) sns.histplot(ds1.mass.to_list(), stat='density', bins=bins, color='orange', label='ds1(目标分布)', alpha=0.5) sns.histplot(smpl.mass.to_list(), stat='density', bins=bins, color='green', label='从ds2抽取的样本', alpha=0.5) sns.lineplot(x=xs, y=ds1_kde(xs), color='orange', label='ds1_kde') sns.lineplot(x=xs, y=smpl_kde(xs), color='green', label='样本_kde') plt.xlabel("mass") plt.title("ds2为偏斜分布时采样失败") plt.legend() plt.show()
结果说明:
样本的「mass」分布保留了ds2的左偏特性,无法匹配ds1的目标分布,样本KDE曲线与ds1的KDE曲线存在明显偏差。
问题本质
这是从总体中抽取子样本时,控制变量分布以匹配目标子总体分布场景的简化版本。
内容的提问来源于Stack Exchange,提问作者Kacper
相关产品推荐
相关产品推荐

