如何在 pandas 中将新类别附加到 HDF5?

Posted

技术标签:

【中文标题】如何在 pandas 中将新类别附加到 HDF5?【英文标题】:How to append new categories to HDF5 in pandas? 【发布时间】:2018-02-26 13:20:05 【问题描述】:

已回答:看来此数据类型不适合添加 任意字符串到 hdf5store。

背景

我使用一个脚本来生成单行结果,并以迭代的方式将它们附加到磁盘上的文件中。为了加快速度,我决定使用 HDF5 容器而不是 .csv。 A benchmarking 然后透露字符串会减慢 HDF5 的速度。我是told 这可以在将字符串转换为categorical dtype 时得到缓解。

问题

我无法将分类行添加新类别到 HDF5。另外,我不知道如何控制cat.codes 的dtypes,AFAIK 可以以某种方式完成。

可重现的例子:

1 - 使用分类数据创建大型数据框

import pandas as pd
import numpy as np
from pandas import HDFStore, DataFrame
import random, string

dummy_data = [''.join(random.sample(string.ascii_uppercase, 5)) for i in range(100000)]
df_big = pd.DataFrame(dummy_data, columns = ['Dummy_Data'])
df_big['Dummy_Data'] = df_big['Dummy_Data'].astype('category')

2 - 创建一行以追加

df_small = pd.DataFrame(['New_category'], columns = ['Dummy_Data'])
df_small['Dummy_Data'] = df_small['Dummy_Data'].astype('category')

3 - 将 (1) 保存到 HDF 并尝试附加 (2)

df_big.to_hdf('h5_file.h5', \
      'symbols_dict', format = "table", data_columns = True, append = False, \
       complevel = 9, complib ='blosc')

df_small.to_hdf('h5_file.h5', \
      'symbols_dict', format = "table", data_columns = True, append = True, \
       complevel = 9, complib ='blosc')

这会导致以下异常

ValueError: 附加数据时 [values_axes] 的无效组合 [name->Dummy_Data,cname->Dummy_Data,dtype->int8,kind->integer,shape->(1,)] 与当前表 [name->Dummy_Data,cname->Dummy_Data,dtype->int32,kind->integer,shape->None]

我的修复尝试

我尝试调整cat.catcodes的dtypes:

df_big['Dummy_Data'] = df_big['Dummy_Data'].cat.codes.astype('int32')
df_small['Dummy_Data'] = df_small['Dummy_Data'].cat.codes.astype('int32')

当我这样做时,错误消失了,但分类 dtype 也消失了:

df_test = pd.read_hdf('h5_file.h5', key='symbols_dict')
print df_mydict.info()

<class 'pandas.core.frame.DataFrame'>
Int64Index: 100001 entries, 0 to 0       # The appending worked now
Data columns (total 1 columns):
Dummy_Data    100001 non-null int32      # Categorical dtype gone
dtypes: int32(1)                         # I need to change dtype of cat.codes of categorical    
memory usage: 1.1 MB                     # Not of categorical itself

另外,df_small.info()一开始没有显示cat.codes的dtype,调试起来很困难。我做错了什么?

问题

1.如何正确更改cat.codes的dtypes? 2. 如何在python中正确地将分类数据附加到HDF5?

【问题讨论】:

请参阅***.com/a/37054761/4893407 了解有关熊猫 HDF 中分类的 cmets。 【参考方案1】:

我不是这方面的专家,但就我至少查看 h5py 模块 http://docs.h5py.org/en/latest/high/dataset.html 而言,HDF5 支持 Numpy 数据类型,它不包括任何分类数据类型。

PyTables 也是如此,它被 Pandas 使用。

Categories 数据类型在Pandas datatypes 中引入和使用,并进行了描述:

分类变量具有有限,并且通常是固定,可能值的数量(类别;R 中的级别)

那么可能发生的情况是,每次添加新类别时,您都必须以某种方式从 hdf5store 重新读取所有现有类别,以便 Pandas 重新索引它?

但是,从一般文档来看,这种数据类型似乎适合将任意字符串添加到 hdf5store,除非您确定在添加了几次之后不会有新的类别.

另外说明,除非您的应用程序需要极高的性能,否则将数据存储在 SQL 中可能是更好的选择——一方面,SQL 对字符串有更好的支持。例如,虽然在某些test 中发现 SQLite 比 HDF5 慢,但它们不包括处理字符串。从 CSV 跳到 HDF5 听起来就像从马车跳到火箭,但也许汽车或飞机也能发挥同样的作用(或者更好,因为它有更多的选择,延伸类比)?

【讨论】:

实际上,读取从 hdf5 到 pandas 的所有当前类别,然后进行后续连接,然后覆盖 hdf5 存储是一种临时解决方法。一旦存储大于 RAM,这当然会达到极限。为答案 +1。 @sudonym 这似乎支持了熊猫中的所有类别都必须事先知道的观点。【参考方案2】:

如果对你有帮助,我会重写你代码的开头。它对我有用。

import pandas as pd
from pandas import HDFStore, DataFrame
import random, string


def create_dummy(nb_iteration):

    dummy_data = [''.join(random.sample(string.ascii_uppercase, 5)) for i in range(nb_iteration)]
    df = pd.DataFrame(dummy_data, columns = ['Dummy_Data'])

    return df

df_small= create_dummy(53)
df_big= create_dummy(100000)

df_big.to_hdf('h5_file.h5', \
  'symbols_dict', format = "table", data_columns = True, append = False, \
  complevel = 9, complib ='blosc')

df_small.to_hdf('h5_file.h5', \
  'symbols_dict', format = "table", data_columns = True, append = True, \
  complevel = 9, complib ='blosc')

df_test = pd.read_hdf('test_def.h5', key='table')
df_test

【讨论】:

这是有效的,因为您的 df_small 中的类别不是新的 - 向 df_small 添加 1 个六字母字符串,您会看到 也就是说,df_small 只有一行。如果添加超过 128 行,cat.codes 的 dtype 将更改为 int32 并且它会起作用 - 但是,问题是关于添加新类别(仅限)

以上是关于如何在 pandas 中将新类别附加到 HDF5?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 R 中将保存在 pandas 中的数据框作为 HDF5 文件加载?

使用 Pandas、Python 将数据附加到 HDF5 文件

在熊猫中将可变长度列表保存到 HDF5

如何有效地将数据附加到 C 中的 HDF5 表?

如何在从 python 触发的电子邮件中将 pandas 数据框附加为 excel

在 python pandas 中将级别附加到列索引