首页 > 解决方案 > 如何正确地将一部分文件复制到新目录中?

问题描述

我正在开发一个功能,我应该将一定比例的文件从 SOURCE 目录复制到两个不同的目录中,一个是培训目录,一个是测试目录。函数看起来像这样

def copy_file(source, training, testing, split_size):

在哪里:

-source 是我要从中复制的源目录

-training 是要复制到的目录

-testing 是另一个要复制到的目录

-split_size 是我想要复制到测试和训练的源的百分比,以小数点表示(例如,如果 split_size 为 0.9,我将复制 90% 的源到训练,10% 到测试)

我的代码目前看起来像这样

def split_data(SOURCE, TRAINING, TESTING, SPLIT_SIZE):
    #get the source image names in a list
    source_images = os.listdir(SOURCE)
    splitVal_training = int(round(SPLIT_SIZE*len(source_images))) #get 1350 aka 90% of all the documents
    splitVal_testing = int(round((1 - SPLIT_SIZE)*len(source_images))) #get the remainder of the split_size, aka 10% of all images
    
    
    
    training_list = random.sample(source_images, splitVal_training) #create a new list with 1350 elements of the original list
    print(len(training_list))
    testing_list = [image for image in source_images if not image in training_list]
    print(len(testing_list))
    
    
    
    for image in training_list:
            copyfile(os.path.join(SOURCE,image),os.path.join(TRAINING,image))
        
    for image in testing_list:
            copyfile(os.path.join(SOURCE,image),os.path.join(TESTING,image))


CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"
TRAINING_CATS_DIR = "/tmp/cats-v-dogs/training/cats/"
TESTING_CATS_DIR = "/tmp/cats-v-dogs/testing/cats/"
DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"
TRAINING_DOGS_DIR = "/tmp/cats-v-dogs/training/dogs/"
TESTING_DOGS_DIR = "/tmp/cats-v-dogs/testing/dogs/"

split_size = .9
split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, TESTING_CATS_DIR, split_size)
split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, TESTING_DOGS_DIR, split_size)

当我运行它并获得我的训练和测试列表的长度时,我得到了正确的结果,分别为 1350 和 150。但是,当我在下一个代码单元中检查目录的长度时(我正在使用 Google Colab),我不断得到 1500 的训练目录和每个测试目录的随机数。为什么是这样?当我打印培训和测试列表的长度时,我得到的数字不应该与我得到的相同吗?

print(len(os.listdir('/tmp/cats-v-dogs/training/cats/')))
print(len(os.listdir('/tmp/cats-v-dogs/training/dogs/')))
print(len(os.listdir('/tmp/cats-v-dogs/testing/cats/')))
print(len(os.listdir('/tmp/cats-v-dogs/testing/dogs/')))

# Expected output:
# 1350
# 1350
# 150
# 150

#Actual output:
#1500
#1500
#1309
#1203

更新:今天我清除内核并再次运行后,我在第一次运行时得到了正确的输出。第二次和随后的运行再次给了我随机数。我第一次尝试运行的任何文件是否可以保留在文件夹中并添加到预期的输出中?

我无法解决的另一个问题是我应该检查每个文件的大小是否大于 0。为此,我尝试将 for 循环编辑为如下所示

for image in training_list: 
     if os.path.gets_size(image) > 0 :
         copyfile(os.path.join(SOURCE,image),os.path.join(TRAINING,image))

但是每次我运行它时都会收到一条错误消息,指出该文件不存在,这是检查文件大小的错误方法吗?

标签: pythonpython-3.xoperating-systemcopyshutil

解决方案


因为您没有保留在运行之间随机选择用于训练与测试的文件名,所以最终您将得到 1500 个训练文件和 1500 个测试文件。

由于您使用 .9 作为 split_size,因此测试将需要更长的时间。您的测试数据的明显随机大小是您1203的程序运行约 8 次的结果,其中一些来自int(round(SPLIT_SIZE)您正在使用的程序。

您可以通过在序列化结构中将初始拆分持久化为训练/测试或在添加任何内容之前检查 /training_location/ 和 /test_location/ 的内容来解决此问题。

一般来说,我会避免将os包用于这样的事情,而支持pathlib. Pathlib 将为您提供文件列表以及大小


推荐阅读