J'ai un fichier texte enregistré sur S3 qui est une table délimitée par des tabulations. Je veux le charger dans pandas mais je ne peux pas le sauvegarder au préalable parce que je suis sur un serveur heroku. Voici ce que j'ai à ce jour.
import io
import boto3
import os
import pandas as pd
os.environ["AWS_ACCESS_KEY_ID"] = "xxxxxxxx"
os.environ["AWS_SECRET_ACCESS_KEY"] = "xxxxxxxx"
s3_client = boto3.client('s3')
response = s3_client.get_object(Bucket="my_bucket",Key="filename.txt")
file = response["Body"]
pd.read_csv(file, header=14, delimiter="\t", low_memory=False)
l'erreur est
OSError: Expected file path name or file-like object, got <class 'bytes'> type
Comment convertir le corps de la réponse dans un format pandas acceptera?)
pd.read_csv(io.StringIO(file), header=14, delimiter="\t", low_memory=False)
returns
TypeError: initial_value must be str or None, not StreamingBody
pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
returns
TypeError: 'StreamingBody' does not support the buffer interface
UPDATE - Utilisation de ce qui suit a fonctionné
file = response["Body"].read()
et
pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
pandas
utilise boto
pour read_csv
, vous devriez donc pouvoir:
import boto
data = pd.read_csv('s3://bucket....csv')
Si tu as besoin boto3
parce que vous êtes sur python3.4+
, vous pouvez
import boto3
import io
s3 = boto3.client('s3')
obj = s3.get_object(Bucket='bucket', Key='key')
df = pd.read_csv(io.BytesIO(obj['Body'].read()))
Maintenant les pandas peuvent gérer les URL S . Vous pouvez simplement faire:
import pandas as pd
import s3fs
df = pd.read_csv('s3://bucket-name/file.csv')
Vous devez installer s3fs
si vous ne l'avez pas. pip install s3fs
Si votre compartiment S3 est privé et nécessite une authentification, vous avez deux options:
1- Ajouter des identifiants d'accès à votre ~/.aws/credentials
fichier de configuration
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Ou
2- Définissez les variables d’environnement avec leurs valeurs appropriées:
aws_access_key_id
aws_secret_access_key
aws_session_token
Ceci est maintenant pris en charge dans les derniers pandas. Voir
http://pandas.pydata.org/pandas-docs/stable/io.html#reading-remote-files
par exemple.,
df = pd.read_csv('s3://pandas-test/tips.csv')
Avec s3fs cela peut être fait comme suit:
import s3fs
import pandas as pd
fs = s3fs.S3FileSystem(anon=False)
# CSV
with fs.open('mybucket/path/to/object/foo.pkl') as f:
df = pd.read_csv(f)
# Pickle
with fs.open('mybucket/path/to/object/foo.pkl') as f:
df = pd.read_pickle(f)
Les fichiers pouvant être trop volumineux, il n’est pas judicieux de les charger dans le cadre de données. Par conséquent, lisez ligne par ligne et enregistrez-le dans le dataframe. Oui, nous pouvons également fournir la taille de bloc dans read_csv, mais nous devons ensuite conserver le nombre de lignes lues.
Par conséquent, je suis venu avec cette ingénierie:
def create_file_object_for_streaming(self):
print("creating file object for streaming")
self.file_object = self.bucket.Object(key=self.package_s3_key)
print("File object is: " + str(self.file_object))
print("Object file created.")
return self.file_object
for row in codecs.getreader(self.encoding)(self.response[u'Body']).readlines():
row_string = StringIO(row)
df = pd.read_csv(row_string, sep=",")
Je supprime également le df une fois le travail terminé. del df
Une option consiste à convertir le fichier csv en fichier json via df.to_dict()
, puis à le stocker en tant que chaîne. Notez que cela n’est pertinent que si le fichier CSV n’est pas une exigence mais que vous souhaitez simplement placer rapidement le cadre de données dans un compartiment S3 et le récupérer à nouveau.
from boto.s3.connection import S3Connection
import pandas as pd
import yaml
conn = S3Connection()
mybucket = conn.get_bucket('mybucketName')
myKey = mybucket.get_key("myKeyName")
myKey.set_contents_from_string(str(df.to_dict()))
Cela convertira le df en une chaîne de dict, puis sauvegardera cela comme json dans S3. Vous pourrez le lire plus tard dans le même format JSON:
df = pd.DataFrame(yaml.load(myKey.get_contents_as_string()))
Les autres solutions sont également bonnes, mais ceci est un peu plus simple. Yaml n'est peut-être pas nécessaire, mais vous avez besoin de quelque chose pour analyser la chaîne json. Si le fichier S3 ne doit pas nécessairement nécessité être un fichier CSV, cela peut constituer une solution rapide.