如何将AWS S3上的文本文件导入到pandas中而无需写入磁盘

时间:2016-06-08 13:16:50

标签: python pandas heroku amazon-s3 boto3

我在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)

9 个答案:

答案 0 :(得分:53)

pandasboto用于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()))

答案 1 :(得分:26)

现在pandas can handle S3 URLs。您可以简单地做到:

import pandas as pd
import s3fs

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

如果S3文件是私有文件,则需要S3 configurations setup properly

答案 2 :(得分:11)

最新的熊猫现在支持此功能。见

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

例如

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

答案 3 :(得分:5)

使用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)

答案 4 :(得分: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

答案 5 :(得分:1)

对于文本文件,您可以将以下代码与以竖线分隔的文件一起使用,例如:-

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)

答案 6 :(得分:0)

一个选项是通过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文件不一定需要 为CSV,则可以快速解决此问题。

答案 7 :(得分:0)

对于python 3.6及更高版本,亚马逊现在有一个非常不错的库,名为awswrangler

import awswrangler as wr
import boto3


# Boto3 session
session = boto3.session.Session(aws_access_key_id='XXXX', 
                                aws_secret_access_key='XXXX')

# Awswrangler pass forward all pd.read_csv() function args
df = wr.s3.read_csv(path='s3://bucket/path/',
                    boto3_session=session,
                    skiprows=2,
                    sep=';',
                    decimal=',',
                    na_values=['--'])

要安装awswrangler:pip install awswrangler

答案 8 :(得分:0)

import s3fs
import pandas as pd
s3 = s3fs.S3FileSystem(profile='<profile_name>')
pd.read_csv(s3.open(<s3_path>))