Dataframe을 csv에 s3 Python에 직접 저장


125

새 CSV 파일에 업로드하려는 pandas DataFrame이 있습니다. 문제는 파일을 s3로 전송하기 전에 로컬에 저장하고 싶지 않다는 것입니다. 데이터 프레임을 s3에 직접 쓰는 to_csv와 같은 방법이 있습니까? boto3를 사용하고 있습니다.
지금까지 내가 가지고있는 것은 다음과 같습니다.

import boto3
s3 = boto3.client('s3', aws_access_key_id='key', aws_secret_access_key='secret_key')
read_file = s3.get_object(Bucket, Key)
df = pd.read_csv(read_file['Body'])

# Make alterations to DataFrame

# Then export DataFrame to CSV through direct transfer to s3

3
df.to_csv('s3://mybucket/dfs/somedf.csv'). 자세한 정보는 stackoverflow.com/a/56275519/908886 을 참조하십시오.
Peter Berg

답변:


158

당신이 사용할 수있는:

from io import StringIO # python3; python2: BytesIO 
import boto3

bucket = 'my_bucket_name' # already created on S3
csv_buffer = StringIO()
df.to_csv(csv_buffer)
s3_resource = boto3.resource('s3')
s3_resource.Object(bucket, 'df.csv').put(Body=csv_buffer.getvalue())

9
대용량 파일 인 경우 메모리에 어떤 영향을 미칩니 까 ...?
citynorman

2
파일이 더 크면 사용 가능한 RAM이 더 커지면 작업이 실패하고 예외가 발생합니다 (어떤 예외가 있는지 알 수 없음). 이것은 답으로 인정해야한다
에 란 모세를

5
TypeError: unicode argument expected, got 'str'사용하는 동안 오류 가 발생했습니다 StringIO. 나는 사용 BytesIO했고 완벽하게 잘 작동했습니다. 참고 : 이것은 Python 2.7에있었습니다
Abhishek Upadhyaya

1
bucket개체 는 무엇 입니까? 어떻게 만들었습니까?
Charles Chow

1
bucketS3에 객체를 저장하는 곳입니다. 코드는 이것을 저장할 대상 (예 : 디렉토리)을 이미 만들었다 고 가정합니다. S3 문서
Stefan 19

65

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

릴리스 노트:

S3 파일 처리

pandas는 이제 S3 연결을 처리하기 위해 s3fs를 사용합니다. 이것은 어떤 코드도 깨서는 안됩니다. 그러나 s3fs는 필수 종속성이 아니므로 이전 버전의 pandas에있는 boto처럼 별도로 설치해야합니다. GH11915 .


7
이것은 확실히 가장 쉬운 대답입니다. s3fs를 백그라운드에서 사용하므로 requirements.txt에 추가해야합니다.
JD D

1
나는 그것이 쉬운 것을 좋아하지만 다음과 같은 오류가 계속 발생하기 때문에 실제로 작동하지 않는 것 같습니다 NoCredentialsError: Unable to locate credentials. 어떤 제안?
CathyQian

1
나는 0.24 확인 팬더로 업그레이드 할 수 있으므로,이 팬더 <= 0.23.4와 작업을하지 않는 확인할 수 있습니다
귀도에게

1
이것은 내가 to_csv 명령을 사용하려고 할 때 표시되는 오류입니다 TypeError : write () 인수 1은 str이 아닌 유니 코드 여야합니다
Raj

13
나는 pandas 0.24.2를 사용하고 있는데 내가 얻는 것은 NotImplementedError: Text mode not supported, use mode='wb' and manage bytes. 어떤 제안?
Binyamin Even

57

나는 s3를 (거의) 로컬 파일 시스템처럼 사용할 수있는 s3fs 를 좋아한다.

다음과 같이 할 수 있습니다.

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)

s3fsrbwb파일 열기 모드 만 지원하기 때문에이 bytes_to_write작업을 수행했습니다.


큰! 동일한 s3fs 모듈을 사용하여 파일 URL을 어떻게 얻을 수 있습니까?
M.Zaman 2017-10-13

작성된 파일을 다운로드 할 수있는 URL을 찾고 있었는데, 어쨌든 S3FileSystem을 통해 얻었습니다. 감사합니다
M.Zaman

이것이 내가 사용하는 것입니다. 감사. pd.read_csv (<s3path>)가 예상대로 작동하는 이유가 궁금하지만 작성을 위해이 해결 방법을 사용해야합니다. .. 내 jupyter가있는 s3 버킷에 직접 쓰는 경우를 제외하고.
Renée

