डेटाफ़्रेम को cs3 में सीधे s3 पायथन में सहेजें


125

मेरे पास एक पांडा डेटाफ़्रेम है जिसे मैं एक नई सीएसवी फ़ाइल में अपलोड करना चाहता हूं। समस्या यह है कि मैं फ़ाइल को स्थानीय रूप से 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

3
df.to_csv('s3://mybucket/dfs/somedf.csv')। अधिक जानकारी के लिए stackoverflow.com/a/56275519/908886
पीटर बर्ग

जवाबों:


158

आप उपयोग कर सकते हैं:

from io import StringIO # python3; python2: BytesIO 
import boto3

bucket = 'my_bucket_name' # already created on S3
csv_buffer = StringIO()
df.to_csv(csv_buffer)
s3_resource = boto3.resource('s3')
s3_resource.Object(bucket, 'df.csv').put(Body=csv_buffer.getvalue())

9
यदि यह एक बड़ी फ़ाइल है, तो यह मेमोरी को क्या करता है ...?
नगरनाराम

2
यदि फ़ाइल बड़ी है, तो आपके पास उपलब्ध RAM विफल हो जाएगी और अपवाद को छोड़कर (पता नहीं कि कौन सा)। इसे उत्तर के रूप में स्वीकार किया जाना चाहिए
एरन मोशे

5
TypeError: unicode argument expected, got 'str'उपयोग करते समय मुझे त्रुटि मिली StringIO। मैंने इस्तेमाल किया BytesIOऔर यह पूरी तरह से ठीक काम किया। नोट: यह पायथन 2.7 में था
अभिषेक उपाध्याय

1
bucketवस्तु क्या है ? आपने इसे कैसे बनाया?
चार्ल्स चाउ

1
bucketवह जगह है जहाँ आप वस्तुओं को S3 पर संग्रहीत करते हैं। कोड मानता है कि आपने पहले ही गंतव्य बनाया है (सोचें: निर्देशिका) जहां इसे संग्रहीत करना है। S3 डॉक्स
स्टीफन

65

आप सीधे 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 फ़ाइल हैंडलिंग

पांडा अब S3 कनेक्शन को संभालने के लिए s3fs का उपयोग करता है। यह किसी भी कोड को नहीं तोड़ना चाहिए। हालांकि, चूंकि s3fs एक आवश्यक निर्भरता नहीं है, इसलिए आपको इसे अलग से स्थापित करने की आवश्यकता होगी, जैसे पंडों के पूर्व संस्करणों में बोटो। GH11915


7
यह निश्चित रूप से अब सबसे आसान जवाब है, यह पर्दे के पीछे s3fs का उपयोग करता है ताकि आपको अपनी आवश्यकताओं में इसे जोड़ना पड़े। txt
JD D

1
मुझे पसंद है यह आसान है, लेकिन ऐसा लगता है कि यह वास्तव में काम नहीं कर रहा है क्योंकि मुझे निम्नलिखित त्रुटि मिलती रहती है NoCredentialsError: Unable to locate credentials। कोई सुझाव?
कैथीशियन

1
मैं इस बात की पुष्टि कर सकता हूं कि यह पंडों के साथ काम नहीं करता है <= 0.23.4, इसलिए पंडों को अपग्रेड करना सुनिश्चित करें। 0.24
गुइडो

1
यह वह त्रुटि है जिसे मैं तब देखता हूं जब मैं to_csv कमांड का उपयोग करने का प्रयास करता हूं TypeError: लिखना () तर्क 1 में यूनिकोड होना चाहिए, str नहीं
राज

13
मैं 0.24.2 पांडा का उपयोग कर रहा हूं और मुझे जो भी मिल रहा है NotImplementedError: Text mode not supported, use mode='wb' and manage bytes। कोई सुझाव?
बिन्यामीन यहां तक ​​कि

57

मुझे 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सामान किया।


महान! मैं उसी s3fs मॉड्यूल का उपयोग करके फ़ाइल url कैसे प्राप्त कर सकता हूं?
एम। अंजमान

