将Pandas DataFrame作为Pickle写入S3

问题描述

这是我的要求。

  • 将熊猫数据框作为泡菜文件上传到AWS S3
  • 由于环境原因,必须使用boto3,并且不能选择s3fs之类的选择
  • 数据必须存在于内存中,并且无法写入临时文件

我创建了以下简单函数,将Pandas数据帧作为csv上传到s3:

def df_to_s3_csv(df,filename,sep=','):
    s3 = boto3.resource('s3')
    buffer = io.StringIO()
    df.to_csv(buffer,sep=sep,index=False)
    s3.Object(s3bucket,f'{s3_upload_path}/{filename}').put(Body=buffer.getvalue())

此功能可以正常工作,并且可以完成预期的工作。对于泡菜文件,我以类似的方式创建了以下函数:

def df_to_s3_pckl(df,filename):
    s3 = boto3.resource('s3')
    buffer = io.BytesIO()
    df.to_pickle(buffer)
    buffer.seek(0)
    obj = s3.Object(s3bucket,f'{s3_upload_path}/{filename}')
    obj.put(Body=buffer.getvalue())

我尝试使用带有和不带有seek部分的函数,并且无论哪种方式都会引发以下错误:ValueError: I/O operation on closed file.

进一步研究该问题,发现buffer一被调用就被认为closed。可以通过发出以下命令来重现这一点:

df.to_pickle

以上打印buffer = io.BytesIO() df.to_pickle(buffer) print(buffer.closed) 。看来True缓冲区已被BytesIO关闭,因此无法引用其数据。如何解决此问题,或者有其他替代方案可以满足我的要求?我在SO上发现了几个有关如何使用boto3上载到S3的问题,但是没有关于如何使用BytesIO缓冲区上载由熊猫创建的泡菜文件的问题。

以下是该基本问题的可重现示例:

to_pickle

解决方法

看来该问题可以追溯到the pandas source code。最终,这可能是由于BytesIO方法中意外使用to_pickle对象而导致的熊猫中的错误。我使用以下代码设法在最小的可重现示例中解决了这个问题,该代码使用了dump模块中的pickle方法:

import pandas as pd
import numpy as np
import io
from pickle import dump
df = pd.DataFrame(np.random.randint(0,100,size=(4,4)))
buffer = io.BytesIO()
dump(df,buffer)
buffer.seek(0)
print(buffer.closed)

现在,打印语句将打印False,并且可以访问BytesIO流数据。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...