赞
踩
想要将拿到的数据做切片处理,但是每训练一次网络就需要切一次,这样的效率太低了,然后就想着先把切片后的数据存储起来,然后训练网络的时候直接调用就可以。学习了一下python的pkl文件的读写,记录下来,方便以后查阅。
pkl格式的文件是python用于保存文件用的。
pkl文件是python里面保存文件的一种格式,如果直接打开会显示一堆序列化的东西(二进制文件)。需要使用rb类型来打开。
pickle模块是Python专用的持久化模块,所谓的持久化就是让数据持久化保存,可以持久化包括自定义类在内的各种数据,比较适合Python本身复杂数据的存储。
但是持久化后的字符串是只能用于Python环境,不能用作与其他语言进行数据交换。pickle的本意是腌渍的意思,就是将物品永久地保存成文件,用的时候读出来还能用。
pickle模块的作用是把Python对象直接保存到文件里,而不需要先把它们转化为字符串再保存,也不需要用底层的文件访问操作,直接把它们写入一个二进制文件里。
pickle模块会创建一个Python语言专用的二进制格式,不需要使用者考虑任何文件细节,它会帮你完成读写对象的操作。用pickle比打开文件、转换数据格式以及写入文件的操作能够节省不少代码。
pickle本身和json的功能是相同的,都是将Python数据对象保存为持久化的文件,区别是pickle能够保存Python的复杂的数据类型,包括列表、元组、自定义类等,而json只能保存字典类型的数据,同时pickle只能用Python打开,而json却可以被其他语言所读取。
访问模式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写,如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果改文件不存在,创建新文件用于读写。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头 |
wb+ | 以二进制格式打开一个文件用于读写。如果改文件已存在则会覆盖。如果改文件不存在,创建新文件。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果改文件不存在,创建新文件用于读写。 |
Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式,提高了易用性。
with 语句使代码更清晰、更具可读性, 它简化了文件流等公共资源的管理。
在处理文件对象时使用 with 关键字是一种很好的做法。
file = open('./test_runoob.txt', 'w')
file.write('hello world !')
file.close()
以上代码如果在调用 write 的过程中,出现了异常,则 close 方法将无法被执行,因此资源就会一直被该程序占用而无法被释放。 接下来我们呢可以使用 try…except…finally 来改进代码:
file = open('./test_runoob.txt', 'w')
try:
file.write('hello world')
finally:
file.close()
以上代码我们对可能发生异常的代码处进行 try 捕获,发生异常时执行 except 代码块,finally 代码块是无论什么情况都会执行,所以文件会被关闭,不会因为执行异常而占用资源。
使用 with 关键字:
with open('./test_runoob.txt', 'w') as file:
file.write('hello world !')
使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的。
pickle.dump()
: 将对象序列化成二进制对象;
pickle.load()
: 读取指定的二进制对象,并返回序列化对象。
import pickle
import numpy as np
output_dir = '/home/pytorch/LiangXiaohan/MI_Dataverse/MI_same_limb/window_size_150/'
data = [1, 2, 3, 4, 5]
with open(output_dir+ "-data_eeg.pkl", "wb") as fp_data:
pickle.dump(data, fp_data)
with open(output_dir + "-data_eeg.pkl", "rb") as fp_data:
data_pkl = pickle.load(fp_data)
data_pkl
输出:
[1, 2, 3, 4, 5]
import pickle import numpy as np ### 生成滑动窗口数据 def windows_create(data_lengh, window_size, stirde): # data size [channel, samples] start = 0 while ((start+window_size) < data_lengh): yield int(start), int(start + window_size) start += stirde ### 滑动窗分割数据并将数据保存为pkl文件 def segment_signal_pkl(output_dir, persion_data, data, label, window_size, stirde): # data size [Train/Test_samp, channel, samples] label size [Train/Test_samp, 1] shape = data.shape output_data = output_dir + "sub-" + persion_data + "-data_eeg.pkl" output_label = output_dir + "sub-" + persion_data + "-label_eeg.pkl" file_data = open(output_data, 'ab') file_label = open(output_label, 'ab') for i in range(0, shape[0]): for (start, end) in windows_create(shape[2], window_size, stirde) : if ((data[i, :, start:end]).shape[1]== window_size): if (start == 0): segments = data[i, :, start:end] labels = label[i] else: segments = np.vstack((segments, data[i, :, start:end])) labels = np.append(labels, label[i]) segments = segments.reshape(int(segments.shape[0]/shape[1]), shape[1], window_size) pickle.dump(segments, file_data) pickle.dump(labels, file_label) segments = [] labels = [] file_data.close() file_label.close() output_dir = '/home/pytorch/LiangXiaohan/MI_Dataverse/MI_same_limb/window_size_150/' persion_data = '001' data = np.random.rand(20, 62, 500) label = np.random.rand(20, 1) segment_signal_pkl(output_dir, persion_data, data, label, 150, 10) cnn_features = [] labels = [] with open(output_dir + "sub-" + persion_data + "-data_eeg.pkl", "rb") as fp_data: for i in range(0, 20): cnn_features.append(pickle.load(fp_data)) with open(output_dir + "sub-" + persion_data + "-label_eeg.pkl", "rb") as fp_label: for i in range(0, 20): labels.append(pickle.load(fp_label)) np.array(cnn_features).shape
输出:
(20, 35, 62, 150)
注:在连续写入后进行读取操作,这里与之前有点不同,就是读取的时候不能一次性全部读出来,每次读取读到的数据是,连续写入过程中其中一次写入的数据,所以在读取的时候我们需要用for
循环来读取。
注:原本的分割数据的函数如下所示,但是这个函数有个问题,那就是越运行越慢,跑完一组数据需要一天的时间,分析了一下发现原因在这句话segments = np.vstack((segments, data[i, :, start:end]))
,随着程序的运行,存储的数据也越来越多,造成segments
占用的内存越来越大,这就造成程序运行越来越慢,进而想到将函数更改为上面的样子,这就出现了连续读写pkl文件的问题。
### 滑动窗分割数据 def segment_signal(data, label, window_size, stirde): # data size [Train/Test_samp, channel, samples] label size [Train/Test_samp, 1] shape = data.shape for i in tqdm(range(0, shape[0])): for (start, end) in windows_create(shape[2], window_size, stirde): if ((data[i, :, start:end]).shape[1]== window_size): if (start == 0) and (i == 0): segments = data[i, :, start:end] labels = label[i] else: segments = np.vstack((segments, data[i, :, start:end])) labels = np.append(labels, label[i]) segments = segments.reshape(int(segments.shape[0]/shape[1]), shape[1], window_size) # segments size [Train/Test_samp, channel, window_size] labels size [Train/Test_samp, 1] return segments, labels
shape = np.array(Pearson_feature).shape
shape
输出:
(900, 65, 62, 62)
with open(output_dir + "sub-" + persion_data + "-feature_eeg.pkl", "wb") as fp_feature:
for i in tqdm(range(0, 900)):
pickle.dump(Pearson_feature[i], fp_feature)
feature_data = []
with open(output_dir + "sub-" + persion_data + "-feature_eeg.pkl", "rb") as fp_feature:
for i in range(0, 900):
feature_data.append(pickle.load(fp_feature))
shape = np.array(feature_data).shape
shape
输出:
(900, 65, 62, 62)
可以看到对于4维矩阵写入文件和读取出来都需要使用for
循环。
更新:2023年2月10日。
今天突然发现四维矩阵可以正常的保存和读取,之前的时候报错,也不知道为啥!!!
np.array(data_2D).shape
输出:
(900, 800, 9, 11)
with open(output_dir + "sub-" + persion_data + "-aaa_eeg.pkl", "wb") as fp_aaa:
pickle.dump(data_2D, fp_aaa)
with open(output_dir + "sub-" + persion_data + "-aaa_eeg.pkl", "rb") as fp_datas:
X = pickle.load(fp_datas)
np.array(X).shape
输出:
(900, 800, 9, 11)
更新:2023年2月12日。
直接在pickle.dump中增加一个protocol = 4这个参数就行。
import pickle
pickle.dump(data,open('file','wb'),protocol = 4)
原因如下所示:
https://docs.python.org/3.7/library/pickle.html?highlight=pickle#pickle.HIGHEST_PROTOCOL
在对数据进行处理,然后将处理后的数据暂时存储到一个变量中。起初,我使用的是np.array
数据类型,发现随着存储的数据越来越多,程序运行的就越来越慢,然后考虑到对处理后的数据进行连续存储处理,这样每次存储结束就清空np.array
数组,这样的操作确实解决了程序运行缓慢的问题,但是在读取pkl文件的时候就需要用for循环,这样写的代码很难看。然后不经意间用到了list
,发现就算储存的数据量很大也不会出现程序运行缓慢的问题了,也就不需要连续存储的操作了,然后在读取文件的时候也可以直接读取,不再使用for循环了,这样程序写起来就好看多了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。