Сохранить Dataframe в csv прямо на s3 Python
У меня есть DataFrame для панд, который я хочу загрузить в новый файл CSV. Проблема в том, что я не хочу сохранять файл локально, прежде чем перенести его на s3. Есть ли какой-либо метод, например to_csv, для прямой записи данных в s3? Я использую boto3.
Вот что у меня так далеко:
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
Ответы
Ответ 1
Ты можешь использовать:
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())
Ответ 2
Мне нравится s3fs, который позволяет использовать s3 (почти) как локальную файловую систему.
Вы можете сделать это:
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
поддерживает только rb
и wb
режимы открытия файла, поэтому я сделал этот материал bytes_to_write
.
Ответ 3
Это более актуальный ответ:
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)
Проблема с StringIO заключается в том, что он будет уничтожен вашей памятью. С помощью этого метода вы передаете файл в файл s3 вместо преобразования его в строку, а затем записываете его в файл s3. Хранение информационного кадра Pandas и его строковой копии в памяти кажется очень неэффективным.
Если вы работаете в режиме ec2, вы можете назначить ему роль IAM, чтобы разрешить запись его в s3, поэтому вам не нужно передавать учетные данные напрямую. Однако вы также можете подключиться к S3FileSystem()
передав учетные данные в S3FileSystem()
. См. Документацию: https://s3fs.readthedocs.io/en/latest/.
Ответ 4
Вы можете напрямую использовать путь S3. Я использую Панды 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
Примечание к выпуску:
S3 File Handling
pandas теперь использует s3fs для обработки соединений S3. Это не должно нарушать любой код. Однако, поскольку s3fs не является обязательной зависимостью, вам нужно будет установить ее отдельно, как boto в предыдущих версиях pandas. GH11915.
Ответ 5
Если вы передадите None
в качестве первого аргумента to_csv()
, данные будут возвращены в виде строки. Оттуда это простой шаг, чтобы загрузить его на S3 за один раз.
Также должно быть возможно передать объект StringIO
в to_csv()
, но использовать строку будет проще.
Ответ 6
import boto3
s3_client = boto3.client('s3',aws_access_key_id="AccessKey",aws_secret_access_key="Secretkey")
head_response = s3_client.head_object(Bucket='YourBucket',Key='YourPath')
if head_response['HTTPStatusCode'] == 200:
Your operation if file exsits
Ответ 7
Я прочитал csv с двумя столбцами из ведра s3, а содержимое файла csv я помещено в pandas dataframe.
Пример:
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 __name__ == '__main__':
test = test()
test.process()