You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

二类不平衡数据集80-20拆分需求:确保稀有类同时存在于训练测试集

解决极端不平衡数据集的拆分问题(稀有类仅1个样本)

嘿,这个问题我之前也碰到过!当稀有类只有1个样本时,sklearn自带的train_test_split或者StratifiedShuffleSplit确实没法满足“同时出现在训练和测试集”的需求——毕竟它们只能把每个样本分配到其中一个集合里。不过咱们可以手动处理,轻松搞定这个问题,代码也很简单,完全适合Python新手~

核心思路

因为稀有类(label=0)只有1个样本,咱们需要让这个样本同时出现在训练集和测试集,然后从多数类(label=1)里按80-20的比例拆分出对应数量的样本,最后把两部分合并即可。这样既保证了稀有类在两个集合都存在,也满足了整体的拆分比例。

具体步骤(附代码)

假设你用pandas读取数据集(新手最常用的工具),咱们一步步来:

  1. 导入必要的库
import pandas as pd
from sklearn.model_selection import train_test_split
  1. 读取并拆分数据集
    先把数据分成稀有类和多数类两部分:
# 读取数据集(替换成你的数据文件路径)
df = pd.read_csv('your_dataset.csv')

# 分离稀有类(label=0)和多数类(label=1)
df_rarity = df[df['label'] == 0]  # 仅1个样本
df_majority = df[df['label'] == 1]  # 500个样本
  1. 拆分多数类为训练和测试集
    按80-20比例拆分多数类样本:
# test_size=0.2表示测试集占20%,random_state保证拆分结果可复现
train_majority, test_majority = train_test_split(
    df_majority,
    test_size=0.2,
    random_state=42
)
  1. 合并稀有类到训练和测试集
    把唯一的稀有类样本分别加到训练集和测试集里:
# 训练集 = 多数类训练样本 + 稀有类样本
train_set = pd.concat([train_majority, df_rarity], ignore_index=True)

# 测试集 = 多数类测试样本 + 稀有类样本
test_set = pd.concat([test_majority, df_rarity], ignore_index=True)
  1. 可选:打乱数据集顺序
    如果需要打乱训练集和测试集的顺序,可添加这一步:
train_set = train_set.sample(frac=1, random_state=42).reset_index(drop=True)
test_set = test_set.sample(frac=1, random_state=42).reset_index(drop=True)

验证结果

你可以检查两个集合的样本数和类别分布:

print(f"训练集总样本数:{len(train_set)},label=0的样本数:{len(train_set[train_set['label']==0])}")
print(f"测试集总样本数:{len(test_set)},label=0的样本数:{len(test_set[test_set['label']==0])}")

输出应该是:

训练集总样本数:401,label=0的样本数:1
测试集总样本数:101,label=0的样本数:1

总样本数501,训练集占比≈80.04%,测试集≈20.16%,完美符合80-20的要求,而且稀有类样本在两个集合都存在啦!

为什么之前的方法不行?

StratifiedShuffleSplit这类分层方法会按类别比例拆分样本,但当某个类别只有1个样本时,它只能把这个样本分配到训练集或测试集其中一个——毕竟一个样本不能同时出现在两个地方(除非咱们手动复制它~)。

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

火山引擎 最新活动