为不平衡数据集生成平衡批次

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本项目中,你将学习如何实现一个不平衡数据管道,该管道能够处理不平衡数据集并生成具有近似平衡类分布的批次数据。这是机器学习中的一项常见任务,在该任务中,数据集中某个类别的样本可能比其他类别多得多,这可能导致模型训练出现偏差并降低性能。

🎯 任务

在本项目中,你将学习:

  • 如何实现上采样和下采样功能,以平衡批次内的样本分布。
  • 如何输出一批样本数量等于批次大小的样本,其中批次内标签的分布尽可能均匀。
  • 如何测试不平衡数据管道,以确保其按预期工作。

🏆 成果

完成本项目后,你将能够:

  • 处理机器学习中的不平衡数据集。
  • 应用上采样和下采样技术来平衡类分布。
  • 实现一个能够从不平衡数据集中生成平衡批次的数据管道。

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/DataStructuresGroup(["Data Structures"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/PythonStandardLibraryGroup(["Python Standard Library"]) python/ControlFlowGroup -.-> python/for_loops("For Loops") python/DataStructuresGroup -.-> python/lists("Lists") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/PythonStandardLibraryGroup -.-> python/data_collections("Data Collections") subgraph Lab Skills python/for_loops -.-> lab-373136{{"为不平衡数据集生成平衡批次"}} python/lists -.-> lab-373136{{"为不平衡数据集生成平衡批次"}} python/function_definition -.-> lab-373136{{"为不平衡数据集生成平衡批次"}} python/data_collections -.-> lab-373136{{"为不平衡数据集生成平衡批次"}} end

实现上采样和下采样

在这一步中,你将学习如何实现上采样和下采样功能,以平衡批次内的样本分布。

打开位于 /home/labex/project 目录下的 unbalanced_data_pipeline.py 文件。

unbalanced_data_pipeline 函数中,首先创建一个名为 counterdefaultdict,用于存储特征向量及其对应的独热标签向量。

    counter = defaultdict(list)
    for x, y in data:
        counter[tuple(y)].append(x)

这将按标签向量对数据进行分组,便于执行上采样和下采样。

接下来,计算每个标签在每个批次中要包含的样本数量。这可以通过将批次大小除以唯一标签的数量,然后将余数存储在 num_left 变量中来完成。

    batch_data = []
    pre_num = batch_size // len(counter.keys())
    num_left = batch_size % len(counter.keys())

现在,遍历 counter 字典,为每个标签随机采样所需数量的样本。将这些样本添加到 batch_data 列表中。

    for y, x in counter.items():
        samples = random.sample(x, pre_num)
        batch_data.extend([[sample, list(y)] for sample in samples])

最后,通过从相应列表中随机选择一个标签和一个样本,并将其添加到 batch_data 列表中来处理剩余的样本。

    for _ in range(num_left):
        y = random.choice(list(counter.keys()))
        x = random.choice(counter[y])
        batch_data.append([x, list(y)])

返回 batch_data 列表。

    return batch_data

在这一步中,你已经实现了上采样和下采样功能,以平衡批次内的样本分布。unbalanced_data_pipeline 函数现在接受输入数据和批次大小,并返回一个具有近似平衡类分布的批次列表。

✨ 查看解决方案并练习

测试不平衡数据管道

在这一步中,你将测试 unbalanced_data_pipeline 函数,以确保它按预期工作。

unbalanced_data_pipeline.py 文件中添加以下代码。

if __name__ == "__main__":
    data = [
        [[1, 2, 5], [1, 0]],
        [[1, 6, 0], [1, 0]],
        [[4, 1, 8], [1, 0]],
        [[7, 0, 4], [0, 1]],
        [[5, 9, 4], [0, 1]],
        [[2, 0, 1], [0, 1]],
        [[1, 9, 3], [0, 1]],
        [[5, 5, 5], [0, 1]],
        [[8, 4, 0], [0, 1]],
        [[9, 6, 3], [0, 1]],
        [[7, 7, 0], [0, 1]],
        [[0, 3, 4], [0, 1]],
     ]
    for epoch in range(10):
        batch_data = unbalanced_data_pipeline(data, 6)
        batch_data = list(batch_data)
        print(f"{epoch=}, {batch_data=}")

if __name__ == "__main__": 代码块中,我们使用示例数据和批次大小 6 调用 unbalanced_data_pipeline 函数。

运行 unbalanced_data_pipeline.py 文件以查看输出。

python unbalanced_data_pipeline.py

输出应与原始挑战中提供的示例类似:

epoch=0, batch_data=[[[1, 2, 5], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[2, 0, 1], [0, 1]], [[7, 0, 4], [0, 1]], [[5, 9, 4], [0, 1]]]
epoch=1, batch_data=[[[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[2, 0, 1], [0, 1]], [[9, 6, 3], [0, 1]], [[1, 9, 3], [0, 1]]]
epoch=2, batch_data=[[[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[5, 5, 5], [0, 1]], [[7, 0, 4], [0, 1]], [[8, 4, 0], [0, 1]]]
epoch=3, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[7, 7, 0], [0, 1]], [[8, 4, 0], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=4, batch_data=[[[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[1, 2, 5], [1, 0]], [[5, 5, 5], [0, 1]], [[0, 3, 4], [0, 1]], [[8, 4, 0], [0, 1]]]
epoch=5, batch_data=[[[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[2, 0, 1], [0, 1]], [[7, 0, 4], [0, 1]], [[7, 7, 0], [0, 1]]]
epoch=6, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[8, 4, 0], [0, 1]], [[5, 9, 4], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=7, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[2, 0, 1], [0, 1]], [[0, 3, 4], [0, 1]], [[1, 9, 3], [0, 1]]]
epoch=8, batch_data=[[[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[7, 7, 0], [0, 1]], [[2, 0, 1], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=9, batch_data=[[[1, 2, 5], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[7, 0, 4], [0, 1]], [[0, 3, 4], [0, 1]], [[5, 5, 5], [0, 1]]]

在这一步中,你已经测试了 unbalanced_data_pipeline 函数,以确保它按预期工作。该函数现在应该能够处理不平衡数据并返回具有近似平衡类分布的数据批次。

✨ 查看解决方案并练习

总结

恭喜你!你已经完成了这个项目。你可以在 LabEx 中练习更多实验来提升你的技能。