web-dev-qa-db-ja.com

ディスクに書き込まずにAWS S3のテキストファイルをpandasにインポートする方法

タブ区切りのテーブルであるS3にテキストファイルを保存しています。 pandasにロードしたいのですが、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)
59
alpalalpal

pandasread_csvbotoを使用するため、次のことができるはずです。

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

pandasはS3 URLを処理できます 。簡単にできます:

import pandas as pd
import s3fs

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

s3fsをインストールする必要があります お持ちでない場合。 pip install s3fs

認証

S3バケットがプライベートで認証が必要な場合、2つのオプションがあります。

1-アクセス認証情報を ~/.aws/credentials configファイル に追加します

[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
40
Wesam

これは現在、最新のパンダでサポートされています。見る

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

例えば。、

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

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)
6
Dror

ファイルが大きすぎる可能性があるため、それらをすべてデータフレームにロードすることは賢明ではありません。したがって、1行ずつ読み取り、データフレームに保存します。はい、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

1
aviral sanjay

オプションは、df.to_dict()を介してcsvをjsonに変換し、それを文字列として保存することです。これは、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文字列に変換され、S3にjsonとして保存されます。後で同じJSON形式で読むことができます:

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

他のソリューションも良いですが、これは少し簡単です。 Yamlは必ずしも必要ではありませんが、json文字列を解析するために何かが必要です。 S3ファイルが必ずしもneedでなくてもCSVである場合、これは簡単な修正方法です。

0
billmanH