मैं उस URL की तलाश कर रहा था जहाँ से मैं लिखित फ़ाइल को डाउनलोड कर सकूँ, वैसे भी मुझे S3FileSystem के माध्यम से जो भी मिलता है। धन्यवाद
M.Zaman

यही है वह जो मेरे द्वारा उपयोग किया जाता है; धन्यवाद। मैं उत्सुक हूं कि pd.read_csv (<s3path>) अपेक्षा के अनुसार काम करता है, लेकिन लिखने के लिए हमें इस काम का उपयोग करना होगा .. सिवाय इस बात के कि मैं सीधे s3 बाल्टी में लिख रहा हूं, मेरी जुपिटर में है
रेनी

@ michcio1234 मैं एपेंड मोड में कैसे कर सकता हूं? मुझे मौजूदा सीएसवी में डेटा को s3
j '

@j ' s3fsएपेंड मोड का समर्थन नहीं करता है।
michcio1234

43

यह उत्तर तिथि तक अधिक है:

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 में लिख रहे हैं। पांडा की डेटाफ्रेम पकड़ना और मेमोरी में इसकी स्ट्रिंग कॉपी का होना बहुत ही अयोग्य है।

यदि आप एक एक् 2 इंस्टेंट में काम कर रहे हैं, तो आप इसे S3 में लिखने के लिए IAM भूमिका दे सकते हैं, इस प्रकार आपको सीधे क्रेडेंशियल्स में पास होने की आवश्यकता नहीं है। हालाँकि, आप S3FileSystem()फ़ंक्शन को क्रेडेंशियल्स पास करके एक बाल्टी से भी कनेक्ट कर सकते हैं । दस्तावेज़ देखें: https://s3fs.readthedocs.io/en/latest/


किसी कारण से जब मैंने ऐसा किया था तो हर लाइन आउटपुट CSV
kjmerf

हम्म। यकीन नहीं होता कि ऐसा क्यों होगा। शायद एक और पांडा df के साथ देखने की कोशिश करें कि क्या आपको अभी भी समस्या है? अगर आपके पंडों का संस्करण इसका समर्थन करता है, तो @ amit-kushwaha का उत्तर आज़माएं, जहाँ आप सीधे s3 url पास करते हैं to_csv()। एक क्लीनर कार्यान्वयन की तरह लगता है।
9

@erncyp मुझे लगता है कि इसमें त्रुटि हो रही है: botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied ... मैंने बाल्टी PUBLIC READ भी कर दी है और मैंने निम्नलिखित कार्यवाहियों को अपने विशिष्ट खाते IAM उपयोगकर्ता के तहत, बकेट नीति में शामिल कर लिया है:"Action": [ "s3:PutObject", "s3:PutObjectAcl", "s3:GetObject", "s3:GetObjectAcl", "s3:DeleteObject" ]
ajoros

ऐसा लगता है जैसे आपको अनुमतियों की कमी है? सुनिश्चित करें कि S3 पढ़ी गई अनुमतियाँ IAM भूमिका का उपयोग करने के लिए अनुमतियाँ संलग्न करें
erncyp

@erncyp मेरे पास मेरे IAM उपयोगकर्ता से जुड़ी प्रशासक सफल नीति है, इसलिए सिद्धांत रूप में मुझे ठीक पढ़ने / लिखने में सक्षम होना चाहिए ... अजीब तरह से, जब मैं निम्नलिखित फ़ंक्शन का उपयोग करता हूं, तो एक और Stackververflow उपयोगकर्ता का उपयोग करके मैं ठीक ठीक लिख सकता हूं सलाह (फी अर्ध-कॉलन एंड-ऑफ-लाइन हैं क्योंकि मुझे नहीं पता कि टिप्पणी अनुभाग में प्रारूपित कैसे करें):def send_to_bucket(df, fn_out, bucketname): csv_buffer = StringIO(); df.to_csv(csv_buffer); s3_resource = boto3.resource('s3'); s3_resource.Object(bucketname, fn_out).put(Body=csv_buffer.getvalue());
एज़ोरोस

