将数组或DataFrame与其他信息一起保存在文件中

时间:2018-04-09 19:21:31

标签: python pandas numpy stata hdf5

统计软件Stata允许将短文本片段保存在数据集中。这可以使用notes和/或characteristics完成。

这对我来说是一个很有价值的功能,因为它允许我保存各种信息,从提醒和待办事项列表到有关我如何生成数据的信息,甚至是特定变量的估算方法是。

我现在正试图在Python 3.6中提出类似的功能。到目前为止,我已经在线查看了一些帖子,但这些帖子并没有完全解决我想做的事情。

一些参考文章包括:

对于较小的NumPy数组,我得出结论,函数numpy.savez()dictionary的组合可以在一个文件中充分存储所有相关信息。

例如:

a = np.array([[2,4],[6,8],[10,12]])
d = {"first": 1, "second": "two", "third": 3}

np.savez(whatever_name.npz, a=a, d=d)
data = np.load(whatever_name.npz)

arr = data['a']
dic = data['d'].tolist()

但问题仍然存在:

是否有更好的方法可以将其他信息包含在包含NumPy数组或(大)Pandas DataFrame的文件中?

我特别感兴趣的是,您可以通过示例了解任何建议的专业缺点。依赖性越少越好。

6 个答案:

答案 0 :(得分:19)

有很多选择。我将只讨论HDF5,因为我有使用这种格式的经验。

优点:可移植(可在Python之外读取),本机压缩,内存不足功能,元数据支持。

缺点:依赖单个低级别C API,将数据损坏作为单个文件的可能性,删除数据不会自动减小大小。

根据我的经验,出于性能和可移植性,避免 pyTables / HDFStore来存储数字数据。您可以使用h5py提供的直观界面。

存储数组

import h5py, numpy as np

arr = np.random.randint(0, 10, (1000, 1000))

f = h5py.File('file.h5', 'w', libver='latest')  # use 'latest' for performance

dset = f.create_dataset('array', shape=(1000, 1000), data=arr, chunks=(100, 100)
                        compression='gzip', compression_opts=9)

压缩&分块

有许多压缩选择,例如blosclzf分别是压缩和解压缩性能的不错选择。注意gzip是原生的;默认情况下,您的HDF5安装可能无法提供其他压缩过滤器。

Chunking是另一种选择,当与读取数据内存时的方式一致时,可以显着提高性能。

添加一些属性

dset.attrs['Description'] = 'Some text snippet'
dset.attrs['RowIndexArray'] = np.arange(1000)

存储词典

for k, v in d.items():
    f.create_dataset('dictgroup/'+str(k), data=v)

内存不足

dictionary = f['dictgroup']
res = dictionary['my_key']

没有任何替代方法可以阅读h5py documentation,这会暴露大部分C API,但您应该从上面看到它具有很大的灵活性。

答案 1 :(得分:7)

我同意JPP的说法,hdf5存储在这里是个不错的选择。他和我的解决方案之间的区别在于我使用Pandas数据帧而不是numpy数组。我更喜欢数据框,因为它允许混合类型,多级索引(甚至是日期时间索引,这对我的工作非常重要),以及列标记,这有助于我记住不同数据集的组织方式。此外,熊猫提供了一系列内置功能(非常像numpy)。使用Pandas的另一个好处是它内置了一个hdf创建器(即pandas.DataFrame.to_hdf),我觉得很方便

当将数据帧存储到h5时,您可以选择存储元数据字典,这可以是您自己的注释,也可以是不需要存储在数据帧中的实际元数据(我用它来设置标志)同样,例如{' is_agl':True,' scale_factor':100,'已经校正':False,等等}。在这方面,没有区别在使用numpy数组和数据帧之间。有关完整解决方案,请参阅my original question and solution here.

答案 2 :(得分:4)

实用的方法是将元数据直接嵌入Numpy数组中。优点是,正如您所希望的那样,没有额外的依赖性,并且在代码中使用起来非常简单。 但是,这并不能完全回答您的问题,因为您仍需要一种机制来保存数据,我建议您使用HDF5使用jpp的解决方案。

要在ndarray中包含元数据,the documentation中有一个示例。 您基本上必须继承ndarray并添加字段infometadata或其他任何内容。

