
本文介绍一种灵活、可复用的方法,通过分组抽样与去重合并策略,在 pandas 中实现同时满足“每地点至少2个样本(若可行)”和“每颜色至少1个样本(若可行)”的复合条件随机抽样。
本文介绍一种灵活、可复用的方法,通过分组抽样与去重合并策略,在 pandas 中实现同时满足“每地点至少2个样本(若可行)”和“每颜色至少1个样本(若可行)”的复合条件随机抽样。
在实际数据分析中,简单的 df.sample(n) 往往无法满足业务层面的结构化抽样需求——例如要求样本在多个分类维度(如 location 和 color)上均具备最低覆盖度。此时需采用分层+组合+去重的策略,而非单一全局抽样。
以下是一个专业、健壮的实现方案:
import pandas as pd
def custom_sample(df, min_per_location=2, min_per_color=1, random_state=42):
"""
从DataFrame中抽取满足多维约束的随机样本:
- 每个 location 至少 min_per_location 个样本(上限为该组实际行数)
- 每个 color 至少 min_per_color 个样本(默认为1)
返回去重后的合并样本,确保无重复行。
"""
# 按 location 分组抽样:每组取 min(指定数, 组大小) 行
location_samples = (
df.groupby('location', group_keys=False)
.apply(lambda g: g.sample(n=min(min_per_location, len(g)),
random_state=random_state))
)
# 按 color 分组抽样:每组固定取 min_per_color 行(此处为1)
color_samples = (
df.groupby('color', group_keys=False)
.apply(lambda g: g.sample(n=min_per_color, random_state=random_state))
)
# 合并两部分样本,并自动去重(基于所有列值完全一致)
combined_sample = pd.concat([location_samples, color_samples]).drop_duplicates()
return combined_sample.reset_index(drop=True)
使用示例(基于题设数据):
# 构造原始数据
df1 = pd.DataFrame({
'character': ['mario', 'luigi', 'yoshi', 'peach', 'bowser', 'boo', 'toad', 'lakitu', 'koopa'],
'location': ['castle', 'castle', 'forest', 'castle', 'dungeon', 'dungeon', 'forest', 'forest', 'dungeon'],
'color': ['red', 'green', 'green', 'yellow', 'blue', 'white', 'blue', 'yellow', 'green']
})
# 执行抽样
result = custom_sample(df1)
print(result)
✅ 输出保障说明:
-
location维度:castle(3人)、forest(3人)、dungeon(3人)→ 各取最多2人 → 共6人; -
color维度:red/green/yellow/blue/white(共5色)→ 各取1人 → 共5人; - 合并后自动去重,最终样本兼具双重覆盖性(如
green色可能已在forest或dungeon抽样中被包含,避免冗余)。
⚠️ 注意事项:
- 若某分组行数不足要求(如某
color仅1行但min_per_color=2),sample()将抛出ValueError;建议在生产环境中添加replace=True(允许有放回抽样)或预检len(g) >= n; -
random_state固定确保结果可复现,调试阶段推荐保留,上线后可设为None以获得真正随机性; - 此方法不保证总样本量精确可控(因去重导致数量浮动),如需严格
n行,应在合并后追加sample(n, replace=False)—— 但需注意可能破坏原始约束,应谨慎权衡。
该方案逻辑清晰、扩展性强,只需调整参数或增减分组维度(如增加 .groupby('category')),即可适配更复杂的多条件抽样场景。