13

यदि आप डेटा Noneके पहले तर्क के रूप में पास होते हैं to_csv(), तो इसे स्ट्रिंग के रूप में लौटाया जाएगा। वहाँ से यह एक आसान कदम है कि एक ही बार में S3 पर अपलोड करें।

किसी StringIOऑब्जेक्ट को पास करना भी संभव होना चाहिए to_csv(), लेकिन स्ट्रिंग का उपयोग करना आसान होगा।


किस तरह से आसान होगा? इसे करने का सही तरीका क्या है?
एरन मोशे

@EranMoshe: किसी भी तरह से सही तरीके से काम करेगा, लेकिन जाहिर है कि किसी ऑब्जेक्ट को बनाने और उसके बाद डेटा को वापस पढ़ने की तुलना में लौटे स्ट्रिंग को पास Noneकरना to_csv()और उसका उपयोग करना आसान StringIOहै।
म्हावेके

एक आलसी प्रोग्रामर के रूप में जो मैंने किया। और आप कम कोड लिखने वाले प्रोग्रामर के लिए आसान थे:>
एरन मोशे

2

आप AWS डेटा रैंगलर का उपयोग भी कर सकते हैं :

import awswrangler

session = awswrangler.Session()
session.pandas.to_csv(
    dataframe=df,
    path="s3://...",
)

ध्यान दें कि यह समानांतर में अपलोड होने के बाद से कई भागों में विभाजित हो जाएगा।


2

मैंने पाया कि यह प्रयोग किया जा सकता है clientऔर सिर्फ नहीं resource

from io import StringIO
import boto3
s3 = boto3.client("s3",\
                  region_name=region_name,\
                  aws_access_key_id=aws_access_key_id,\
                  aws_secret_access_key=aws_secret_access_key)
csv_buf = StringIO()
df.to_csv(csv_buf, header=True, index=False)
csv_buf.seek(0)
s3.put_object(Bucket=bucket, Body=csv_buf.getvalue(), Key='path/test.csv')

0

जब से आप उपयोग कर रहे हैं boto3.client(), कोशिश करें:

import boto3
from io import StringIO #python3 
s3 = boto3.client('s3', aws_access_key_id='key', aws_secret_access_key='secret_key')
def copy_to_s3(client, df, bucket, filepath):
    csv_buf = StringIO()
    df.to_csv(csv_buf, header=True, index=False)
    csv_buf.seek(0)
    client.put_object(Bucket=bucket, Body=csv_buf.getvalue(), Key=filepath)
    print(f'Copy {df.shape[0]} rows to S3 Bucket {bucket} at {filepath}, Done!')

copy_to_s3(client=s3, df=df_to_upload, bucket='abc', filepath='def/test.csv')

-1

मुझे लगता है कि काम करने के लिए एक बहुत ही सरल समाधान मिला:

s3 = boto3.client("s3")

s3.put_object(
    Body=open("filename.csv").read(),
    Bucket="your-bucket",
    Key="your-key"
)

उम्मीद है की वो मदद करदे !


-5

मैंने बाल्टी s3 से दो कॉलम के साथ एक सीएसवी पढ़ा, और फाइल सीएसवी की सामग्री मैंने पंडों के डेटाफ्रेम में डाल दी।

उदाहरण:

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()

4
कृपया समाधान पोस्ट न करें, इसका स्पष्टीकरण भी जोड़ें।
संजुतिरानी

क्या इस तरह के एक जटिल (पायथन में एक नौसिखिया के लिए) समाधान बनाने पर कोई फायदा है?
जेवियर लोपेज़ टोमस

1
यह s3 की एक फ़ाइल को पढ़ता है, सवाल यह था कि s3 को df कैसे लिखा जाए।
डेमियन सटरथवेट-फिलिप्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.