承接《Pandas 描述性统计》,本篇讲解 Pandas 样本抽样、分层抽样、随机打乱、随机数据生成、随机种子固定、有放回/无放回抽样,是建模、验证集划分、数据模拟常用功能,保持系列教程统一风格。
前置导入与示例数据
import pandas as pd
import numpy as np
df = pd.DataFrame({
"region": ["华东","华东","华南","华南","华北","华北","华东","华南","华北","华东"],
"cate": ["手机","电脑","手机","电脑","手机","电脑","手机","电脑","手机","电脑"],
"sales": [1200, 800, 1500, 950, 1100, 780, 1350, 1020, 960, 1420],
"profit": [180, 120, 220, 140, 160, 110, 195, 150, 132, 176]
})
print(df)
一、sample 基础抽样函数
df.sample() 是 Pandas 内置抽样方法,支持按数量、按比例抽样,控制是否放回。
df.sample(
n=None,
frac=None,
replace=False,
random_state=None,
axis=0,
weights=None,
ignore_index=False
)
n:抽样行数(整数)frac:抽样比例,0~1replace=False:无放回抽样;replace=True:有放回抽样(允许重复抽到同一行)random_state:随机种子,固定结果,复现实验ignore_index=True:抽样后重置索引
1. 指定行数抽样
# 随机抽取3行
sample_n = df.sample(n=3, random_state=42)
print(sample_n)
2. 按比例抽样
# 抽取30%的数据
sample_frac = df.sample(frac=0.3, random_state=42)
print(sample_frac)
3. 有放回抽样(可重复)
适合 bootstrap 自助抽样
sample_replace = df.sample(n=10, replace=True, random_state=42)
4. 打乱整张表(frac=1)
经常用来做数据集洗牌
df_shuffle = df.sample(frac=1, random_state=42, ignore_index=True)
二、权重抽样 weights
按权重概率抽样,权重越大,被抽到概率越高
# 权重列,sales越大,被抽到概率越高
sample_weight = df.sample(n=4, weights="sales", random_state=42)
print(sample_weight)
weights 也可以直接传入一维数组:
df.sample(n=3, weights=[0.1,0.1,0.2,0.2,0.05,0.05,0.1,0.1,0.05,0.05])
三、分层抽样(业务高频)
简单随机抽样容易导致小类别样本抽不到,分层抽样保证每个分组都抽到样本。
方案:groupby + sample
# 按region分层,每个地区抽2条
strat_sample = df.groupby("region", group_keys=False).apply(
lambda x: x.sample(n=2, random_state=42)
)
print(strat_sample)
按比例分层:每个分组抽取该组 50%
strat_frac = df.groupby("region", group_keys=False).apply(
lambda x: x.sample(frac=0.5, random_state=42)
)
注意:group_keys=False,避免生成多余的外层索引
四、划分训练集、测试集
简易划分(不推荐复杂建模,复杂场景用sklearn)
# 7:3划分
train = df.sample(frac=0.7, random_state=42)
test = df.drop(train.index)
print("训练集数量:", len(train))
print("测试集数量:", len(test))
分层划分版本(保证地区分布一致)
def strat_split(df, group_col, test_ratio=0.3):
test = df.groupby(group_col, group_keys=False).apply(
lambda x: x.sample(frac=test_ratio, random_state=42)
)
train = df.drop(test.index)
return train, test
train_df, test_df = strat_split(df, "region", 0.3)
五、np.random 配合 Pandas 生成随机数据
5.1 生成随机整数
df["rand_int"] = np.random.randint(100, 500, size=len(df))
5.2 0~1均匀随机数
df["rand_uniform"] = np.random.rand(len(df))
5.3 正态分布随机数
df["rand_norm"] = np.random.normal(loc=100, scale=10, size=len(df))
5.4 随机选择指定候选值
df["rand_promo"] = np.random.choice([0,1], size=len(df), p=[0.7,0.3])
p 是每个选项的概率之和必须=1
六、固定随机种子
如果不设置 random_state,每次运行抽样结果不一样。
两种固定方式:
# 方式1:sample内指定random_state(推荐,局部生效)
df.sample(n=3, random_state=42)
# 方式2:全局numpy种子(全局生效)
np.random.seed(42)
建议优先写在 sample 参数里,避免全局污染其他随机逻辑。
七、随机排序、随机取列
axis=1 对列抽样
# 随机挑选2列
col_sample = df.sample(n=2, axis=1)
print(col_sample)
八、抽样校验
抽样后检查分布是否和原数据接近
# 原分布
print(df["region"].value_counts(normalize=True))
# 抽样样本分布
print(sample_frac["region"].value_counts(normalize=True))
九、高频坑清单
- 样本量大于分组行数,无放回抽样直接报错,需要
replace=True - 分层抽样忘记
group_keys=False,结果多出一层索引 - 划分训练测试集只用简单sample,类别不平衡(小类别全部进训练集)
- 权重存在0、负数,weights 报错;权重会自动归一化,但不能为负
- 多次抽样不设置random_state,结果不可复现,调试困难
- frac=1 洗牌后索引不变,记得
ignore_index=True - np.random.seed 全局种子,和 sample 的 random_state 是两套独立随机器
十、综合实战模板
def simple_sample(df, n=None, frac=None, seed=42):
"""简单随机抽样"""
return df.sample(n=n, frac=frac, random_state=seed, ignore_index=True)
def stratified_sample(df, group_col, n_per_group=None, frac=None, seed=42):
"""分层抽样,每组固定数量或者固定比例"""
if n_per_group is not None:
fn = lambda x: x.sample(n=n_per_group, random_state=seed)
else:
fn = lambda x: x.sample(frac=frac, random_state=seed)
return df.groupby(group_col, group_keys=False).apply(fn)
# 调用
sample_strat = stratified_sample(df, group_col="region", n_per_group=2)
print(sample_strat)
十一、速查表
| 需求 | 写法 |
|---|---|
| 随机抽N行 | sample(n=5) |
| 抽取20%数据 | sample(frac=0.2) |
| 洗牌打乱整张表 | sample(frac=1, ignore_index=True) |
| 有放回自助抽样 | sample(replace=True) |
| 按字段概率加权抽样 | sample(weights=”col”) |
| 每个分组都抽到样本 | groupby + sample |
| 固定随机结果 | random_state=42 |
0 条笔记