Ich habe eine Textdatei in S3 gespeichert, die eine tabulatorgetrennte Tabelle ist. Ich möchte es in Pandas laden, kann es aber nicht zuerst speichern, da ich auf einem Heroku-Server laufe. Folgendes habe ich bisher.
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)
Der Fehler ist
OSError: Expected file path name or file-like object, got <class 'bytes'> type
Wie konvertiere ich den Antworttext in ein Format, das Pandas akzeptieren?
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 - Die folgenden Funktionen haben funktioniert
file = response["Body"].read()
und
pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
io.BytesIO(file)
oderio.StringIO(file)
stattfile
imread_csv()
Anrufio.StringIO
wie in dieser Antwort verwenden .Antworten:
pandas
verwendetboto
fürread_csv
, so sollten Sie in der Lage sein:import boto data = pd.read_csv('s3://bucket....csv')
Wenn Sie brauchen,
boto3
weil Sie eingeschaltet sindpython3.4+
, können Sieimport boto3 import io s3 = boto3.client('s3') obj = s3.get_object(Bucket='bucket', Key='key') df = pd.read_csv(io.BytesIO(obj['Body'].read()))
Da Version 0.20.1
pandas
verwendets3fs
, siehe Antwort unten.quelle
boto3
Dokumente zeigen, wie die Authentifizierung so konfiguriert wird, dass Sie auch auf private Dateien zugreifen können: boto3.readthedocs.io/en/latest/guide/quickstart.htmldf = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8')
Jetzt können Pandas mit S3-URLs umgehen . Sie könnten einfach tun:
import pandas as pd import s3fs df = pd.read_csv('s3://bucket-name/file.csv')
Sie müssen installieren,
s3fs
wenn Sie es nicht haben.pip install s3fs
Authentifizierung
Wenn Ihr S3-Bucket privat ist und eine Authentifizierung erfordert, haben Sie zwei Möglichkeiten:
1- Fügen Sie Ihrer Konfigurationsdatei Zugriffsdaten hinzu
~/.aws/credentials
Oder
2- Stellen Sie die folgenden Umgebungsvariablen mit ihren richtigen Werten ein:
aws_access_key_id
aws_secret_access_key
aws_session_token
quelle
Dies wird jetzt in den neuesten Pandas unterstützt. Sehen
http://pandas.pydata.org/pandas-docs/stable/io.html#reading-remote-files
z.B.,
df = pd.read_csv('s3://pandas-test/tips.csv')
quelle
Mit s3fs kann dies wie folgt durchgeführt werden:
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)
quelle
df = pd.read_csv('s3://mybucket/path/to/object/foo.pkl')
Da die Dateien zu groß sein können, ist es nicht ratsam, sie insgesamt in den Datenrahmen zu laden. Lesen Sie daher Zeile für Zeile und speichern Sie es im Datenrahmen. Ja, wir können auch die Blockgröße in read_csv angeben, aber dann müssen wir die Anzahl der gelesenen Zeilen beibehalten.
Daher habe ich mir dieses Engineering ausgedacht:
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=",")
Ich lösche auch die df, sobald die Arbeit erledigt ist.
del df
quelle
Für Textdateien können Sie den folgenden Code mit einer durch Pipe getrennten Datei verwenden, zum Beispiel: -
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)
quelle
Eine Option besteht darin, die CSV über über in json zu konvertieren
df.to_dict()
und sie dann als Zeichenfolge zu speichern. Beachten Sie, dass dies nur relevant ist, wenn die CSV nicht erforderlich ist, Sie den Datenrahmen jedoch schnell in einen S3-Bucket einfügen und erneut abrufen möchten.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()))
Dadurch wird der df in einen diktierten String konvertiert und in S3 als json gespeichert. Sie können es später im gleichen JSON-Format lesen:
Die anderen Lösungen sind ebenfalls gut, aber das ist etwas einfacher. Yaml ist möglicherweise nicht unbedingt erforderlich, aber Sie benötigen etwas, um die JSON-Zeichenfolge zu analysieren. Wenn die S3 - Datei nicht unbedingt benötigt eine CSV zu sein , dies kann eine schnelle Lösung sein.
quelle