如何正确保存和加载 numpy.array() 数据?
Posted
技术标签:
【中文标题】如何正确保存和加载 numpy.array() 数据?【英文标题】:How to save and load numpy.array() data properly? 【发布时间】:2015-04-10 23:01:23 【问题描述】:我想知道如何正确保存和加载numpy.array
数据。目前我正在使用numpy.savetxt()
方法。例如,如果我得到一个数组markers
,它看起来像这样:
我尝试通过以下方式保存它:
numpy.savetxt('markers.txt', markers)
在其他脚本中,我尝试打开以前保存的文件:
markers = np.fromfile("markers.txt")
这就是我得到的......
保存的数据首先如下所示:
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
但是当我使用相同的方法保存刚刚加载的数据时,即。 numpy.savetxt()
看起来像这样:
1.398043286095131769e-76
1.398043286095288860e-76
1.396426376485745879e-76
1.398043286055061908e-76
1.398043286095288860e-76
1.182950697433698368e-76
1.398043275797188953e-76
1.398043286095288860e-76
1.210894289234927752e-99
1.398040649781712473e-76
我做错了什么? PS我没有执行其他“后台”操作。只是保存和加载,这就是我得到的。提前谢谢你。
【问题讨论】:
文本文件的输出是什么?为什么不直接写入 CSV 文件? 您需要保存和加载为人类可读的文本文件吗?如果您使用np.save()
和np.load()
保存/加载二进制文件,它会更快(并且文件会更紧凑)。
感谢您的建议。它有帮助。但是,您能解释一下为什么会这样吗?是否有任何方法可以将数据保存为 *.txt 格式并轻松加载?例如,当您想使用 matlab、java 或其他工具/语言时。
要将数组传入/传出 MATLAB,您可以使用 scipy.io.savemat
和 scipy.io.loadmat
。
fromfile
的默认值是以二进制形式读取数据。 loadtxt
是与 savetxt
的正确配对。查看函数文档。
【参考方案1】:
简短的回答是:您应该使用np.save
和np.load
。
使用这些函数的优势在于它们是由 Numpy 库的开发人员制作的,并且它们已经可以工作(另外,很可能针对处理速度进行了很好的优化)。
例如:
import numpy as np
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
np.save(path/'x', x)
np.save(path/'y', y)
x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')
print(x is x_loaded) # False
print(x == x_loaded) # [[ True True True True True]]
扩展答案:
最后,它真的取决于您的需求,因为您还可以将其保存为人类可读的格式(请参阅Dump a NumPy array into a csv file),或者如果您的文件非常大,甚至可以使用其他库(请参阅best way to preserve numpy arrays on disk 进行扩展讨论)。
但是,(由于您在问题中使用了“正确”一词,因此进行了扩展)我仍然认为使用开箱即用的 numpy 函数(以及大多数代码!)最有可能满足大多数用户的需求。最重要的原因是它已经工作了。出于任何其他原因尝试使用其他东西可能会让你陷入一个意想不到的长兔子洞,以找出它为什么不起作用并强制它起作用。
以尝试用泡菜保存它为例。我只是为了好玩而尝试这样做,我花了至少 30 分钟才意识到除非我使用 wb
以字节模式打开并读取文件,否则泡菜不会保存我的东西。谷歌搜索问题、测试潜在解决方案、理解错误消息等需要时间……这是一个小细节,但事实上它已经要求我以意想不到的方式打开文件使事情变得复杂。除此之外,它需要我重新阅读(顺便说一句有点令人困惑):Difference between modes a, a+, w, w+, and r+ in built-in open function?。
因此,如果有满足您需求的界面,请使用它,除非您有(非常)充分的理由(例如与 matlab 兼容或出于某种原因您真的想读取文件并打印在 Python 中确实不能满足您的需求,这可能是有问题的)。此外,如果您需要对其进行优化,很可能会在以后发现(而不是花费大量时间调试无用的东西,例如打开一个简单的 Numpy 文件)。
所以使用接口/numpy 提供。它可能并不完美,但很可能没问题,尤其是对于一个与 Numpy 一样长的库。
我已经以多种方式使用 numpy 保存和加载数据,所以玩得开心。希望这会有所帮助!
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')
关于我学到的一些知识:
np.save
正如预期的那样,这已经很好地压缩了它(参见https://***.com/a/55750128/1601580),开箱即用,无需打开任何文件。干净的。简单。高效的。使用它。
np.savez
使用未压缩的格式(请参阅docs)以未压缩的.npz
格式将多个数组保存到单个文件中。如果您决定使用它(您已被警告不要使用标准解决方案,所以期待错误!)您可能会发现您需要使用参数名称来保存它,除非您想使用默认名称。因此,如果第一个已经有效(或任何作品都在使用它!),请不要使用它!
Pickle 还允许执行任意代码。出于安全原因,有些人可能不想使用它。
人类可读的文件制作成本很高。可能不值得。
对于大文件,有一个叫做hdf5
的东西。凉爽的! https://***.com/a/9619713/1601580
请注意,这不是一个详尽的答案。但对于其他资源,请检查:
泡菜(猜猜最好的答案是不要使用泡菜,使用np.save
):Save Numpy Array using Pickle
对于大文件(很好的答案!比较存储大小、加载保存等等!):https://***.com/a/41425878/1601580
对于 matlab(我们必须接受 matlab 有一些非常好的情节!):"Converting" Numpy arrays to Matlab and vice versa
以可读格式保存:Dump a NumPy array into a csv file
【讨论】:
【参考方案2】:我发现最可靠的方法是将np.savetxt
与np.loadtxt
一起使用,而不是np.fromfile
,后者更适合用tofile
编写的二进制文件。 np.fromfile
和 np.tofile
方法写入和读取二进制文件,而 np.savetxt
写入文本文件。
所以,例如:
a = np.array([1, 2, 3, 4])
np.savetxt('test1.txt', a, fmt='%d')
b = np.loadtxt('test1.txt', dtype=int)
a == b
# array([ True, True, True, True], dtype=bool)
或者:
a.tofile('test2.dat')
c = np.fromfile('test2.dat', dtype=int)
c == a
# array([ True, True, True, True], dtype=bool)
我使用前一种方法,即使它速度较慢并且会创建更大的文件(有时):二进制格式可能取决于平台(例如,文件格式取决于系统的字节序)。
NumPy 数组有一种平台无关格式,可以用np.save
和np.load
保存和读取:
np.save('test3.npy', a) # .npy extension is added if not given
d = np.load('test3.npy')
a == d
# array([ True, True, True, True], dtype=bool)
【讨论】:
.npy
文件(例如由np.save()
生成) 独立于平台,并且比文本文件更紧凑、创建速度更快。
如果你想压缩输出,也可以np.savez
。
@tegan np.savez
保存了几个未压缩的数组 - np.savez_compressed
将压缩它们 - 目前还没有 np.save_compressed
。见docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
谢谢 xnx 我在使用 np.savetxt 和 np.loadtxt 时遇到了同样的问题(使用 dtype float)解决了它
我在 pickle 保存大于 2GB 的数据时遇到问题。感谢 xnx 通过使用 a.tofile 和 np.fromfile 解决了问题。【参考方案3】:
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load
【讨论】:
【参考方案4】:np.fromfile()
有一个 sep=
关键字参数:
如果文件是文本文件,则项目之间的分隔符。空(“”)分隔符表示文件应被视为二进制文件。分隔符中的空格 (” ”) 匹配零个或多个空白字符。仅由空格组成的分隔符必须至少匹配一个空格。
sep=""
的默认值意味着np.fromfile()
尝试将其读取为二进制文件而不是空格分隔的文本文件,因此您会得到无意义的值。如果你使用np.fromfile('markers.txt', sep=" ")
,你会得到你想要的结果。
然而,正如其他人所指出的,np.loadtxt()
是将文本文件转换为 numpy 数组的首选方法,除非文件需要人类可读,否则通常最好使用二进制格式(例如 np.load()
/np.save()
)。
【讨论】:
以上是关于如何正确保存和加载 numpy.array() 数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何在numpy.array中以热量方式将numpy.array传递给对象的方法
如何在没有科学记数法和给定精度的情况下漂亮地打印 numpy.array?