Python 如何从train、test和validation文件夹中的多个文件夹中拆分和复制文件

Python 如何从train、test和validation文件夹中的多个文件夹中拆分和复制文件,python,random,shutil,Python,Random,Shutil,我有一个数据集,由130个文件夹组成,每个文件夹包含32张照片 从每个文件夹中,我想将这些照片(26张用于培训,3张用于测试,3张用于验证)随机复制到train,validation and test文件夹中相应的子文件夹(001,002,003…)中。 所以我会有这样的东西: 列车组 001(文件夹包含26张照片) 002 003 验证集 001(文件夹包含3张照片) 002 003 列车组 001(文件夹包含3张照片) 002 003 代码如下: import rand

我有一个数据集,由130个文件夹组成,每个文件夹包含32张照片

从每个文件夹中,我想将这些照片(26张用于培训,3张用于测试,3张用于验证)随机复制到train,validation and test文件夹中相应的子文件夹(001,002,003…)中。 所以我会有这样的东西:

  • 列车组

    • 001(文件夹包含26张照片)
    • 002
    • 003
  • 验证集

    • 001(文件夹包含3张照片)
    • 002
    • 003
  • 列车组

    • 001(文件夹包含3张照片)
    • 002
    • 003
代码如下:

import random
import shutil

n_photo_train = 26
n_photo_validation = 3
n_photo_test = 3

for idx in range(130):

    source = '/Users/john/photodb_original/{d:03d}'.format(d=(idx + 1))
    dest_train = '/Users/john/photodb_sets/Train/{d:03d}'.format(d=(idx + 1))
    dest_validation = '/Users/john/photodb_sets/Validation/{d:03d}'.format(d=(idx + 1))
    dest_test = '/Users/john/photodb_sets/Test/{d:03d}'.format(d=(idx + 1))

    files = random.choice(os.listdir(source))
    photo_train = files[:n_photo_train]
    photo_test = files[26:29]
    photo_val = files[29:]

    shutil.copyfile(os.path.join(source, photo_train), dest_train)
    shutil.copyfile(os.path.join(source, photo_val), dest_validation)
    shutil.copyfile(os.path.join(source, photo_test), dest_test)
我得到这个错误:
isDirectoryError:[Errno 21]是一个目录:'/Users/john/photodb_original/001/'

我是否错误地使用了shutil.copyfile?否则,有没有一种方法可以更紧凑、更清晰地编写代码?

random.choice(os.listdir(source))
将只返回一个-当您尝试索引此字符串时,您将得到一个空字符串,
os.path.join
将返回目录路径-这将导致异常

从您的代码来看,您的目标似乎是使用。请注意,如果您使用的是shuffle,它会改变列表,因此您的代码应该拆分为两个命令:

files = os.listdir(source)
random.shuffle(files)
random.choice(os.listdir(source))
将只返回一个-当您尝试索引此字符串时,您将得到一个空字符串,
os.path.join
将返回目录路径-这将导致您的异常

从您的代码来看,您的目标似乎是使用。请注意,如果您使用的是shuffle,它会改变列表,因此您的代码应该拆分为两个命令:

files = os.listdir(source)
random.shuffle(files)

我认为您需要创建目录来复制其中的文件,或者当您遇到关于缺少目录的异常时,请尝试先创建目录,然后再次尝试复制文件。无论如何,这里有一个示例代码,我认为它符合您的要求

import os
from random import shuffle
from shutil import copyfile, rmtree

org = os.path.realpath('org')
trn = os.path.realpath('trn')
tst = os.path.realpath('tst')
val = os.path.realpath('val')
# How split will be performed 26 3 3
rnd = [trn]*26+[tst]*3+[val]*3

rmtree(trn)
rmtree(tst)
rmtree(val)
rmtree(org)

# CREATE DUMMY DATA
for i in range(1, 131):
    d = os.path.join(org, "{:03d}".format(i))
    os.makedirs(d, exist_ok=True)
    for f in range(1, 33):
        f = os.path.join(d, "{:02d}".format(f))
        open(f, 'a').close()

# ACTUAL STUFF
for d in os.listdir(org):
    os.makedirs(os.path.join(trn, d))
    os.makedirs(os.path.join(tst, d))
    os.makedirs(os.path.join(val, d))
    files = os.listdir(os.path.join(org,d))
    shuffle(rnd)
    for f, trg in zip(os.listdir(os.path.join(org,d)),rnd):
        scr = os.path.join(org,d,f)
        dst = os.path.join(trg,d,f)
        copyfile(scr,dst)

我认为您需要创建目录来复制其中的文件,或者当您遇到关于缺少目录的异常时,请尝试先创建目录,然后再次尝试复制文件。无论如何,这里有一个示例代码,我认为它符合您的要求

import os
from random import shuffle
from shutil import copyfile, rmtree

org = os.path.realpath('org')
trn = os.path.realpath('trn')
tst = os.path.realpath('tst')
val = os.path.realpath('val')
# How split will be performed 26 3 3
rnd = [trn]*26+[tst]*3+[val]*3

rmtree(trn)
rmtree(tst)
rmtree(val)
rmtree(org)

# CREATE DUMMY DATA
for i in range(1, 131):
    d = os.path.join(org, "{:03d}".format(i))
    os.makedirs(d, exist_ok=True)
    for f in range(1, 33):
        f = os.path.join(d, "{:02d}".format(f))
        open(f, 'a').close()

# ACTUAL STUFF
for d in os.listdir(org):
    os.makedirs(os.path.join(trn, d))
    os.makedirs(os.path.join(tst, d))
    os.makedirs(os.path.join(val, d))
    files = os.listdir(os.path.join(org,d))
    shuffle(rnd)
    for f, trg in zip(os.listdir(os.path.join(org,d)),rnd):
        scr = os.path.join(org,d,f)
        dst = os.path.join(trg,d,f)
        copyfile(scr,dst)

谢谢现在我有另一个问题。我在运行shutil.copyfile(os.path.join(source,photo\u train,dest\u train)时得到了这个错误
TypeError:join()参数必须是str或bytes,而不是'list'
,那么,使用的index slice命令:
files[:n\u photo\u train]
将返回一个iterable。而copyfile只接受一个文件,您可能希望使用以下理解来迭代和复制该文件:
[sutil.copyfile(file,dest\u train)for file in os.path.join(source,photo\u train)]
谢谢。现在我有另一个问题。我在运行shutil.copyfile(os.path.join(source,photo\u train,dest\u train)时得到了这个错误
TypeError:join()参数必须是str或bytes,而不是'list'
,那么,使用的index slice命令:
files[:n\u photo\u train]
将返回一个iterable。而copyfile只接受一个文件,您可能希望使用以下理解来迭代和复制该文件:
[sutil.copyfile(file,dest\u train)for file in os.path.join(source,photo\u train)]
谢谢!我忘了发布那部分代码,但我已经创建了文件夹001002。在“培训、测试和验证”文件夹中。我不明白你在“#如何执行拆分”部分做了什么。它创建目标目录路径的列表。基本上26项用于培训,3项用于测试,3项用于验证。在循环每个包含32张图片的目录时,您可以洗牌列表,以确定项目是否属于测试、验证和培训集。谢谢!我忘了发布那部分代码,但我已经创建了文件夹001002。在“培训、测试和验证”文件夹中。我不明白你在“#如何执行拆分”一节中做了什么。它创建了一个目标目录路径列表。基本上26个项目用于培训,3个项目用于测试,3个项目用于验证。在循环每个包含32张图片的目录时,你洗牌列表以确定项目属于测试、验证和培训集。