J'ai un fichier texte enregistré sur S3 qui est une table délimitée par des tabulations. Je veux le charger dans des pandas mais je ne peux pas le sauvegarder d'abord car je suis en cours d'exécution sur un serveur heroku. Voici ce que j'ai jusqu'ici.
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 que les pandas accepteront?
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
MISE À JOUR - Utilisation de ce qui suit travaillé
file = response["Body"].read()
et
pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
io.BytesIO(file)
ouio.StringIO(file)
au lieu defile
l'read_csv()
appelio.StringIO
comme dans cette réponse .Réponses:
pandas
utiliseboto
pourread_csv
, vous devriez donc pouvoir:import boto data = pd.read_csv('s3://bucket....csv')
Si vous avez besoin
boto3
parce que vous êtes allumépython3.4+
, vous pouvezimport boto3 import io s3 = boto3.client('s3') obj = s3.get_object(Bucket='bucket', Key='key') df = pd.read_csv(io.BytesIO(obj['Body'].read()))
Depuis la version 0.20.1
pandas
utilises3fs
, voir la réponse ci-dessous.la source
boto3
documentation montre comment configurer l'authentification afin que vous puissiez également accéder aux fichiers privés: boto3.readthedocs.io/en/latest/guide/quickstart.htmldf = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8')
Désormais, les pandas peuvent gérer les URL S3 . 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
Authentification
Si votre compartiment S3 est privé et nécessite une authentification, vous avez deux options:
1- Ajoutez les identifiants d'accès à votre
~/.aws/credentials
fichier de configurationOu
2- Définissez les variables d'environnement suivantes avec leurs valeurs appropriées:
aws_access_key_id
aws_secret_access_key
aws_session_token
la source
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')
la source
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)
la source
df = pd.read_csv('s3://mybucket/path/to/object/foo.pkl')
Étant donné que les fichiers peuvent être trop volumineux, il n'est pas judicieux de les charger complètement dans le dataframe. Par conséquent, lisez ligne par ligne et enregistrez-le dans le dataframe. Oui, nous pouvons également fournir la taille du bloc dans read_csv, mais nous devons ensuite maintenir le nombre de lignes lues.
Par conséquent, j'ai proposé 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
la source
Pour les fichiers texte, vous pouvez utiliser le code ci-dessous avec un fichier délimité par des barres verticales par exemple: -
import pandas as pd import io import boto3 s3_client = boto3.client('s3', use_ssl=False) bucket = # prefix = # obj = s3_client.get_object(Bucket=bucket, Key=prefix+ filename) df = pd.read_fwf((io.BytesIO(obj['Body'].read())) , encoding= 'unicode_escape', delimiter='|', error_bad_lines=False,header=None, dtype=str)
la source
Une option consiste à convertir le csv en json via
df.to_dict()
, puis à le stocker sous forme de chaîne. Notez que cela n'est pertinent que si le CSV n'est pas une exigence, mais que vous souhaitez simplement mettre rapidement le dataframe 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 l'enregistrera en tant que json dans S3. Vous pourrez le lire plus tard dans le même format json:
Les autres solutions sont également bonnes, mais c'est un peu plus simple. Yaml n'est pas forcément nécessaire, mais vous avez besoin de quelque chose pour analyser la chaîne json. Si le fichier S3 n'a pas nécessairement besoin d'être un CSV, cela peut être une solution rapide.
la source