@ michcio1234 추가 모드에서 어떻게 똑같이 할 수 있습니까? s3의 기존 csv에 데이터를 추가해야합니다
j '

@j ' s3fs는 추가 모드를 지원하지 않는 것 같습니다.
michcio1234

43

이것은 최신 답변입니다.

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에 기록합니다. 팬더 데이터 프레임과 문자열 사본을 메모리에 보관하는 것은 매우 비효율적 인 것 같습니다.

ec2 인스턴트로 작업하는 경우 s3에 쓸 수 있도록 IAM 역할을 부여 할 수 있으므로 자격 증명을 직접 전달할 필요가 없습니다. 그러나 S3FileSystem()함수에 자격 증명을 전달하여 버킷에 연결할 수도 있습니다 . 문서 참조 : https://s3fs.readthedocs.io/en/latest/


어떤 이유로 내가 이것을 할 때 출력 CSV에서 모든 줄을 건너 뛰었습니다
kjmerf

흠. 왜 그런지 모르겠습니다. 아마도 다른 pandas df로 시도하여 여전히 문제가 발생하는지 확인 하시겠습니까? 사용중인 pandas 버전에서 지원하는 경우 @ amit-kushwaha의 답변을 시도하여 s3 URL을 to_csv(). 더 깨끗한 구현처럼 보입니다.
erncyp

@erncyp 오류가 발생하는 것 같습니다. botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied ... 버킷을 PUBLIC READ로 설정했으며 버킷 정책에서 내 특정 계정 IAM 사용자 아래에 다음 작업을 추가했습니다."Action": [ "s3:PutObject", "s3:PutObjectAcl", "s3:GetObject", "s3:GetObjectAcl", "s3:DeleteObject" ]
ajoros

권한이 부족한 것 같습니까? 사용중인 IAM 역할에 S3 읽기 쓰기 권한을 연결해야합니다.
erncyp

@erncyp IAM 사용자에게 AdministratorAccess 정책이 연결되어 있으므로 이론적으로는 잘 읽고 쓸 수 있어야합니다. 이상하게도 다른 StackOverflow 사용자를 사용하여 만든 다음 함수를 사용하면 잘 쓸 수 있습니다. 조언 (나는 코멘트 섹션에서 형식을 지정하는 방법을 모르기 때문에 fyi 세미콜론은 줄의 끝입니다) :def send_to_bucket(df, fn_out, bucketname): csv_buffer = StringIO(); df.to_csv(csv_buffer); s3_resource = boto3.resource('s3'); s3_resource.Object(bucketname, fn_out).put(Body=csv_buffer.getvalue());
ajoros

13

None첫 번째 인수로 전달 to_csv()하면 데이터가 문자열로 반환됩니다. 거기에서 한 번에 S3에 쉽게 업로드 할 수 있습니다.

StringIO객체를 에 전달할 수도 to_csv()있지만 문자열을 사용하는 것이 더 쉽습니다.


어느 쪽이 더 쉬울까요? 올바른 방법은 무엇입니까?
Eran Moshe

@EranMoshe는 : 어느 쪽이 제대로 작동하지만 분명히 통과하기 쉽게 Noneto_csv()하고 그것이 생성하는 것보다 반환 된 문자열을 사용하여 StringIO객체를 한 후 데이터를 철회 읽어 보시기 바랍니다.
mhawke

게으른 프로그래머로서 그게 내가 한 일입니다. > : 그리고 당신은 더 적은 코드를 작성 프로그래머 쉽게 의미
에 란 모세

2

AWS Data Wrangler를 사용할 수도 있습니다 .

import awswrangler

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

병렬로 업로드하므로 여러 부분으로 나뉩니다.


2

나는 이것을 사용하여 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')

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

-1

작동하는 것처럼 보이는 매우 간단한 해결책을 찾았습니다.

s3 = boto3.client("s3")

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

도움이 되길 바랍니다!


-5

버킷 s3에서 두 개의 열이있는 csv와 pandas 데이터 프레임에 넣은 csv 파일의 내용을 읽었습니다.

예:

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

4
솔루션을 게시하지 말고 설명도 추가하십시오.
sjaustirni

그런 복잡한 (파이썬 초보자를위한) 솔루션을 만드는 데 어떤 이점이 있습니까?
Javier López Tomás 2019 년

1
이것은 s3에서 파일을 읽습니다. 문제는 s3에 df를 쓰는 방법이었습니다.
Damian Satterthwaite-Phillips
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.