将Pandas数据框作为压缩CSV直接写入到Amazon S3存储桶中?

8

我目前有一个脚本,它可以读取保存在s3上的csv文件的现有版本,将其与pandas数据帧中的新行组合,然后直接将其写回到s3。

    try:
        csv_prev_content = str(s3_resource.Object('bucket-name', ticker_csv_file_name).get()['Body'].read(), 'utf8')
    except:
        csv_prev_content = ''

    csv_output = csv_prev_content + curr_df.to_csv(path_or_buf=None, header=False)
    s3_resource.Object('bucket-name', ticker_csv_file_name).put(Body=csv_output)

有没有一种方法可以使用gzip压缩的csv文件来完成这个操作?如果有,我想读取s3上已经存在的.gz压缩的csv文件,将其与数据框的内容连接起来,然后直接在s3上将新的合并压缩的csv文件覆盖原有的.gz文件,而无需制作本地副本。
3个回答

19

这是一个使用Python 3.5.2和Pandas 0.20.1的解决方案。

源数据可以从S3、本地CSV或其他任何地方读取。

import boto3
import gzip
import pandas as pd
from io import BytesIO, TextIOWrapper

df = pd.read_csv('s3://ramey/test.csv')
gz_buffer = BytesIO()

with gzip.GzipFile(mode='w', fileobj=gz_buffer) as gz_file:
    df.to_csv(TextIOWrapper(gz_file, 'utf8'), index=False)

s3_resource = boto3.resource('s3')
s3_object = s3_resource.Object('ramey', 'new-file.csv.gz')
s3_object.put(Body=gz_buffer.getvalue())

1
对我来说运行良好。有什么想法为什么在写入流时,df.to_csv()中的参数“compression”无法工作? - szu
2
@szu 因为 pandas.io.formats.format.CSVFormatter 是这样实现的。我猜想这个想法是,如果你提供了一个流,你可能会自己设置必要的处理方式...或者开发人员根本不关心提供和测试一个“合理”的实现,而且没有人在迄今为止关心修复它(可悲的是,你现在不能轻松地修复它,否则可能会破坏其他人的代码)。 - KT.

2

有一种更优雅的解决方案,使用smart-open (https://pypi.org/project/smart-open/)

import pandas as pd
from smart_open import open

df.to_csv(open('s3://bucket/prefix/filename.csv.gz','w'),index = False)

如果你将pandas作为pd导入,那么df从哪里来的? :) - Got To Figure

-1
如果您想进行流式写入(以避免在内存中保留(解)压缩的CSV文件),可以执行以下操作:
import s3fs
import io
import gzip

    def write_df_to_s3(df, filename, path):
        s3 = s3fs.S3FileSystem(anon=False)
        with s3.open(path, 'wb') as f:
            gz = gzip.GzipFile(filename, mode='wb', compresslevel=9, fileobj=f)
            buf = io.TextIOWrapper(gz)
            df.to_csv(buf, index=False, encoding='UTF_8')
            gz.flush()
            gz.close()

在此问题得到解决之前,需要使用TextIOWrapper:https://github.com/pandas-dev/pandas/issues/19827


这个答案似乎是可行的,但如果能展示如何调用它会更好。 - Sidney
此外,查看gzip.Gzipfile的文档时,它说要么将filename或fileobj设置为非平凡值(我认为是none)。函数的filename参数是否可以被删除,并且在其位置上调用GzipFile传递None,因为fileobj已经设置为来自s3.open的文件句柄? - Sidney

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