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

Python 如何在同一存档中保存字典和数组(使用numpy.savez),python,dictionary,numpy,Python,Dictionary,Numpy,第一个问题。我会尽量简明扼要 我正在为机器学习应用程序生成包含功能信息的多个数组。由于数组的维数不相等,我将它们存储在字典中而不是数组中。有两种不同的功能,所以我使用两种不同的字典 我还生成标签以配合功能。这些标签存储在数组中。此外,还有一些字符串包含用于运行脚本的确切参数和时间戳 总而言之,它看起来是这样的: import numpy as np feature1 = {} feature2 = {} label1 = np.array([]) label2 = np.array([

第一个问题。我会尽量简明扼要

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

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

总而言之,它看起来是这样的:

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... }
现在我的目标是这样做:

np.savez(outputFile, 
         saveFeature1 = feature1, 
         saveFeature2 = feature2, 
         saveLabel1 = label1, 
         saveLabel2 = label2,
         saveString = docString)
这似乎是可行的(即,这样的文件保存时不会抛出错误,可以再次加载)。但是,当我尝试再次从文件加载功能时,例如:

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1']
loadedString = loadedArchive['saveString']
然后,我得到的不是一个字典,而是一个形状为(0)的numpy数组,其中我不知道如何访问内容:

In []: loadedFeature1
Out[]: 
       array({'case 1': array([1, 2, 3, ...]), 
              'case 2': array([2, 3, 1, ...]), 
              ..., }, dtype=object)
字符串也会变成数组并获得奇怪的数据类型:

In []: loadedString.dtype
Out[]: dtype('|S20')
简而言之,我假设这不是正确的做法。但是,我不希望将所有变量都放在一个大字典中,因为我将在另一个过程中检索它们,并且只希望在dictionary.keys()上循环,而不必担心字符串比较

非常感谢您的任何想法。
谢谢

将所有变量放入一个对象中,然后使用。这是存储状态信息的更好方法。

正如@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)

已经说过了,让我们更详细地看看发生的事情。p>

numpy.savez
要求每个项目都是一个数组。事实上,它会对传入的所有内容调用
np.asarray

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

import numpy as np

test = {'a':np.arange(10), 'b':np.arange(20)}
testarr = np.asarray(test)
类似地,如果使用字符串创建数组,则会得到一个字符串数组:

In [1]: np.asarray('abc')
Out[1]: 
array('abc', 
      dtype='|S3')
但是,由于处理对象数组的方式有一个怪癖,如果传入一个不是元组、列表或数组的单个对象(在您的例子中是您的
dict
),您将得到一个0维对象数组

这意味着您不能直接为其编制索引。实际上,执行
testarr[0]
将引发一个
索引器。数据仍然存在,但您需要先添加一个维度,因此您必须执行
yourdictionary=testarr.Reformate(-1)[0]

如果这一切看起来都很笨拙,那是因为它确实如此。对象数组基本上总是错误的答案。(虽然
asarray
可以说应该将
ndmin=1
传递给
array
,这将解决这个特殊问题,但可能会破坏其他方面。)

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

但是,如果您确实想使用它,一个快速解决方法是:

np.savez(outputFile, 
         saveFeature1 = [feature1], 
         saveFeature2 = [feature2], 
         saveLabel1 = [label1], 
         saveLabel2 = [label2],
         saveString = docString)
然后你就可以用

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1'][0]
loadedString = str(loadedArchive['saveString'])

然而,这显然比仅仅使用泡菜要笨重得多。在保存数组时使用
numpy.savez
。在这种情况下,您正在保存嵌套的数据结构,而不是数组。

< P>如果您需要以结构化的方式保存数据,则应该考虑使用HDF5文件格式()。它非常灵活、易于使用、高效,其他软件可能已经支持它(HDFView、Mathematica、Matlab、Origin…)。有一个简单的python绑定,名为

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

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()
读取数据也很简单,如果需要,您甚至可以从一个大文件中加载几个元素:

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"]

更多功能和可能性可在文档和网站上找到(可能会感兴趣)。

谢谢。但这不意味着每次我都必须使用相同数量的变量吗?如果出于某种原因,我只保存一个字典,那么使用pickle加载此文件的每个脚本都会打乱存储变量的顺序。我更喜欢通过
testarr.flat[0]
访问
()
形状数组中的元素。对于好奇的读者来说,也可以像在
testarr[()]
中那样使用空元组,但这会影响可读性。