Introduction
最近在训练一个病灶区域的分类模型,代码用的是MedMNIST。先是把MRI图像中的病灶区域抠出来保存成图片,然后resize到28*28的大小,再制作成.npz格式的数据集送入模型中进行训练并分类。
按照5-folds-cross-validation 的方法,把数据集分成了5个部分,因为.npz格式的特殊性,label和image必须在ndarray中的索引值一一对应上,所以在选取val-sets时只得按照步长来选取图片作为验证集,每隔10step选取一张图片。
从最终实验结果来看,波动还是挺大的,所以决定对每次的训练结果进行求平均,然而操作繁琐,毕竟要保存1056的结果并且求平均,再进行分析,所以决定直接写两个for循环嵌套,自动完成10-times-5-folds交叉验证
,并用pandas进行数据分析和保存
Pandas中两种数据类型
Pandas中分为两种数据结构,Series和DataFrame,类似于Python中的list,dict之类
- Series 带标签的一维同构数组
- DataFrame 带标签的,大小可变的,二维异构表格
Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。
Series
带有轴标签的一维ndarray,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引,索引可以是字典中的key
import pandas as pd
s = pd.Series(['a',2,'c','www'])
In:s
Out:
0 a
1 2
2 c
3 www
dtype: object
Series中常用的两个属性:index和values,分别显示索引值和元素值
DataFrame
- 二维的表格型数据结构。
- 在DataFrame中行和列的表示不再是axis 0 和axis 1,而是index(行)和columns(列)
因为我在分类训练时,是用二维的嵌套字典生成了DataFrame,所以只介绍这种生成方式
import numpy as np
import pandas as pd
x = {'1': {'train_auc': 1.0, 'train_acc': 1.0, 'val_auc': 0.9987129987129987, 'val_acc': 0.98, 'test_auc': 0.9948529411764705, 'test_acc': 0.9568106312292359}, '2': {'train_auc': 1.0, 'train_acc': 1.0, 'val_auc': 0.9978549978549979, 'val_acc': 0.97, 'test_auc': 0.9434397163120568, 'test_acc': 0.7541528239202658}, '3': {'train_auc': 1.0, 'train_acc': 1.0, 'val_auc': 0.9995709995709996, 'val_acc': 0.99, 'test_auc': 0.9751622418879056, 'test_acc': 0.9501661129568106}, '4': {'train_auc': 1.0, 'train_acc': 1.0, 'val_auc': 0.9987129987129987, 'val_acc': 0.96, 'test_auc': 0.986545100469151, 'test_acc': 0.7574750830564784}, '5': {'train_auc': 1.0, 'train_acc': 1.0, 'val_auc': 0.9867009867009867, 'val_acc': 0.91, 'test_auc': 0.6762710244648318, 'test_acc': 0.6245847176079734}}
df = pd.DataFrame(x)
print(df)
-------------------------------out----------------------------------
1 2 3 4 5
test_acc 0.956811 0.754153 0.950166 0.757475 0.624585
test_auc 0.994853 0.943440 0.975162 0.986545 0.676271
train_acc 1.000000 1.000000 1.000000 1.000000 1.000000
train_auc 1.000000 1.000000 1.000000 1.000000 1.000000
val_acc 0.980000 0.970000 0.990000 0.960000 0.910000
val_auc 0.998713 0.997855 0.999571 0.998713 0.986701
如果把嵌套字典传给DataFrame,Pandas就会被解释为外层字典的键作为列,内层字典键则作为行索引
转置DataFrame
因为后续需要对表格中的数据求平均,而自带的方法.mean()
是对列即columns中的数据进行求平均的,所以需要先对表格进行转置,将index_label和columns_label进行互换,具体做法很简单,加一个.T
就ok了
df = df.T
print(df)
-------------------------------out----------------------------------
test_acc test_auc train_acc train_auc val_acc val_auc
1 0.956811 0.994853 1.0 1.0 0.98 0.998713
2 0.754153 0.943440 1.0 1.0 0.97 0.997855
3 0.950166 0.975162 1.0 1.0 0.99 0.999571
4 0.757475 0.986545 1.0 1.0 0.96 0.998713
5 0.624585 0.676271 1.0 1.0 0.91 0.986701
对各列中的数值进行求平均
转置之后就可以按列对数据进行求平均了,方法也很简单.mean()
即可,但是需要注意的是,.mean()
方法返回的数据类型是Series,不能直接添加到表格的最后一行,所以需要改变数据类型,类似于tensor和numpy互换,调用.to_frame()
就行了
df.mean()
-------------------------------out----------------------------------
test_acc 0.808638
test_auc 0.915254
train_acc 1.000000
train_auc 1.000000
val_acc 0.962000
val_auc 0.996311
dtype: float64
# 输出的是Series类型的数据,所以需要先对其转换
df_mean = df.mean().to_frame()
-------------------------------out----------------------------------
0
test_acc 0.808638
test_auc 0.915254
train_acc 1.000000
train_auc 1.000000
val_acc 0.962000
val_auc 0.996311
# 然而这个输出还需要进行一次转置才能和df相匹配
对df和df_mean进行拼接
df_mean = df_mean.T
df = pd.concat([df,df_mean]) # 注意要先把待拼接的参数加个[]
-------------------------------out----------------------------------
test_acc test_auc train_acc train_auc val_acc val_auc
1 0.956811 0.994853 1.0 1.0 0.980 0.998713
2 0.754153 0.943440 1.0 1.0 0.970 0.997855
3 0.950166 0.975162 1.0 1.0 0.990 0.999571
4 0.757475 0.986545 1.0 1.0 0.960 0.998713
5 0.624585 0.676271 1.0 1.0 0.910 0.986701
0 0.808638 0.915254 1.0 1.0 0.962 0.996311
改index名并且写入csv中
rename方法可以更改index和columns的名称,且不改变数据。用法类似于更改字典中的键值
df.to_csv
- 第一个参数是保存的文件名,没有指定路径的话,保存目录为默认目录,即os.getcwd()下的目录,可以使用绝对路径指定其保存目录和文件名
- sep是隔开每个数据的符号,这里用的空格隔开
- mode是写入模式,因为要持续对csv进行写操作,且不能破坏上次写入的数据,用mode=‘a’可以跟在上次写入后面继续写。default为’w’
df = df.rename(index = {0:'mean'})
df.to_csv('results.csv', sep=' ', mode='a') # 写入csv中