如何正确保存和加载numpy.array()数据?


103

我想知道如何numpy.array正确保存和加载数据。目前,我正在使用该numpy.savetxt()方法。例如,如果我有一个array 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文件呢?

4
您是否需要保存并加载为人类可读的文本文件?如果使用np.save()和保存/加载二进制文件,它将更快(文件更紧凑)np.load()
ali_m 2015年

感谢您的意见。它有帮助。但是,您能解释一下为什么会这样吗,以及是否有任何方法可以将数据保存为* .txt格式并轻松加载呢?例如,当您想使用matlab,java或其他工具/语言时。
bluevoxel

3
要将数组传递到MATLAB或从MATLAB传递出去,可以使用scipy.io.savematscipy.io.loadmat
ali_m 2015年

2
缺省为fromfile将数据读取为二进制。 loadtxt与正确配对savetxt。查看功能文档。
hpaulj 2015年

Answers:


144

我发现执行此操作的最可靠方法是与一起使用np.savetxtnp.loadtxt而不是np.fromfile更适合用编写的二进制文件tofile。该np.fromfilenp.tofile方法写入和读取二进制文件,而np.savetxt写入一个文本文件。因此,例如:

In [1]: a = np.array([1, 2, 3, 4])
In [2]: np.savetxt('test1.txt', a, fmt='%d')
In [3]: b = np.loadtxt('test1.txt', dtype=int)
In [4]: a == b
Out[4]: array([ True,  True,  True,  True], dtype=bool)

要么:

In [5]: a.tofile('test2.dat')
In [6]: c = np.fromfile('test2.dat', dtype=int)
In [7]: c == a
Out[7]: array([ True,  True,  True,  True], dtype=bool)

我使用前一种方法,即使它速度较慢并且有时会创建更大的文件:二进制格式也可能取决于平台(例如,文件格式取决于系统的字节序)。

NumPy数组有与平台无关的格式,可以使用np.save和保存和读取np.load

In  [8]: np.save('test3.npy', a)    # .npy extension is added if not given
In  [9]: d = np.load('test3.npy')
In [10]: a == d
Out[10]: array([ True,  True,  True,  True], dtype=bool)

45
.npy文件(例如由生成的文件np.save()平台无关,并且比文本文件更紧凑,创建更快。
ali_m 2015年

2
另外,np.savez如果您想压缩输出。
tegan

3
@tegan np.savez保存几个未压缩的数组- np.savez_compressed将对其进行压缩- np.save_compressed尚无。参见docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns

1
谢谢xnx,我在使用np.savetxt和np.loadtxt时遇到了相同的问题(使用dtype float)
Yogesh

我在泡菜保存大于2GB的数据时遇到问题。多亏了xnx,使用a.tofile和np.fromfile解决了问题。
阿扎尔侯赛因

47
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load

使用有问题pickle吗?
查理·帕克

例如,以便我们可以x = db["x"]y = db["y"]?后面的?加载数据。
查理·帕克

3

np.fromfile()有一个sep=关键字参数:

如果文件是文本文件,则项目之间的分隔符。空(“”)分隔符表示文件应被视为二进制文件。分隔符中的空格(“”)匹配零个或多个空格字符。仅由空格组成的分隔符必须至少匹配一个空格。

默认值sep=""意味着np.fromfile()试图将其读取为二进制文件而不是以空格分隔的文本文件,因此您会得到无意义的值。如果使用np.fromfile('markers.txt', sep=" "),将得到您想要的结果。

但是,正如其他人指出的那样,这np.loadtxt()是将文本文件转换为numpy数组的首选方法,除非该文件需要人类可读,否则通常最好使用二进制格式(例如np.load()/ np.save())。


使用有问题pickle吗?
查理·帕克

0

对于简短的答案,您应该使用np.savenp.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]]

扩展答案:

最后,它确实取决于您的需求,因为您还可以将其保存为人类可读的格式(请参见将此NumPy数组转储到csv文件中),或者如果文件非常大,甚至可以与其他库一起使用(请参见保存numpy数组的最佳方法)在磁盘上进行扩展讨论)。

但是,(由于您在问题中使用“正确”一词,因此进行了扩展)我仍然认为开箱即用(和大多数代码!)使用numpy函数最有可能满足大多数用户需求。最重要的原因是它已经起作用。出于其他原因尝试使用其他东西可能会使您出乎意料的长兔子洞,弄清楚为什么它不起作用并迫使它起作用。

以尝试用泡菜保存为例。我只是为了好玩而尝试,花了至少30分钟的时间才意识到,除非我用字节模式打开并读取文件,否则泡菜不会保存我的东西wb。花时间去Google,试一试,理解错误消息等。小细节,但事实是它已经需要我打开文件,从而以意想不到的方式使事情变得复杂。补充一点,它要求我重新阅读此内容(哪个btw有点令人困惑)内置开放功能中的模式a,a +,w,w +和r +之间的区别?

所以,如果有符合您需要使用它,除非你有一个(的接口非常)充分的理由(如与MATLAB或由于某种原因,你真的要读取的文件和打印蟒蛇真的不能满足您的需求,它的兼容性可能有问题)。此外,最有可能的是,如果您需要对其进行优化,则可以在以后找到答案(而不是花很多时间调试无用的东西,例如打开一个简单的numpy文件)。

因此,请使用interface / 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://stackoverflow.com/a/55750128/1601580),开箱即用,无需打开任何文件。清洁。简单。高效。用它。
  • np.savez使用未压缩的格式(请参阅docsSave several arrays into a single file in uncompressed 。npz format.如果决定使用此格式(警告您不要使用标准解决方案,因此请注意错误!),您可能会发现您需要使用参数名称来保存它,除非您想要使用默认名称。因此,如果第一个已经使用(或任何作品都使用该功能!),请勿使用此功能。
  • Pickle还允许执行任意代码。出于安全原因,某些人可能不想使用此功能。
  • 可读文件的制作成本很高,可能不值得。
  • 有一些所谓hdf5的大文件。凉!https://stackoverflow.com/a/9619713/1601580

请注意,这不是详尽的答案。但是对于其他资源,请检查以下内容:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.