Diske yazmadan AWS S3'teki bir metin dosyasını pandalara aktarma


91

Sekmeyle ayrılmış bir tablo olan S3'e kaydedilmiş bir metin dosyam var. Onu pandalara yüklemek istiyorum ama önce kaydedemiyorum çünkü bir heroku sunucusunda çalışıyorum. İşte şimdiye kadar sahip olduğum şey.

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)

hata

OSError: Expected file path name or file-like object, got <class 'bytes'> type

Yanıt gövdesini pandaların kabul edeceği bir biçime nasıl dönüştürebilirim?

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

GÜNCELLEME - Aşağıdakileri kullanarak çalıştı

file = response["Body"].read()

ve

pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)

bu şekilde deneyin: io.BytesIO(file)ya io.StringIO(file)yerine filede read_csv()çağrı
MaxU

Bu cevaptaio.StringIO olduğu gibi kullanabilirsiniz .
IanS

Bu önerilerin hiçbiri işe yaramadı. Hataları yazı düzenlememde görebilirsiniz.
alpalalpal

1
GÜNCELLEME kısmı benim için çalıştı. Teşekkürler.
Wim Berchmans

Yanıtlar:


110

pandaskullanımları botoiçin read_csvsize gerekir, böylece:

import boto
data = pd.read_csv('s3://bucket....csv')

Eğer gerekiyorsa boto3üzerinde olduğu için python3.4+, olabildiğince

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

Yana sürüm 0.20.1 pandas kullanımları s3fs, aşağıdaki yanıta bakın.


Herkese açık hale getirmeden bir URL kullanmanın bir yolu var mı? Dosyanın gizli kalması gerekiyor.
alpalalpal

boto3: Docs yapılandırmak kimlik doğrulaması Eğer sıra özel dosyalara erişebilir, böylece göstermek boto3.readthedocs.io/en/latest/guide/quickstart.html
Stefan

1
NoCredentialsError atıyor. S3 kimlik bilgilerini buna nasıl ayarlayabilirim? Python ve boto'da yeniyim
Sunil Rao

15
Boto3 ile son örnekte şunları yapmam gerektiğini fark ettim: df = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8')
user394430

Bu cevap güncel değil . Lütfen Wesams'ın cevabına bakın .
gerrit

80

Artık pandalar S3 URL'lerini işleyebilir . Şunları yapabilirsiniz:

import pandas as pd
import s3fs

df = pd.read_csv('s3://bucket-name/file.csv')

Sahips3fs değilseniz yüklemeniz gerekir. pip install s3fs

Doğrulama

S3 klasörünüz özelse ve kimlik doğrulama gerektiriyorsa iki seçeneğiniz vardır:

1- Yapılandırma dosyanıza erişim kimlik bilgilerini ekleyin~/.aws/credentials

[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Veya

2- Aşağıdaki ortam değişkenlerini uygun değerleriyle ayarlayın:

  • aws_access_key_id
  • aws_secret_access_key
  • aws_session_token

Güzel. Python3 ile çalışır.
Kyler Brown

kimlik doğrulamaya ne dersin ..?
James Wierzba

1
@JamesWierzba, yukarıdaki cevabıma kimlik doğrulama hakkında daha fazla ayrıntı ekledim.
Wesam

3
Birden çok aws profiliyle uğraşırken, hangi profilin kullanılması gerektiğini nasıl seçebilirsiniz? s3fs profil_adı seçeneğine sahiptir, ancak bunun pandalarla nasıl çalıştığından emin değilim.
Ivo Merchiers

1
@IanS Gerçekten değil, şu anda, önce dosya nesnesini s3fs ile açıyorum (belirtilen profili kullanarak) ve sonra burada yaptıkları gibi pandalarla okuyorum github.com/pandas-dev/pandas/issues/16692
Ivo Merchiers

15

Bu artık son pandalarda destekleniyor. Görmek

http://pandas.pydata.org/pandas-docs/stable/io.html#reading-remote-files

Örneğin.,

df = pd.read_csv('s3://pandas-test/tips.csv')

4
'S3 URL'lerinin de işlendiğini ancak S3Fs kitaplığının yüklenmesini gerektirdiğini' unutmayın
Julio Villane

kimlik doğrulamaya ne dersin
James Wierzba

url kamu olarak maruz, sürece auth ile url zor olabilir, emin değilim basit / temel http kimlik doğrulama, çalışıp çalışmayacağını
Raveen Beemsingh

9

S3fs ile şu şekilde yapılabilir:

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)

2
Sanırım s3fs ile yazabilirsinizdf = pd.read_csv('s3://mybucket/path/to/object/foo.pkl')
louis_guitton

1
@louis_guitton bu pd-read_csv ile çalışıyor gibi görünüyor ama read_pickle ile çalışmıyor
Sip

1

Dosyalar çok büyük olabileceğinden, bunları veri çerçevesine tamamen yüklemek akıllıca değildir. Bu nedenle, satır satır okuyun ve veri çerçevesine kaydedin. Evet, ayrıca read_csv'de yığın boyutunu da sağlayabiliriz, ancak o zaman okunan satır sayısını korumamız gerekir.

Dolayısıyla bu mühendisliği buldum:

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=",")

İş bittiğinde df'yi de siliyorum. del df


1

Metin dosyaları için, boru ile ayrılmış dosya ile aşağıdaki kodu kullanabilirsiniz, örneğin: -

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)

0

Bir seçenek, csv'yi json'a dönüştürmek df.to_dict()ve ardından bir dize olarak saklamaktır. Bunun yalnızca CSV'nin bir gereksinim olmaması, ancak veri çerçevesini hızlı bir şekilde bir S3 klasörüne yerleştirip yeniden almak istediğinizde geçerli olduğunu unutmayın.

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

Bu, df'yi bir dikt dizesine dönüştürür ve ardından bunu S3'te json olarak kaydeder. Daha sonra aynı json formatında okuyabilirsiniz:

df = pd.DataFrame(yaml.load(myKey.get_contents_as_string()))

Diğer çözümler de iyidir, ancak bu biraz daha basittir. Yaml gerekli olmayabilir, ancak json dizesini ayrıştırmak için bir şeye ihtiyacınız var. S3 dosyasının mutlaka bir CSV olması gerekmiyorsa , bu hızlı bir düzeltme olabilir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.