You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DataFrame随机抽样:需保证每组最小样本量且保留原分布

实现带分组最小样本要求的加权随机抽样(保留原数据分布)

我完全懂你的需求——既要做随机抽样,又得保证目标分组列的每个类别至少有1个样本,同时还要尽量贴合原数据里各分组的样本量占比(也就是保留原分布特征)。针对你给出的示例数据,咱们可以通过先给每个分组保底抽1个样本,再对剩余名额按原分布加权抽样的方式来完美实现。

先看你的示例数据

先把你的测试数据构造出来:

import pandas as pd

# 构造示例DataFrame
df = pd.DataFrame({'class': [0]*13 + [1, 2]})

这里class列里,0占了13个样本,1和2各1个,要抽4个样本的话,刚好每个组先拿1个,剩下1个名额给占比最高的0,就是你期望的结果。

分步实现抽样逻辑

1. 先抽取每个分组的保底样本

首先给每个class类别至少抽1个样本,确保每个分组都有代表:

# 每个分组抽取1个样本,random_state用于结果可复现,可按需调整
min_samples = df.groupby('class').sample(n=1, random_state=42)

2. 计算剩余需要抽取的样本数

total_target = 4  # 你想要的总抽样数量
remaining_quota = total_target - len(min_samples)

这里len(min_samples)是3(3个分组),所以还剩1个名额需要抽取。

3. 按原分布加权抽取剩余名额

接下来要从剩下的样本里,按照原数据的分组占比来抽,保证抽样结果的分布和原数据一致:

# 计算原数据各分组的样本占比,作为抽样权重
class_weights = df['class'].value_counts(normalize=True)

# 排除已经抽过的保底样本,得到剩余可抽样的数据集
remaining_data = df.drop(min_samples.index)

# 按权重抽取剩余名额,这里权重用原分布的占比,确保贴合原数据特征
additional_samples = remaining_data.sample(
    n=remaining_quota,
    weights=remaining_data['class'].map(class_weights),
    random_state=42
)

4. 合并结果并整理

把保底样本和额外抽取的样本合并,再排序整理一下:

df_sample = pd.concat([min_samples, additional_samples]).sort_values('class').reset_index(drop=True)

查看最终结果

打印df_sample就能得到你期望的输出:

print(df_sample)

输出:

class
0      0
1      0
2      1
3      2

通用适配说明

这个方法适用于任何满足总抽样数≥分组数量的场景:

  • 如果某个分组本身样本量只有1个(比如示例里的1和2),额外抽样时不会再选中它,因为没有剩余样本了,符合逻辑;
  • 如果总抽样数更大,比如要抽5个,那剩余2个名额都会给占比最高的0,完美保留原数据的分布特征。

内容的提问来源于stack exchange,提问作者s900n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 07:07:52