它会给出(来自上面链接的代码)

import numpy as np

class ArrayWithInfo(np.ndarray):

    def __new__(cls, input_array, info=None):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type
        obj = np.asarray(input_array).view(cls)
        # add the new attribute to the created instance
        obj.info = info
        # Finally, we must return the newly created object:
        return obj

    def __array_finalize__(self, obj):
        # see InfoArray.__array_finalize__ for comments
        if obj is None: return
        self.info = getattr(obj, 'info', None)

要通过numpy保存数据,您需要重载write功能或使用其他解决方案。

答案 3 :(得分:3)

jpp的答案非常全面,只是想提一下,因为pandas v22实木复合地板是非常方便快捷的选择,与csv几乎没有任何弊端(也许接受咖啡休息)。

read parquet

write parquet

在撰写本文时,您还需要

pip install pyarrow

在添加信息方面,您拥有附加到数据的元数据

import pyarrow as pa
import pyarrow.parquet as pq
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.normal(size=(1000, 10)))

tab = pa.Table.from_pandas(df)

tab = tab.replace_schema_metadata({'here' : 'it is'})

pq.write_table(tab, 'where_is_it.parq')

pq.read_table('where_is_it.parq')
然后产生一个表

Pyarrow table
0: double
1: double
2: double
3: double
4: double
5: double
6: double
7: double
8: double
9: double
__index_level_0__: int64
metadata
--------
{b'here': b'it is'}

要把它带回熊猫:

tab.to_pandas()

答案 4 :(得分:-1)

这是一个有趣的问题,尽管我认为这是非常开放的。

文字摘要
对于包含文字注释的文本片段(如,不是代码而不是数据),我真的不知道你的用例是什么,但我不知道为什么我会偏离使用通常的{{ 1}}

各种数据的小集合
当然,你的with open() as f: ...有效。实际上你正在做的非常类似于创建一个字典,其中包含你要保存的所有东西并且用这个字典腌制它。

有关pickle和npz之间差异的讨论,请参阅here(但主要是npz针对numpy数组进行了优化)。

就个人而言,我说如果你不存储Numpy数组我会使用pickle,甚至实现一个快速npz类,它基本上是一个字典来保存其中的东西,还有一些额外的功能你可能想要。

大型物品的集合
对于我在HDF5格式之前使用的非常大的np.arrays或数据帧。好处是它已经内置到大熊猫中,你可以直接df.to_hdf5()。它确实需要在MyNotes下面 - 安装应该是相当轻松的pip或conda-但直接使用pytables可能是一个更大的痛苦。

同样,这个想法非常相似:你正在创建一个HDFStore,它几乎是一个可以存储(几乎任何)对象的大字典。好处是该格式通过利用类似值的重复以更智能的方式利用空间。当我用它来存储大约2GB的数据帧时,它能够将它减少几乎整整的数量级(~250MB)。

最后一位玩家:pytables
Feather是由Wes McKinney和Hadley Wickham在Apache Arrow框架之上创建的项目,用于以与语言无关的二进制格式保存数据(因此您可以从R和Python中读取)。但是,它仍在开发中,上次我检查时他们并不鼓励将其用于长期存储(因为规范可能会在未来的版本中更改),而不是仅仅用于R和Python之间的通信

他们刚刚在几周前推出了Ursalabs,这将继续发展这一举措和类似举措。

答案 5 :(得分:-1)

你说这个问题的原因是:

  

...它允许我 保存   各种信息,从提醒和待办事项列表,到   有关我如何生成数据的信息,甚至是什么   特定变量的估算方法是

我可以建议一个与Stata提供的范式不同的范例吗?笔记和特征似乎非常有限,仅限于文本。相反,您应该使用Jupyter Notebook进行研究和数据分析项目。它提供了如此丰富的环境来记录您的工作流程,并在您进行分析和研究时捕获细节,想法和想法。它可以很容易地共享,并且可以进行演示。

以下是许多行业和学科的a gallery of interesting Jupyter Notebooks,以展示笔记本电脑的众多功能和用例。它可能会扩展您的视野,而不是试图设计一种方法来将简单的文本片段标记为您的数据。