J'ai un pandas _ DataFrame que je souhaite télécharger dans un nouveau fichier CSV. Le problème est que je ne veux pas enregistrer le fichier localement avant de le transférer sur s3. Existe-t-il une méthode telle que to_csv pour écrire le dataframe sur s3 directement? J'utilise boto3.
Voici ce que j'ai jusqu'à présent:
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
Vous pouvez utiliser:
from io import StringIO # python3; python2: BytesIO
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())
J'aime s3fs qui vous permet d'utiliser (presque) s3 comme un système de fichiers local.
Tu peux le faire:
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
ne supporte que rb
et wb
modes d'ouverture du fichier, c'est pourquoi j'ai fait ce type de bytes_to_write
.
Ceci est une réponse plus à jour:
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)
Le problème avec StringIO est qu'il va ronger votre mémoire. Avec cette méthode, vous transmettez en continu le fichier au format s3, plutôt que de le convertir en chaîne, puis de l'écrire au format s3. Tenir le pandas dataframe et sa copie de chaîne en mémoire semble très inefficace.
Si vous travaillez dans un instant ec2, vous pouvez lui attribuer un rôle IAM pour lui permettre de l'écrire sur s3. Ainsi, vous n'avez pas besoin de passer directement les informations d'identification. Toutefois, vous pouvez également vous connecter à un compartiment en transmettant les informations d'identification à la fonction S3FileSystem()
. Voir la documentation: https://s3fs.readthedocs.io/en/latest/
Vous pouvez directement utiliser le chemin S3. J'utilise 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
Traitement de fichiers S3
les pandas utilisent maintenant s3fs pour gérer les connexions S3. Cela ne devrait casser aucun code. Cependant, s3fs n'étant pas une dépendance requise, vous devrez l'installer séparément, comme boto dans les versions précédentes de pandas. GH11915 .
Si vous passez None
comme premier argument à to_csv()
, les données seront renvoyées sous forme de chaîne. À partir de là, il est facile de télécharger cela en une fois sur S3.
Il devrait également être possible de passer un objet StringIO
à to_csv()
, mais l'utilisation d'une chaîne sera plus facile.
J'ai lu un CSV avec deux colonnes du seau S3 et le contenu du fichier CSV que j'ai mis dans pandas dataframe.
Exemple:
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 __== '__main__':
test = test()
test.process()