Pandas的to_hdf出现OverflowError错误

9

我是Python的新手。

我尝试使用to_hdf将一个大的数据框以lz4压缩的形式保存到HDF文件中。

我使用的是Windows 10操作系统,Python 3和Pandas 20.2。

出现了“OverflowError: Python int too large to convert to C long”错误。

机器资源(RAM、CPU、SWAP)都没有接近极限。

之前的帖子讨论了dtype,但以下示例显示存在其他问题,可能与大小有关?

import numpy as np
import pandas as pd


# sample dataframe to be saved, pardon my French 
n=500*1000*1000
df= pd.DataFrame({'col1':[999999999999999999]*n,
                  'col2':['aaaaaaaaaaaaaaaaa']*n,
                  'col3':[999999999999999999]*n,
                  'col4':['aaaaaaaaaaaaaaaaa']*n,
                  'col5':[999999999999999999]*n,
                  'col6':['aaaaaaaaaaaaaaaaa']*n})

# works fine
lim=200*1000*1000
df[:lim].to_hdf('df.h5','table', complib= 'blosc:lz4', mode='w')

# works fine
lim=300*1000*1000
df[:lim].to_hdf('df.h5','table', complib= 'blosc:lz4', mode='w')


# Error
lim=400*1000*1000
df[:lim].to_hdf('df.h5','table', complib= 'blosc:lz4', mode='w')


....
OverflowError: Python int too large to convert to C long

你真的期望订单的整数值为 999999999999999999 吗?还是这只是一个糟糕的例子?如果是前者,使用浮点值会损害精度吗? - user707650
之前的帖子讨论了dtype:这个问题也涉及到dtype,因为那些整数值太大了,无法容纳在4字节整数中。您可能想显示数据框的dtype。 - user707650
1
谢谢Evert的评论。这个例子旨在说明它并不是关于整数值或数据类型。有500M个相同的行。写入300M行的文件可以正常工作。但是,写入400M行就会失败。 - Ron
3个回答

3
正如 @Giovanni Maria Strampelli 指出的那样,@Artem Snorkovenko 的答案只保存了最后一批。Pandas documentation 指出:

为了将另一个 DataFrame 或 Series 添加到现有的 HDF 文件中,请使用追加模式和不同的键。

以下是从 @Artem Snorkovenko 的答案调整后可能的解决方法,以保存 所有 批次:
for i in range(len(df)):
    sr = df.loc[i] #pandas series object for the given index
    sr.to_hdf('df.h5', key='table_%i'%i, complib='blosc:lz4', mode='a')

这段代码将每个 Pandas Series 对象使用不同的键进行保存,每个键都由 i 进行索引。
要在保存后加载现有的 .h5 文件,可以执行以下操作:
i = 0
dfdone = False #if True, all keys in the .h5 file are successfully loaded.
srl = [] #df series object list
while dfdone == False:
    #print(i) #this is to see if code is working properly.
    try: #check whether current i value exists in the keys of the .h5 file
        sdfr = pd.read_hdf('df.h5', key='table_%i'%i) #Current series object
        srl.append(sdfr) #append each series to a list to create the dataframe in the end.
        i += 1 #increment i by 1 after loading the series object
    except: #if an error occurs, current i value exceeds the number of keys, all keys are loaded.
        dfdone = True #Terminate the while loop.

df = pd.DataFrame(srl) #Generate the dataframe from the list of series objects.

我使用了while循环,假设我们不知道.h5文件中dataframe的确切长度。如果已知长度,也可以使用for循环。
请注意,我这里没有将数据框保存在块中。因此,在当前形式下,加载过程不适用于分块保存,其中每个块的数据类型为DataFrame。在我的实现中,每个保存的对象都是Series,并且DataFrame是从Series列表生成的。我提供的代码可以调整为适用于分块保存并从DataFrame对象列表生成DataFrame的情况(可以在ths Stack Overflow entry中找到一个不错的起点)。

3

我也遇到了同样的问题,似乎与数据框的大小有关,而不是dtype(我把所有列都存储为字符串,并能够将它们单独存储为.h5文件)。

对我有用的解决方案是使用mode ='a'将数据框保存为块。

如在pandas文档中建议的那样:mode{'a','w','r+'},默认为'a': 'a':追加,打开一个现有文件进行读写,如果文件不存在则创建文件。

因此,示例代码将类似于:

batch_size = 1000
for i, df_chunk in df.groupby(np.arange(df.shape[0]) // batch_size):
    df_chunk.to_hdf('df.h5','table', complib= 'blosc:lz4', mode='a')

1
嗨,我有一个类似的问题,但是当我尝试这个解决方案时,它只保存了最后一批。这正常吗? - Giovanni Maria Strampelli

1

除了 @tetrisforjeff 的回答之外:

如果 df 包含对象类型,读取可能会导致错误。我建议使用 pd.concat(srl) 而不是 pd.DataFrame(srl)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接