使用Polars在Python中多次随机抽样结果重复的问题求助
问题分析与解决方案
一、抽样结果重复的原因及修复
你的代码里,repeat(pop_data_frame.sample(n=num_obs), samples)是先执行一次sample生成单个样本,再把这个样本重复1000次存入列表,所以所有样本完全相同。
修复方法
方法1:列表推导式生成独立样本
直接循环调用sample生成每个独立样本,无需指定种子时,Polars会自动使用不同的随机源:
sample_list = [pop_data_frame.sample(n=num_obs) for _ in range(samples)]
方法2:指定不同随机种子(可复现)
如果需要结果可复现,给每次抽样分配不同的种子:
sample_list = [] for idx in range(samples): # 用递增的种子保证样本不同且可复现 sample = pop_data_frame.sample(n=num_obs, seed=42 + idx) sample_list.append(sample)
二、正交多次随机抽样实现
正交抽样的核心是让样本间的抽样分布更均匀,避免重叠偏差,以下是三种实用实现方式:
1. 无重叠全覆盖正交抽样
当总体大小恰好等于样本数×单样本量(你的场景中1e6=1000×100刚好满足),可以先打乱总体,再分割成等份样本,每个单元恰好被抽一次:
# 随机打乱总体顺序 shuffled_pop = pop_data_frame.sample(n=N, shuffle=True) # 分割为1000个各含100条的样本 sample_list = [shuffled_pop.slice(i*num_obs, num_obs) for i in range(samples)]
2. 分层正交抽样(按特征平衡)
如果需要按分类特征(比如你的B列)平衡抽样,保证每个样本中各分层的比例一致,同时控制单元被抽中的次数:
# 按B列分层,每层分配50个样本量(对应单样本100条) stratum_size = num_obs // 2 # 初始化抽样计数,跟踪每个单元被抽次数 pop_with_counts = pop_data_frame.with_columns(pl.lit(0).alias("sample_count")) sample_list = [] for _ in range(samples): # 从B=0层抽取未被抽过的50条 stratum_0 = pop_with_counts.filter((pl.col("B") == 0) & (pl.col("sample_count") == 0)).sample(n=stratum_size) # 从B=1层抽取未被抽过的50条 stratum_1 = pop_with_counts.filter((pl.col("B") == 1) & (pl.col("sample_count") == 0)).sample(n=stratum_size) # 合并为当前样本 current_sample = pl.concat([stratum_0, stratum_1]) sample_list.append(current_sample) # 更新已抽样单元的计数 pop_with_counts = pop_with_counts.with_columns( pl.when(pl.col("id").is_in(current_sample["id"])).then(pl.col("sample_count") + 1).otherwise(pl.col("sample_count")) )
3. 允许重叠的平衡正交抽样
如果允许单元被多次抽取,希望每个单元被抽中的次数尽可能均匀,可以先重复总体再分割:
# 计算每个单元需要被抽取的次数(这里1000×100/1e6=1,刚好一次;若样本量调整可自动计算) repeat_times = (samples * num_obs) // N # 重复总体后打乱,再分割为样本 extended_pop = pop_data_frame.repeat(repeat_times).sample(n=repeat_times*N, shuffle=True) sample_list = [extended_pop.slice(i*num_obs, num_obs) for i in range(samples)]
内容的提问来源于stack exchange,提问作者Damon C. Roberts
相关产品推荐
相关产品推荐

