代码之家  ›  专栏  ›  技术社区  ›  user8682794

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

  •  9
  • user8682794  · 技术社区  · 6 年前

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

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

    我现在正试图在Python 3.6中实现类似的功能。到目前为止,我已经在网上查阅了许多帖子,但这些帖子并没有确切说明我想做什么。

    一些参考职位包括:

    对于一个小 NumPy 数组,我的结论是 numpy.savez() 和a 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()
    

    然而,问题仍然存在:

    是否有更好的方法可以在包含 努比 阵列或a(大) Pandas DataFrame ?

    我特别感兴趣的是 专业人士 缺点 你可能会有任何建议的例子。依赖关系越少越好。

    6 回复  |  直到 6 年前
        1
  •  8
  •   jpp    4 年前

    有很多选择。我将只讨论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)
    

    压缩(&A);分块

    有许多压缩选项,例如。 blosc lzf 分别是压缩和解压缩性能的良好选择。笔记 gzip 是本地人;默认情况下,HDF5安装可能不会附带其他压缩过滤器。

    分块是另一种选择,当与从内存中读取数据的方式一致时,它可以显著提高性能。

    添加一些属性

    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,但您应该从上面看到,它具有很大的灵活性。

        2
  •  1
  •   Christian    6 年前

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

    将元数据包括在 ndarray ,中有一个示例 the documentation 。 基本上必须将 恩达雷 并添加字段 info metadata 或者别的什么。

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

    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
  •  0
  •   WillMonge    6 年前

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

    文本片段
    对于有文字注释的文本片段(例如,不是代码也不是数据),我真的不知道您的用例是什么,但我不明白为什么我会偏离使用通常的 with open() as f: ...

    各种数据块的小集合
    当然,你的 npz 作品实际上,您所做的工作非常类似于创建一个包含您想要保存的所有内容的词典,并对该词典进行酸洗。

    看见 here 讨论pickle和npz之间的差异(但主要是npz针对numpy阵列进行了优化)。

    就我个人而言,如果您不存储Numpy数组,我会使用pickle,甚至实现一个快速 MyNotes 类,该类基本上是一个字典,用于保存其中的内容,并提供一些您可能需要的附加功能。

    大型对象的集合
    对于真正的大np。我在HDF5格式之前使用过的数组或数据帧。好的是,它已经内置在熊猫体内,你可以直接 df.to_hdf5() .它确实需要在下面 pytables -使用pip或conda进行安装应该相当轻松,但直接使用pytables可能会带来更大的痛苦。

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

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

    他们俩都刚刚开始 Ursalabs 就在几周前,这将继续推动这一举措和类似举措的发展。

        4
  •  0
  •   floydn    6 年前

    您陈述了此问题的原因:

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

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

    这里是 a gallery of interesting Jupyter Notebooks 跨越多个行业和学科,展示笔记本电脑的众多功能和使用案例。它可能会扩展您的视野,而不仅仅是试图设计一种将简单文本片段标记到数据中的方法。

        5
  •  0
  •   tnknepp    6 年前

    我同意JPP的观点,hdf5存储是一个很好的选择。他的解决方案和我的不同之处在于,我的使用熊猫数据帧,而不是numpy数组。我更喜欢dataframe,因为它允许混合类型、多级索引(甚至datetime索引,这对我的工作非常重要)和列标签,这有助于我记住不同的数据集是如何组织的。此外,Pandas还提供了一系列内置功能(很像numpy)。使用Pandas的另一个好处是它内置了hdf创建者(即Pandas.DataFrame.to\u hdf),我觉得这很方便

    将数据帧存储到h5时,您可以选择存储元数据字典,它可以是您的自我注释,或者不需要存储在数据帧中的实际元数据(我也使用它来设置标志,例如{'is\u agl':True,'scale\u factor':100,'ready\u corrected':False等)。在这方面,使用numpy数组和数据帧之间没有区别。有关完整的解决方案,请参阅 my original question and solution here.

        6
  •  0
  •   Darren Brien    6 年前

    jpp的回答相当全面,只是想提到,对于熊猫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()