データフレームを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 2018年

2
ファイルが大きい場合、使用可能なRAMは失敗し、例外を除きます(どれがわからないか)。これは答えとして受け入れられるべき
エランモシェを

5
の使用中にTypeError: unicode argument expected, got 'str'エラーが発生しましたStringIO。私が使用しBytesIO、それは完全にうまくいきました。注:これはPython 2.7の
バージョン

1
bucketオブジェクトとは何ですか?どうやってそれを作ったの?
Charles Chow

1
bucketS3のオブジェクトを保存する場所です。コードは、これを保存する宛先(think:ディレクトリ)がすでに作成されていることを前提としています。S3ドキュメントを
Stefan

65

S3パスを直接使用できます。私はパンダ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は必須の依存関係ではないため、以前のバージョンのパンダのbotoのように、個別にインストールする必要があります。GH11915


7
これはあなたのrequirements.txtにそれを追加する必要があるので、それはs3fs舞台裏使用して、最も簡単な答えは今、間違いなくある
JD D

1
私はそれが簡単なのが好きですが、次のエラーが発生し続けるので、実際には機能していないようNoCredentialsError: Unable to locate credentialsです。助言がありますか?
CathyQian

1
これが0.23.4以下のパンダでは機能しないことが確認できたので、パンダ0.24にアップグレードしてください
Guido

1
これは、to_csvコマンドを使用しようとしたときに表示されるエラーですTypeError:write()引数1はstrではなくUnicodeである必要があります
Raj

13
私は0.24.2パンダ使用していると私はあるものを手に入れますNotImplementedError: Text mode not supported, use mode='wb' and manage bytes。助言がありますか?
Binyamin

57

私は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を実行しました。


すごい!同じs3fsモジュールを使用してファイルのURLを取得するにはどうすればよいですか?
M.Zaman 2017年

書き込んだファイルをダウンロードできるURLを探していましたが、とにかくS3FileSystemから取得しました。ありがとう
M.Zaman

これは私が使用するものです。ありがとう。。私は、なぜpd.read_csv(<s3path>)期待通りに動作しますが、書き込みのために私たちがしている私はS3バケット私jupyterに直接書いていた場合を除き..周りにこの作品を使用する必要が好奇心
ルネ

@ 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インスタントで作業している場合は、IAMロールを付与してs3への書き込みを有効にできるため、資格情報を直接渡す必要はありません。ただし、S3FileSystem()関数に認証情報を渡すことでバケットに接続することもできます。ドキュメントを参照してください:https : //s3fs.readthedocs.io/en/latest/


何らかの理由でこれを行ったとき、出力CSVですべての行がスキップされました
kjmerf

うーん。なぜそれが起こるのかわからない。おそらく別のパンダdfを試して、まだ問題が発生するかどうかを確認してください。お使いのパンダのバージョンでサポートされている場合は、@ 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ユーザーを使用して作成した次の関数を使用すると、問題なく書き込めますアドバイス(コメント欄でのフォーマット方法がわからないため、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());
fyiセミコロンは行末です

13

データにNone最初の引数として渡すと、to_csv()文字列として返されます。そこから、それを一度にS3にアップロードする簡単なステップです。

StringIOオブジェクトをに渡すことも可能ですto_csv()が、文字列を使用する方が簡単です。


どちらの方法で簡単になりますか?それを行う正しい方法は何ですか?
エランモシェ

@EranMoshe:どちらの方法でも正しく動作しますが、オブジェクトを作成してデータを読み取るよりも、返された文字列に渡しNoneto_csv()使用する方が明らかに簡単StringIOです。
mhawke

怠惰なプログラマーとして私はそうしました。そして、あなたはより少ないコードを書くプログラマにとってより簡単であることを意味しました:>
Eran Moshe '10

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から2列の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()

4
ソリューションを投稿するだけでなく、説明も追加してください。
sjaustirni 2017年

このような複雑な(Pythonの初心者向け)ソリューションを作成することには利点がありますか?
JavierLópezTomás19年

1
これはs3からファイルを読み取り、問題はdfをs3に書き込む方法でした。
Damian Satterthwaite-Phillips
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.