【问题标题】:Write pandas dataframe as compressed CSV directly to Amazon s3 bucket?将 Pandas 数据帧作为压缩 CSV 直接写入 Amazon s3 存储桶?
【发布时间】:2017-09-29 11:10:50
【问题描述】:

我目前有一个脚本,它读取保存到 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 制作本地副本。

【问题讨论】:

    标签: python csv pandas amazon-web-services amazon-s3


    【解决方案1】:

    有一个更优雅的解决方案使用 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)
    

    【讨论】:

      【解决方案2】:

      如果您想要流式写入(不在内存中保存(解)压缩的 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

      【讨论】:

      • 这个答案似乎有效,但可以通过展示如何调用它来改进它。
      • 此外,查看 gzip.Gzipfile 的文档,它说 filename 或 fileobj neec 需要设置为一个不平凡的值(我假设没有)。是否可以删除函数的文件名参数,并且对 GzipFile 的调用在其位置传递 None,因为 fileobj 设置为来自 s3.open 的文件手?
      【解决方案3】:

      这是 Python 3.5.2 中使用 Pandas 0.20.1 的解决方案。

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

      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())
      

      【讨论】:

      • 对我来说很好。任何想法为什么在写入流时参数“压缩”在 df.to_csv() 中不起作用?
      • @szu 因为 pandas.io.formats.format.CSVFormatter 就是这样实现的。我认为这个想法是,如果你提供一个流,你不妨自己设置必要的处理......或者开发人员根本不关心在那里提供和测试一个“明智的”实现,没有人关心到目前为止修复这个问题(可悲的是,你现在不能轻易地修复它而不会破坏其他人的代码)。
      猜你喜欢
      • 2020-07-29
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 2015-07-17
      • 2020-08-11
      • 1970-01-01
      • 2023-03-14
      • 2022-01-23
      相关资源
      最近更新 更多