Как импортировать текстовый файл на AWS S3 в панды без записи на диск
У меня есть текстовый файл, сохраненный на S3, который является таблицей с разделителями табуляции. Я хочу загрузить его в панды, но не могу сохранить его сначала, потому что я бегу на сервере heroku. Вот что я до сих пор.
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)
ошибка
OSError: Expected file path name or file-like object, got <class 'bytes'> type
Как преобразовать тело ответа в формат, который будет принимать pandas?
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
ОБНОВЛЕНИЕ - использование следующих отработанных
file = response["Body"].read()
а также
pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
Ответы
Ответ 1
pandas
использует boto
для read_csv
, так что вы должны быть в состоянии:
import boto
data = pd.read_csv('s3://bucket....csv')
Если вам нужен boto3
потому что вы находитесь на python3.4+
, вы можете
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()))
Ответ 2
Теперь панды могут обрабатывать S3 URL. Вы можете просто сделать:
import pandas as pd
import s3fs
df = pd.read_csv('s3://bucket-name/file.csv')
Вам нужно установить s3fs
если у вас его нет. pip install s3fs
Аутентификация
Если ваша корзина S3 является частной и требует аутентификации, у вас есть два варианта:
1- Добавьте учетные данные для доступа к ~/.aws/credentials
конфигурации ~/.aws/credentials
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Или же
2- Установите следующие переменные среды с их правильными значениями:
-
aws_access_key_id
-
aws_secret_access_key
-
aws_session_token
Ответ 3
Это теперь поддерживается в последних пандах. Увидеть
http://pandas.pydata.org/pandas-docs/stable/io.html#reading-remote-files
например.,
df = pd.read_csv('s3://pandas-test/tips.csv')
Ответ 4
С s3fs это можно сделать следующим образом:
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)
Ответ 5
Вы можете настроить функцию, которая выглядит так, чтобы обернуть pd.read_csv
import pandas as pd
import io
import boto3
s3_resource = boto3.resource('s3')
s3_client = boto3.client('s3')
def pd_read_csv_s3(path, *args, **kwargs):
path = path.replace("s3://", "")
bucket, key = path.split('/', 1)
obj = s3_client.get_object(Bucket=bucket, Key=key)
return pd.read_csv(io.BytesIO(obj['Body'].read()), *args, **kwargs)
# Example usage
pd_read_csv_s3("s3://my_bucket/my_folder/file.csv", skiprows=2)
Обратите внимание, что аргументы, такие как skiprows или что-то еще, что вы хотите, прошли правильно
Ответ 6
Поскольку файлы могут быть слишком большими, нецелесообразно загружать их в кадр данных вообще. Следовательно, читайте построчно и сохраняйте его в кадре данных. Да, мы можем также указать размер фрагмента в read_csv, но тогда мы должны сохранить количество прочитанных строк.
Следовательно, я придумал эту разработку:
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=",")
Я также удаляю df, как только работа сделана. del df
Ответ 7
Один из вариантов - преобразовать csv в json с помощью df.to_dict()
а затем сохранить его в виде строки. Обратите внимание, что это уместно только в том случае, если CSV не является обязательным требованием, но вы просто хотите быстро поместить фрейм данных в корзину S3 и получить его снова.
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()))
Это преобразует df в строку dict, а затем сохраняет ее как json в S3. Позже вы можете прочитать его в том же формате JSON:
df = pd.DataFrame(yaml.load(myKey.get_contents_as_string()))
Другие решения тоже хороши, но это немного проще. Yaml не обязательно требуется, но вам нужно что-то для анализа строки json. Если файл S3 не обязательно должен быть CSV, это может быть быстрым решением.