将数据帧直接保存到csv到s3 Python

时间:2016-07-01 21:23:51

标签: python csv amazon-s3 dataframe boto3

我有一个pandas DataFrame,我想上传到新的CSV文件。问题是我不想在将文件传输到s3之前将其保存在本地。是否有像to_csv这样的方法直接将数据帧写入s3?我正在使用boto3 以下是我到目前为止的情况:

Unable to initialize the shader program:
C:\fakepath(72,30-133): error X3507: '_directionToColor':
  Not all control paths return a value

12 个答案:

答案 0 :(得分:62)

您可以使用:

from io import StringIO
import boto3

csv_buffer = StringIO()
df.to_csv(csv_buffer)
s3_resource = boto3.resource('s3')
s3_resource.Object(bucket, 'df.csv').put(Body=csv_buffer.getvalue())

答案 1 :(得分:35)

我喜欢s3fs,它允许您使用s3(几乎)像本地文件系统。

你可以这样做:

import s3fs

bytes_to_write = df.to_csv(None).encode()
fs = s3fs.S3FileSystem(key=key, secret=secret)
with fs.open('s3://bucket/path/to/file.csv', 'wb') as f:
    f.write(bytes_to_write)

s3fs仅支持rbwb打开文件的模式,这就是我执行此bytes_to_write内容的原因。

答案 2 :(得分:17)

这是最新的答案:

import s3fs

s3 = s3fs.S3FileSystem(anon=False)

# Use 'w' for py3, 'wb' for py2
with s3.open('<bucket-name>/<filename>.csv','w') as f:
    df.to_csv(f)

StringIO的问题在于它将吞噬您的内存。使用此方法,您将文件流式传输到s3,而不是将其转换为字符串,然后将其写入s3。将pandas数据框及其字符串副本保存在内存中似乎效率很低。

如果您在ec2即时环境中工作,则可以为其赋予IAM角色以将其写入s3,因此您无需直接传递凭据。但是,您也可以通过将凭据传递到S3FileSystem()函数来连接到存储桶。查看文档:{​​{3}}

答案 3 :(得分:11)

如果将None作为第一个参数传递给to_csv(),数据将作为字符串返回。从那里可以轻松地将其一次性上传到S3。

还应该可以将StringIO对象传递给to_csv(),但使用字符串会更容易。

答案 4 :(得分:4)

我发现也可以使用client来完成此操作,而不仅仅是resource

from io import StringIO
import boto3
s3 = boto3.client("s3",\
                  region_name=region_name,\
                  aws_access_key_id=aws_access_key_id,\
                  aws_secret_access_key=aws_secret_access_key)
csv_buf = StringIO()
df.to_csv(csv_buf, header=True, index=False)
csv_buf.seek(0)
s3.put_object(Bucket=bucket, Body=csv_buf.getvalue(), Key='path/test.csv')

答案 5 :(得分:2)

我使用 AWS Data Wrangler。例如:

import awswrangler as wr
import pandas as pd

# read a local dataframe
df = pd.read_parquet('my_local_file.gz')

# upload to S3 bucket
wr.s3.to_parquet(df=df, path='s3://mys3bucket/file_name.gz')

这同样适用于 csv 文件。使用具有正确文件扩展名的 read_parquetto_parquet,而不是 read_csvto_csv

答案 6 :(得分:0)

我从存储桶s3读取了一个带有两列的csv,并且将文件csv的内容放入pandas数据帧中。

示例:

config.json

{
  "credential": {
    "access_key":"xxxxxx",
    "secret_key":"xxxxxx"
}
,
"s3":{
       "bucket":"mybucket",
       "key":"csv/user.csv"
   }
}

cls_config.json

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import json

class cls_config(object):

    def __init__(self,filename):

        self.filename = filename


    def getConfig(self):

        fileName = os.path.join(os.path.dirname(__file__), self.filename)
        with open(fileName) as f:
        config = json.load(f)
        return config

cls_pandas.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pandas as pd
import io

class cls_pandas(object):

    def __init__(self):
        pass

    def read(self,stream):

        df = pd.read_csv(io.StringIO(stream), sep = ",")
        return df

cls_s3.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3
import json

class cls_s3(object):

    def  __init__(self,access_key,secret_key):

        self.s3 = boto3.client('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key)

    def getObject(self,bucket,key):

        read_file = self.s3.get_object(Bucket=bucket, Key=key)
        body = read_file['Body'].read().decode('utf-8')
        return body

test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from cls_config import *
from cls_s3 import *
from cls_pandas import *

class test(object):

    def __init__(self):
        self.conf = cls_config('config.json')

    def process(self):

        conf = self.conf.getConfig()

        bucket = conf['s3']['bucket']
        key = conf['s3']['key']

        access_key = conf['credential']['access_key']
        secret_key = conf['credential']['secret_key']

        s3 = cls_s3(access_key,secret_key)
        ob = s3.getObject(bucket,key)

        pa = cls_pandas()
        df = pa.read(ob)

        print df

if __name__ == '__main__':
    test = test()
    test.process()

答案 7 :(得分:0)

您可以直接使用S3路径。我正在使用Pandas 0.24.1

In [1]: import pandas as pd

In [2]: df = pd.DataFrame( [ [1, 1, 1], [2, 2, 2] ], columns=['a', 'b', 'c'])

In [3]: df
Out[3]:
   a  b  c
0  1  1  1
1  2  2  2

In [4]: df.to_csv('s3://experimental/playground/temp_csv/dummy.csv', index=False)

In [5]: pd.__version__
Out[5]: '0.24.1'

In [6]: new_df = pd.read_csv('s3://experimental/playground/temp_csv/dummy.csv')

In [7]: new_df
Out[7]:
   a  b  c
0  1  1  1
1  2  2  2

  

注意:对于0.20.3版的熊猫,使用S3路径无效

FileNotFoundError: [Errno 2] No such file or directory: 's3://experimental/playground/temp_csv/dummy.csv'

一个人可以查看该功能的确切发布版本。

答案 8 :(得分:0)

由于您使用的是boto3.client(),请尝试:

import boto3
from io import StringIO #python3 
s3 = boto3.client('s3', aws_access_key_id='key', aws_secret_access_key='secret_key')
def copy_to_s3(client, df, bucket, filepath):
    csv_buf = StringIO()
    df.to_csv(csv_buf, header=True, index=False)
    csv_buf.seek(0)
    client.put_object(Bucket=bucket, Body=csv_buf.getvalue(), Key=filepath)
    print(f'Copy {df.shape[0]} rows to S3 Bucket {bucket} at {filepath}, Done!')

copy_to_s3(client=s3, df=df_to_upload, bucket='abc', filepath='def/test.csv')

答案 9 :(得分:0)

您也可以使用AWS Data Wrangler

import awswrangler

session = awswrangler.Session()
session.pandas.to_csv(
    dataframe=df,
    path="s3://...",
)

请注意,由于它是并行上传的,因此将分为几部分。

答案 10 :(得分:-1)

    import boto3

    s3_client = boto3.client('s3',aws_access_key_id="AccessKey",aws_secret_access_key="Secretkey")

    head_response = s3_client.head_object(Bucket='YourBucket',Key='YourPath')

    if head_response['HTTPStatusCode'] == 200:
          Your operation if file exsits

答案 11 :(得分:-2)

我找到了一个似乎很有效的简单解决方案:

s3 = boto3.client("s3")

s3.put_object(
    Body=open("filename.csv").read(),
    Bucket="your-bucket",
    Key="your-key"
)

希望有帮助!