如何在同一个存档中保存字典和数组(使用numpy.savez)

sur*_*chs 13 python dictionary numpy

这是第一个问题.我会尽量简明扼要.

我正在生成包含机器学习应用程序的功能信息的多个数组.由于数组没有相同的尺寸,我将它们存储在字典而不是数组中.有两种不同的功能,所以我使用两种不同的词典.

我还生成标签以配合这些功能.这些标签存储在数组中.此外,还有一些字符串包含用于运行脚本的确切参数和时间戳.

总而言之它看起来像这样:

import numpy as np    

feature1 = {}
feature2 = {}
label1 = np.array([])
label2 = np.array([])
docString = 'Commands passed to the script were...'

# features look like this:
feature1 = {'case 1': np.array([1, 2, 3, ...]),
            'case 2': np.array([2, 1, 3, ...]),
            'case 3': np.array([2, 3, 1, ...]),
            and so on... }
Run Code Online (Sandbox Code Playgroud)

现在我的目标是这样做:

np.savez(outputFile, 
         saveFeature1 = feature1, 
         saveFeature2 = feature2, 
         saveLabel1 = label1, 
         saveLabel2 = label2,
         saveString = docString)
Run Code Online (Sandbox Code Playgroud)

这似乎有效(即保存这样的文件没有抛出错误,可以再次加载).但是,当我尝试再次加载文件中的功能时:

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1']
loadedString = loadedArchive['saveString']
Run Code Online (Sandbox Code Playgroud)

然后我得到一个numpy数组形状(0),而不是获取字典,我不知道如何访问内容:

In []: loadedFeature1
Out[]: 
       array({'case 1': array([1, 2, 3, ...]), 
              'case 2': array([2, 3, 1, ...]), 
              ..., }, dtype=object)
Run Code Online (Sandbox Code Playgroud)

字符串也成为数组并获得奇怪的数据类型:

In []: loadedString.dtype
Out[]: dtype('|S20')
Run Code Online (Sandbox Code Playgroud)

所以简而言之,我假设这不是如何正确完成的.但是我宁愿不将所有变量放入一个大字典中,因为我将在另一个进程中检索它们,并且只想循环遍历dictionary.keys()而不必担心字符串比较.

任何想法都非常感谢.谢谢

Joe*_*ton 17

正如@fraxel已经建议的那样,在这种情况下使用pickle是一个更好的选择.只需将dict您的物品保存在其中即可.

但是,一定要使用带有二进制协议的pickle.默认情况下,格式效率较低,如果阵列较大,将导致内存使用过多和文件过多.

saved_data = dict(outputFile, 
                  saveFeature1 = feature1, 
                  saveFeature2 = feature2, 
                  saveLabel1 = label1, 
                  saveLabel2 = label2,
                  saveString = docString)

with open('test.dat', 'wb') as outfile:
    pickle.dump(saved_data, outfile, protocol=pickle.HIGHEST_PROTOCOL)
Run Code Online (Sandbox Code Playgroud)

话虽如此,让我们来看看为了说明目的而更详细地发生了什么.

numpy.savez期望每个项目都是一个数组.事实上,它会调用np.asarray你传递的所有内容.

如果你把一个dict变成一个数组,你将得到一个对象数组.例如

import numpy as np

test = {'a':np.arange(10), 'b':np.arange(20)}
testarr = np.asarray(test)
Run Code Online (Sandbox Code Playgroud)

类似地,如果你从一个字符串中创建一个数组,你将获得一个字符串数组:

In [1]: np.asarray('abc')
Out[1]: 
array('abc', 
      dtype='|S3')
Run Code Online (Sandbox Code Playgroud)

但是,由于处理对象数组的方式很奇怪,如果传入一个dict不是元组,列表或数组的单个对象(在您的情况下,您的),您将获得一个0维对象数组.

这意味着您无法直接将其编入索引.事实上,做testarr[0]会提高一个IndexError.数据仍然存在,但您需要先添加维度,因此您必须这样做yourdictionary = testarr.reshape(-1)[0].

如果所有这些看起来都很笨重,那是因为它是.对象数组基本上总是错误的答案.(虽然asarray应该可以说是传递ndmin=1array,这将解决这个特定的问题,但可能会破坏其他的东西.)

savez用于存储数组,而不是任意对象.由于它的工作方式,它可以存储完全任意的对象,但不应该以这种方式使用.

但是,如果您确实想要使用它,可以采用以下快速解决方法:

np.savez(outputFile, 
         saveFeature1 = [feature1], 
         saveFeature2 = [feature2], 
         saveLabel1 = [label1], 
         saveLabel2 = [label2],
         saveString = docString)
Run Code Online (Sandbox Code Playgroud)

然后你就可以访问了

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1'][0]
loadedString = str(loadedArchive['saveString'])
Run Code Online (Sandbox Code Playgroud)

然而,这显然比仅仅使用泡菜更笨重.使用numpy.savez当你刚刚保存的阵列.在这种情况下,您将保存嵌套数据结构,而不是数组.

  • 我更喜欢通过`testarr.flat [0]`访问`()`形数组中的元素.对于好奇的读者来说,也可以使用`testarr [()]`中的空元组,但这会损害可读性. (2认同)

pwu*_*rtz 10

如果需要以结构化方式保存数据,则应考虑使用HDF5文件格式(http://www.hdfgroup.org/HDF5/).它非常灵活,易于使用,高效,其他软件可能已经支持它(HDFView,Mathematica,Matlab,Origin ..).有一个简单的python绑定叫做h5py.

您可以将数据集存储在文件系统(如结构)中,并为每个数据集定义属性,如字典.例如:

import numpy as np
import h5py

# some data
table1 = np.array([(1,1), (2,2), (3,3)], dtype=[('x', float), ('y', float)])
table2 = np.ones(shape=(3,3))

# save to data to file
h5file = h5py.File("test.h5", "w")
h5file.create_dataset("Table1", data=table1)
h5file.create_dataset("Table2", data=table2, compression=True)
# add attributes
h5file["Table2"].attrs["attribute1"] = "some info"
h5file["Table2"].attrs["attribute2"] = 42
h5file.close()
Run Code Online (Sandbox Code Playgroud)

读取数据也很简单,如果需要,甚至可以从大文件中加载一些元素:

h5file = h5py.File("test.h5", "r")
# read from file (numpy-like behavior)
print h5file["Table1"]["x"][:2]
# read everything into memory (real numpy array)
print np.array(h5file["Table2"])
# read attributes
print h5file["Table2"].attrs["attribute1"]
Run Code Online (Sandbox Code Playgroud)

文档和网站上提供了更多功能和可能性(" 快速入门指南"可能很有用).