如何在Pandas中按组等概率随机采样(非固定每组行数)
本文介绍一种灵活的pandas分组采样策略:不强制每组抽取相同行数,而是使每个分组被选中的总体概率近似相等,适用于组大小差异大、且需保持组间采样公平性的场景。
本文介绍一种灵活的pandas分组采样策略:不强制每组抽取相同行数,而是使每个分组被选中的总体概率近似相等,适用于组大小差异大、且需保持组间采样公平性的场景。
在实际数据分析中,我们常需对分组数据进行随机采样。但 df.groupby("ID").sample(n=k) 会严格要求每组恰好抽取 k 行,当各组样本量差异显著时,可能导致小组合被过度代表、大组合代表性不足——这违背了“组间采样概率均等”的初衷。
要实现每组被选中的概率大致相同(即:任意一行属于某组 ID,其最终被采中的概率 ≈ 1 / 组总数),推荐采用两阶段采样法:
-
第一阶段:按组均匀过采样
先对每个组独立采样 ⌈N / G⌉ 行(G 为唯一组数),允许重复(replace=True),确保各组提供足够候选; -
第二阶段:全局随机抽样
从所有候选行中无放回地随机抽取 N 行,使最终结果中各组出现频次趋于均衡。
import pandas as pd
import math
# 示例数据
df = pd.DataFrame({
'ID': ['a', 'a', 'b', 'c', 'c', 'c'],
'Value': [2, 4, 6, 8, 10, 12]
})
N = 4 # 目标总采样行数
G = df['ID'].nunique() # 组总数
# 两阶段等概率采样
result = (df.groupby('ID')
.sample(n=math.ceil(N / G), replace=True)
.sample(N, replace=False) # replace=False 更符合常规需求;若需支持 N > 总候选数,可设 replace=True
.reset_index(drop=True))
print(result)
✅ 关键优势:
Img.Upscaler
免费的AI图片放大工具
- 不依赖各组原始大小,小组合不会因样本少而被忽略;
- 随着 N 增大,各组在结果中的占比快速收敛至 1/G(如 N=100 时三组占比均接近 33%);
- 计算高效,仅两次 sample() 调用,无显式循环或自定义函数。
⚠️ 注意事项:
- 若 N 极小(如 N < G),math.ceil(N/G) 可能为 1,此时第一阶段采样量充足,第二阶段仍能保证随机性;
- 默认使用 replace=False 在第二阶段,避免单一样本被多次选取(除非业务明确需要);
- 如需复现结果,请在两步 sample() 中均设置 random_state(例如 .sample(..., random_state=42))。
该方法平衡了统计公平性与工程简洁性,是处理不平衡分组采样的实用范式。