前言
最近参加一个比赛,拿到的数据集分为两部分,需要先进行划分,于是看看网上有没有代码可以借用,这样效率更高,但是发现,大部分代码都是bug满天飞,作者也不给出必要的说明,于是只能自己修改和重写。(不忍吐槽,那些复制别人代码的人,能不能自己跑通了再发布?)
正文
前排提示:我的方法不是一步到位那种,而是拆分为两部分:1) 先按照标签移动数据集。2) 按照比例划分出验证集(或测试集)。之所以这样做,是因为之前我参加过一个比赛,写了一个划分验证集的脚本,现在就直接用了。
拿到的数据集分为两部分:
- 一个名叫train的文件夹,里面包含了所有样本(.jpg格式的图片)
- 一个train.csv文件,记录了每张图片对应的标签
train文件夹:
train.csv:(记住红框里的这两个名字,后面要用)
目的:把train文件夹里的一万多张照片,按照0-5总共6个标签,移动到对应的文件夹里,最后效果如图:
例如标签为0的文件夹:
接下来看代码:
import os
import shutil
import pandas as pd
import random
#打开表格文件并读取
f=open("D:/game_data1/train.csv","rb") # 打开csv文件
list=pd.read_csv(f) # 这句不能少
#创建文件夹
for i in range(6): # "6"指的是0-5总共6个类别
if not os.path.exists('D:/game_data1/'+str(i)): # 最后一个 / 不要漏
os.mkdir('D:/game_data1/'+str(i))
#进行分类
for i in range(6):
listnew=list[list["CATEGORY_ID"]==i] # 对应csv文件图片那一栏的标题
l=listnew["FILE_ID"].tolist() # 对应csv文件标签那一栏的标题
j=str(i)
for each in l:
shutil.move('D:/game_data1/train/'+each, 'D:/game_data1/'+j)
print("完成")
接下来进行第二步:按照比例划分出验证集
path1 = 'D:/game_data1/train'
path2= 'D:/game_data1/valid'
valid_size=0.07
path_1_doc=os.listdir(path1)
path_1_doc_path=[path1+'/'+i for i in path_1_doc]
for doc in path_1_doc: # 新建空文件夹,使得和path1里的一样
if not os.path.exists(path2+'/'+doc):
os.mkdir(path2+'/'+doc)
path_2_doc=os.listdir(path2)
for k in range(len(path_1_doc)):
i = path1+'/'+path_1_doc[k]
image_list=os.listdir(i)
image_detailed=[i+'/'+j for j in image_list]
img_num=len(image_list)
random_index=random.sample(range(0,img_num-1), int(valid_size*img_num))
for i in random_index:
shutil.move(image_detailed[i], path2+'/'+path_1_doc[k])
print("移动完成")
有一个点要解释下:
对于划分数据集,目前用的最多的方案是:
- 训练集:验证集:测试集 = 8:0.5:1.5
- 训练集:验证集:测试集 = 7:1:2
但是针对这个比赛,我从数据集里划分7%作为验证集(实际上是测试集,如果要对超参数进行网格搜索,那么需要明确划分出验证集和测试集),是因为:在之前参加的另一个竞赛中,按照这样的比例划分,能够做到线上线下对最终测试结果的精度几乎保持一致。
换句话说,如果有可以用来比对的指标(比如能看到线上和线下的测试集精度),那么可以调整划分验证集的比例,使得两个指标在多次测试中都很接近。如果没有这样的指标,那么最好按照主流的划分标准来划分数据集。
另外,我之前还在知乎上看到一个观点:
对于较深的网络来说,参数量如果比较大,那么需要更多的训练样本拿去训练,如果训练样本较少的话,可能难以填充参数空间。
听起来挺有道理,但是我还没有找到相应的证明,如果有谁知道,还望告知!
注意:主要容易在path上出问题,比如多一个"/"。
最终效果: