使用Pickle保存Numpy数组



我有一个Numpy数组,我想保存它(130000 x 3),我想用Pickle保存它,代码如下。然而,我在pkl.load行不断收到错误"EOFError:输入不足"或"UnsupportedOperation:read"。这是我第一次用泡菜,有什么想法吗?

谢谢,

Anant

import pickle as pkl
import numpy as np
arrayInput = np.zeros((1000,2)) #Trial input
save = True
load = True
filename = path + 'CNN_Input'
fileObject = open(fileName, 'wb')
if save:
pkl.dump(arrayInput, fileObject)
fileObject.close()
if load:
fileObject2 = open(fileName, 'wb')
modelInput = pkl.load(fileObject2)
fileObject2.close()
if arrayInput == modelInput:
Print(True)

您应该使用numpy.save和numpy.load.

我使用pickle:没有问题

In [126]: arr = np.zeros((1000,2))
In [127]: with open('test.pkl','wb') as f:
...:     pickle.dump(arr, f)
...:     
In [128]: with open('test.pkl','rb') as f:
...:     x = pickle.load(f)
...:     print(x.shape)
...:     
...:     
(1000, 2)

CCD_ 2和CCD_。就像我可以用np.load:加载这个泡菜一样

In [129]: np.load('test.pkl').shape
Out[129]: (1000, 2)

如果我在错误的地方打开pickle文件,我会得到你的错误:

In [130]: with open('test.pkl','wb') as f:
...:     x = pickle.load(f)
...:     print(x.shape)
...:    
UnsupportedOperation: read

但这并不奇怪——你无法读取刚打开的写入文件。它将是空的。

np.save/load是用于写入numpy数组的常用对。但是pickle使用save来序列化数组,save使用pickle来序列化(数组中的)非数组对象。生成的文件大小相似。奇怪的是,泡菜版本在时间上更快。

这有点困难,但如果你发现了这一点,Pickle只需很短的时间就可以完成。

with open('filename','wb') as f: pickle.dump(arrayname, f)
with open('filename','rb') as f: arrayname1 = pickle.load(f)
numpy.array_equal(arrayname,arrayname1) #sanity check

另一方面,默认情况下,numpy压缩将我的5.2GB压缩到了.4GB,Pickle压缩到了1.7GB。

不要对numpy数组使用pickle,对于链接到我能找到的所有资源的扩展讨论,请在这里查看我的答案。

简短原因:

  • numpy的开发人员已经制作了一个不错的界面,可以节省大量的调试时间(最重要的原因)
  • np.save,np.load,np.savez在大多数度量中都有相当好的性能,这是意料之中的,因为它是一个已建立的库,numpy的开发人员制作了这些函数
  • Pickle执行任意代码,是一个安全问题
  • 要使用pickle,您必须打开并归档,可能会遇到导致错误的问题(例如,我不知道使用b,它停止了工作,需要时间进行调试)
  • 如果你拒绝接受这个建议,至少要清楚地说出你需要使用其他东西的原因。确保它在你的脑海中清晰可见

如果解决方案已经存在,请不惜一切代价避免重复代码!

总之,以下是我尝试过的所有接口,希望它能节省一些时间(可能是我未来的自己):

import numpy as np
import pickle
from pathlib import Path
path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)
lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2
# using save (to npy), savez (to npz)
np.save(path/'x', x)
np.save(path/'y', y)
np.savez(path/'db', x=x, y=y)
with open(path/'db.pkl', 'wb') as db_file:
pickle.dump(obj={'x':x, 'y':y}, file=db_file)
## using loading npy, npz files
x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')
db = np.load(path/'db.npz')
with open(path/'db.pkl', 'rb') as db_file:
db_pkl = pickle.load(db_file)
print(x is x_loaded)
print(x == x_loaded)
print(x == db['x'])
print(x == db_pkl['x'])
print('done')

但最有用的是在这里看到我的答案。

这里有一种额外的可能方法。有时您应该添加额外的选项protocol。例如,

import pickle
# Your array
arrayInput = np.zeros((1000,2))

这是你的方法:

pickle.dump(arrayInput, open('file_name.pickle', 'wb'))

您可以更改为:

# in two lines of code
with open("file_name.pickle", "wb") as f:
pickle.dump(arrayInput, f, protocol=pickle.HIGHEST_PROTOCOL)

# Save in line of code
pickle.dump(arrayInput, open("file_name.pickle", "wb"), protocol=pickle.HIGHEST_PROTOCOL)

数学之后,你可以很容易地读取你的numpy数组,比如:

arrayInput = pickle.load(open(self._dir_models+"model_rf.sav", 'rb'))

希望,它对你有用

许多人忘记了一件非常重要的事情:安全

Pickled数据是二进制的,所以它在使用pickle.load时立即运行。如果从不受信任的来源加载,该文件可能包含可执行指令,以实现网络上的中间人攻击等功能。(例如,请参阅realpython.com文章)

如果不使用bz2压缩,则纯腌制数据的保存/加载速度可能更快,因此文件大小更大,但numpy加载/保存可能更安全。

或者,您可以使用内置的hashlibhmac库保存纯腌制数据和加密密钥,并在加载之前将哈希密钥与您的安全密钥进行比较:

import hashlib
import hmac
def calculate_hash(
key_,
file_path,
hash_=hashlib.sha256
):
with open(file_path, "rb") as fp:
file_hash = hmac.new(key_, fp.read(), hash_).hexdigest()
return file_hash
def compare_hash(
hash1,
hash2,
):
"""
Warning:
Do not use `==` directly to compare hash values. Timing attacks can be used
to learn your security key. Use ``compare_digest()``.
"""
return hmac.compare_digest(hash1, hash2)

在公司环境中,请务必与您的IT部门确认。您希望确保正确的身份验证、加密和授权都是"必需的";设置为"去";当通过服务器和网络加载和保存数据时。

酸洗/酸洗

如果你确信你只使用了可信的来源,并且速度是安全性和文件大小的主要问题,那么pickle可能是你的选择。此外,您可以使用cPickle采取一些额外的安全措施(在最近的Python3版本中,这可能直接包含在pickle中,但我不确定,所以请务必仔细检查):

  1. 使用cPickle.Unpickler实例,并设置其";find_global";属性为None以禁止导入任何模块(从而将加载限制为内置类型,如pickle0、intliststring等)。

  2. 使用cPickle.Unpickler实例;find_global";属性,该函数只允许从白名单导入模块和名称。

  3. 如果从不受信任的源加载数据,则在取消拾取数据之前,请使用类似itsdangerous包的方法对数据进行身份验证。

Numpy

如果您只保存numpy数据,而不保存其他python数据,并且安全性比文件大小和速度更重要,那么numpy可能是最佳选择。

HDF5/H5PY

如果您的数据确实很大且复杂,那么通过np.save/load0使用hdf5格式是很好的。

JSON

当然,如果不提到json,这个讨论就不完整。你可能需要做额外的工作来设置数据的编码和解码,但当你使用json.load时,没有什么能立即运行,所以你可以在使用之前检查加载数据的模板/结构。

免责声明:我对所提供信息的最终用户安全不承担任何责任。以上信息仅供参考。请在安全需求方面使用适当的自由裁量权和适当的措施(包括公司政策,如适用)。

您应该使用numpy.save()来保存numpy矩阵。

在您的代码中,您使用的是

if load:
fileObject2 = open(fileName, 'wb')
modelInput = pkl.load(fileObject2)
fileObject2.close()

open函数中的第二个参数是方法。w代表书写,r代表阅读。第二个字符CCD_ 37表示字节将被读取/写入。将要写入的文件无法读取,反之亦然。因此,用fileObject2 = open(fileName, 'rb')打开文件就可以了。

saveload的最简单方法是NumPy数组-

# a numpy array
result.importances_mean
array([-1.43651529e-03, -2.73401297e-03,  9.26784059e-05, -7.41427247e-04,
3.56811863e-03,  2.78035218e-03,  3.70713624e-03,  5.51436515e-03,
1.16821131e-01,  9.26784059e-05,  9.26784059e-04, -1.80722892e-03,
-1.71455051e-03, -1.29749768e-03, -9.26784059e-05, -1.43651529e-03,
0.00000000e+00, -1.11214087e-03, -4.63392030e-05, -4.63392030e-04,
1.20481928e-03,  5.42168675e-03, -5.56070436e-04,  8.34105653e-04,
-1.85356812e-04,  0.00000000e+00, -9.73123262e-04, -1.43651529e-03,
-1.76088971e-03])
# save the array format - np.save(filename.npy, array)
np.save(os.path.join(model_path, "permutation_imp.npy"), result.importances_mean)
# load the array format - np.load(filename.npy)
res = np.load(os.path.join(model_path, "permutation_imp.npy"))
res
array([-1.43651529e-03, -2.73401297e-03,  9.26784059e-05, -7.41427247e-04,
3.56811863e-03,  2.78035218e-03,  3.70713624e-03,  5.51436515e-03,
1.16821131e-01,  9.26784059e-05,  9.26784059e-04, -1.80722892e-03,
-1.71455051e-03, -1.29749768e-03, -9.26784059e-05, -1.43651529e-03,
0.00000000e+00, -1.11214087e-03, -4.63392030e-05, -4.63392030e-04,
1.20481928e-03,  5.42168675e-03, -5.56070436e-04,  8.34105653e-04,
-1.85356812e-04,  0.00000000e+00, -9.73123262e-04, -1.43651529e-03,
-1.76088971e-03])

最新更新