【问题标题】:HDFStore get column namesHDFStore 获取列名
【发布时间】:2018-08-30 06:51:14
【问题描述】:

我对 pandas 的 HDFStore 速度太慢有一些问题,不幸的是我无法从这里的其他问题中找到令人满意的解决方案。

情况

我有一个大 DataFrame,主要包含浮点数,有时包含整数列,这些列经过多个处理步骤(重命名、删除错误条目、聚合 30 分钟)。每行都有一个与之关联的时间戳。我想将一些中间步骤保存到 HDF 文件中,以便用户可以迭代地执行单个步骤,而无需每次都从头开始。

此外,用户应该能够从这些保存中绘制某些列,以便选择不良数据。因此,我想只检索列名而不读取 HDFStore 中的数据。 具体来说,用户应该获得存储在 HDF 中的所有数据帧的所有列的列表,然后他们应该选择他们想要查看的列,然后我使用 matplotlib 向他们展示相应的数据。

数据

shape == (5730000, 339) 看起来一点也不大,这就是我感到困惑的原因......(随着时间的推移可能会有更多的行,列应该保持固定) 在第一步中,我迭代地追加行和列(运行正常),但一旦完成,我总是一次处理整个 DataFrame,只对数据进行分组或删除。

我的方法

  1. 我在内存中进行所有操作,因为 pandas 似乎相当快而 I/O 速度较慢(我认为 HDF 位于不同的物理服务器上)
  2. 我使用日期时间索引并自动选择浮点或整数列
  3. 我使用hdf.put('/name', df, format='fixed') 保存步骤,因为hdf.put('/name'.format(grp), df, format='table', data_columns=True) 似乎太慢了。
  4. 我使用例如df.groupby(df.index).first()df.groupby(pd.Grouper(freq='30Min')).agg(agg_dict) 处理数据,其中 agg_dict 是每列一个函数的字典。这也非常慢。
  5. 为了绘图,我必须读入整个数据框,然后获取列:hdfstore.get('/name').columns

问题

  • 如何在不从 HDFStore 读取任何数据的情况下检索所有列?
  • 存储数据最有效的方法是什么? HDF 是正确的选择吗?桌子还是固定的?
  • 如果索引是日期时间索引,在效率方面是否重要?一般是否存在更有效的格式(例如,所有列都相同、固定 dtype?)
  • 有没有比groupby (df.groupby(pd.Grouper(freq='30Min')).agg(agg_dict)) 更快的聚合方式

类似问题

How to access single columns using .select 我发现我只能使用它来检索某些列,但我认为只有在我知道列名之后才能检索。

感谢您的建议!

【问题讨论】:

  • 关于更快的聚合方式:既然您有DatetimeIndex,您是否尝试过df.resample('30T').agg(agg_dict)
  • 感谢您的意见!它的速度似乎大致相同,但.groupby 似乎更灵活(例如,我也可以使用.apply 而不是.agg 以获得更进化的聚合)。
  • 没问题。在pandas 的最新版本中,当您拥有DatetimeIndex 时,.resample() 方法的工作方式更像groupby;你甚至可以做df.resample().apply()。请参阅docs 了解更多信息。

标签: python pandas dataframe hdfstore


【解决方案1】:

对于 HDFStore hdfkey(来自 hdf.keys()),您可以通过以下方式获取列名:

# Table stored with hdf.put(..., format='table')
columns = hdf.get_node('{}/table'.format(key)).description._v_names

# Table stored with hdf.put(..., format='fixed')
columns = list(hdf.get_node('{}/axis0'.format(key)).read().astype(str))

注意hdf.get(key).columns 也可以,但是它将所有数据读入内存,而上面的方法只读取列名。


完整的工作示例:

#!/usr/bin/env python
import pandas as pd

data = pd.DataFrame({'a': [1,1,1,2,3,4,5], 'b': [2,3,4,1,3,2,1]})

