shutil.copy未复制全部预期文件且无报错,Kaggle数据集拆分异常
问题排查与解决方案
核心问题1:有放回抽样导致文件重复覆盖
你的代码中使用np.random.choice(examples_path, len(examples_path))进行打乱时,默认是有放回抽样(replace=True),这会导致examples_path中出现重复的文件名。当复制这些重复文件时,后续的文件会覆盖之前的同名文件,最终训练文件夹中的实际文件数远少于打印的数量,且每次运行重复情况不同,导致数量波动。
核心问题2:数据集切片索引错误
你在划分验证集时使用了examples_path[n_train_examples:(n_train_examples+n_val_examples+1)],多了一个+1,这会导致验证集实际数量比预期的n_val_examples多1,测试集数量少1,虽然打印的数值看起来匹配,但实际比例不符合你设置的val_split和test_split。
修正步骤
- 改用无放回打乱方式:使用
np.random.shuffle原地打乱数组(无重复),或显式设置np.random.choice的replace=False参数。 - 修正切片索引:移除验证集切片中的
+1,确保划分比例准确。 - 确保模块导入完整:确认导入了
shutil的copy和rmtree方法,避免隐式依赖问题。
修正后的完整代码
import os import numpy as np from shutil import copy, rmtree def shuffle_split_data(source_path, dest_path, train_split, val_split, test_split, clear_existing_destination=True): # 清空目标目录(如果需要) if clear_existing_destination: for item in os.listdir(dest_path): item_path = os.path.join(dest_path, item) if os.path.isfile(item_path): os.remove(item_path) elif os.path.isdir(item_path): rmtree(item_path) for label in os.listdir(source_path): # 创建目标子目录 train_path = os.path.join(dest_path, "training", label) val_path = os.path.join(dest_path, "validation", label) test_path = os.path.join(dest_path, "test", label) os.makedirs(train_path, exist_ok=True) os.makedirs(val_path, exist_ok=True) os.makedirs(test_path, exist_ok=True) # 获取当前类别的所有文件并打乱(无重复) label_source_path = os.path.join(source_path, label) examples_path = os.listdir(label_source_path) np.random.shuffle(examples_path) # 原地打乱,无重复文件 total_examples = len(examples_path) # 计算各集数量 n_train_examples = int(train_split * total_examples) n_val_examples = int(val_split * total_examples) # 划分数据集(修正切片索引) train_examples = examples_path[:n_train_examples] val_examples = examples_path[n_train_examples : n_train_examples + n_val_examples] test_examples = examples_path[n_train_examples + n_val_examples : ] print(len(train_examples), len(val_examples), len(test_examples)) # 复制训练集(原文件名,无重复) for file in train_examples: source = os.path.join(label_source_path, file) dest = os.path.join(train_path, file) copy(source, dest) # 复制验证集 for file in val_examples: source = os.path.join(label_source_path, file) dest = os.path.join(val_path, file[:-4] + "_" + label + ".jpg") copy(source, dest) # 复制测试集 for file in test_examples: source = os.path.join(label_source_path, file) dest = os.path.join(test_path, file[:-4] + "_" + label + ".jpg") copy(source, dest) # 调用函数(确保train_split+val_split+test_split≈1) shuffle_split_data( '/kaggle/input/monkeypox-skin-lesion-dataset/Original Images/Original Images', '/kaggle/working/', train_split=0.79, val_split=0.10, test_split=0.11, clear_existing_destination=True )
验证效果
修正后再次运行函数,打印的训练集数量会和os.listdir统计的数量完全一致,且每次运行数值稳定,不会再出现波动。
内容的提问来源于stack exchange,提问作者alestarbucks
相关产品推荐
相关产品推荐

