[python] AWS S3의 텍스트 파일을 디스크에 쓰지 않고 Pandas로 가져 오는 방법

탭으로 구분 된 테이블 인 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)



답변

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

이후 버전 0.20.1 pandas 용도 s3fs, 아래의 대답을 참조하십시오.


답변

이제 Pandas는 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

[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


답변

이것은 이제 최신 팬더에서 지원됩니다. 보다

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

예 :

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


답변

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)


답변

파일이 너무 클 수 있으므로 데이터 프레임에 모두로드하는 것은 현명하지 않습니다. 따라서 한 줄씩 읽고 데이터 프레임에 저장하십시오. 예, 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


답변

텍스트 파일의 경우 예를 들어 파이프로 구분 된 파일과 함께 아래 코드를 사용할 수 있습니다.

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)


답변

옵션은 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 문자열로 변환 한 다음 S3에 json으로 저장합니다. 나중에 동일한 json 형식으로 읽을 수 있습니다.

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

다른 솔루션도 좋지만 조금 더 간단합니다. Yaml이 반드시 필요한 것은 아니지만 json 문자열을 구문 분석하려면 무언가가 필요합니다. S3 파일이 반드시 CSV 일 필요 가없는 경우 빠른 수정이 될 수 있습니다.