with pd.HDFStore(path='store.h5', mode='a') as hdf:
    hdf.put('/DATA/fixed_store', data, format='fixed')
    hdf.put('/DATA/table_store', data, format='table', data_columns=True)
    for key in hdf.keys():
        try:
            # column names of table store
            print(hdf.get_node('{}/table'.format(key)).description._v_names)
        except AttributeError:
            try:
                # column names of fixed store
                print(list(hdf.get_node('{}/axis0'.format(key)).read().astype(str)))
            except AttributeError:
                # e.g. a dataset created by h5py instead of pandas.
                print('unknown node in HDF.')

【讨论】:

    【解决方案2】:

    您可以通过指定相同的startstop 属性来简单地加载0 行DataFrame。并将所有内部索引/列处理留给 pandas 本身:

    idx = pd.MultiIndex.from_product([('A', 'B'), range(2)], names=('Alpha', 'Int'))
    df = pd.DataFrame(np.random.randn(len(idx), 3), index=idx, columns=('I', 'II', 'III'))
    df
    
    >>>                 I           II          III
    >>> Alpha   Int             
    >>>     A     0     -0.472412    0.436486    0.354592
    >>>           1     -0.095776   -0.598585   -0.847514
    >>>     B     0      0.107897    1.236039   -0.196927
    >>>           1     -0.154014    0.821511    0.092220
    

    以下适用于fixedtable 格式:

    with pd.HDFStore('test.h5') as store:
        store.put('df', df, format='f')
        meta = store.select('df', start=1, stop=1)
        meta
        meta.index
        meta.columns
    
    >>>               I     II    III
    >>> Alpha   Int             
    >>>
    >>> MultiIndex(levels=[[], []],
    >>>            codes=[[], []],
    >>>            names=['Alpha', 'Int'])
    >>>
    >>> Index(['I', 'II', 'III'], dtype='object')
    

    至于其他问题:

    1. 只要您的数据大部分是同质的(几乎是您提到的浮动列)并且您能够将其存储在单个文件中,而无需跨机器分发数据 - 首先要尝试 HDF。
    2. 如果您需要追加/删除/查询数据 - 您必须使用table 格式。如果您只需要一次写入并多次读取 - fixed 将提高性能。
    3. 至于日期时间索引,我想在这里我们可以使用与 1 子句中相同的想法。如果您能够将所有数据转换为单一类型,它应该会提高您的性能。
    4. 没有想到其他在评论您的问题时提出的建议。

    【讨论】:

      【解决方案3】:
      1. 未读取任何数据的列:
      store.get_storer('df').ncols # substitute 'df' with your key
      # you can also access nrows and other useful fields
      
      1. 来自文档(fixed formattable format):(重点以粗体表示)

      [已修复] 这些类型的商店在编写后不可追加(尽管您可以简单地删除它们并重新编写)。 它们也不是可查询的;必须完整地检索它们。它们也不支持具有非唯一列名的数据框。与表格存储相比,固定格式存储提供非常快的写入和稍快的读取。

      [table] 从概念上讲,表格的形状非常像 DataFrame,有行和列。表可以附加到相同或其他会话中。此外,还支持删除和查询类型的操作

      1. 您可以尝试使用纪元(或纪元)(自纪元以来的毫秒或纳秒)代替日期时间。这样,您只需处理整数索引。

      2. 如果您需要对大数据进行分组,您可以查看this answer


      一个建议:如果您有 4 个问题要问,最好就 SO 提出 4 个单独的问题。这样,您将获得更多(更高质量)的答案,因为每个答案都更容易解决。每个人都会处理一个特定的主题,从而更容易搜索正在寻找特定答案的人。

      【讨论】:

        猜你喜欢
        • 2015-04-30
        • 2018-10-07
        • 2011-03-21
        • 2013-07-13
        • 2014-12-09
        • 2015-06-12
        • 2014-11-14
        相关资源
        最近更新 更多