[英]AWS Lambda, Python3 and Large XLSX files to CSV files
我有一批大小從 10Mb 到 400Mb 不等的 XLSX 文件。 它們內部始終具有相同的工作表和結構,但有些包含的數據比其他的多。
我正在嘗試使用 AWS Lambda 處理這些; 它是提交過程的一部分,因此 S3 中的文件丟失是 Lambda 的事件。
我很快了解到 XLSX 是一種可怕的格式,但我無法改變它。 目前我的主要 Lambda 使用這個 class 在網上找到並稍作改動。 memory 的使用率和速度比 Pandas read_excel 有所提高,但仍然不夠。 對於 400Mb 文件,Lambda 只是超時或耗盡其 memory 分配(即使是最大分配)。
對腳本進行一些 memory 分析,我可以看到在 pivot 操作期間大小減小了,但我真的不能跳過它。
關於如何改進它以提高 memory 效率的任何提示?
每個工作表都需要保存到它自己的 CSV 中,但如果有幫助,它可以分成多個 CSV 文件,比如塊大小樣式的迭代器?
import io
import zipfile
from lxml import etree
from pandas import read_csv, to_numeric
class ExcelParse:
sheet_xslt = etree.XML('''
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sp="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
>
<xsl:output method="text"/>
<xsl:template match="sp:row">
<xsl:for-each select="sp:c">
<xsl:value-of select="parent::*/@r"/> <!-- ROW -->
<xsl:text>,</xsl:text>
<xsl:value-of select="@r"/> <!--REMOVEME-->
<xsl:text>,</xsl:text>
<xsl:value-of select="@t"/> <!-- TYPE -->
<xsl:text>,</xsl:text>
<xsl:value-of select="sp:v/text()"/> <!-- VALUE -->
<xsl:text>\n</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
''')
def __init__(self, file):
self.fh = zipfile.ZipFile(file)
self.ns = {
'ns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
}
self.shared = self.load_shared()
self.workbook = self.load_workbook()
def load_workbook(self):
# Load workbook
name = 'xl/workbook.xml'
root = etree.parse(self.fh.open(name))
res = {}
for el in etree.XPath("//ns:sheet", namespaces=self.ns)(root):
res[el.attrib['name']] = str(
int(el.attrib['sheetId']) -
1) # Sheet ID in the XML starts at 2 for some reason?
return res
def load_shared(self):
# Load shared strings
name = 'xl/sharedStrings.xml'
root = etree.parse(self.fh.open(name))
res = etree.XPath("/ns:sst/ns:si/ns:t", namespaces=self.ns)(root)
return {str(pos): el.text for pos, el in enumerate(res)}
def _parse_sheet(self, root):
transform = etree.XSLT(self.sheet_xslt)
result = transform(root)
df = read_csv(io.StringIO(str(result)),
header=None,
names=['row', 'cell', 'type', 'value'])
return df
def read(self, sheet_name):
sheet_id = self.workbook[sheet_name]
sheet_path = f'xl/worksheets/sheet{sheet_id}.xml'
root = etree.parse(self.fh.open(sheet_path))
df = self._parse_sheet(root)
# First row numbers are filled with nan
df['row'] = to_numeric(df['row'].fillna(0))
# Translate string contents
cond = (df.type == 's') & (~df.value.isnull())
df.loc[cond, 'value'] = df[cond]['value'].map(self.shared)
# Add column number and sort rows
df['col'] = df.cell.str.replace(r'[0-9]+', '', regex=True)
# Pivot everything
df = df.pivot(
index='row', columns='col',
values='value').reset_index(drop=True).reset_index(drop=True)
df.columns.name = None # pivot adds a name to the "columns" array
# Sort columns (pivot will put AA before B)
cols = sorted(df.columns, key=lambda x: (len(x), x))
df = df[cols]
df = df.dropna(how='all') # Ignore empty lines
df = df.dropna(how='all', axis=1) # Ignore empty cols
new_header = df.iloc[0] # Grab the first row for the header
df = df[1:] # Take the data less the header row
df.columns = new_header # Set the header row as the df header
return df
def new_method():
xlsx = ExcelParse(
'BigFile.xlsx'
)
print(xlsx.workbook)
df = xlsx.read('Task')
# for sheet_name, sheet_id in xlsx.workbook.items():
# df = xlsx.read(sheet_name)
# do stuff
new_method()
為了加快這個過程,你可以嘗試這些東西並檢查
對於 memory 問題,
我無法理解 10GB 的 RAM 是否已被完全使用,但無論如何至少據我所知,可能很難進行大幅改進。 使用“dtype”選項可能會有所幫助,因為某些數據類型比其他數據類型占用更多 memory,您可以將所有列設為 str 並進行檢查。 read_csv 也有 chunksize 選項。 你可以探索一下。
您還可以探索 read_csv 中的 low_memory 和 memory_map 選項。 我還沒有嘗試過,所以不能真正告訴你有效性。
萬一我弄錯了,如果你在談論存儲 memory,你可以在 read_csv 中使用 storage_options,如果你不這樣做,它將直接從/寫入 S3。
如果您需要更多存儲空間 memory 在本地檢查EFS for Lambdas。
另一方面,您可以制作一個 Fargate 映像並從您的 lambda 調用它。如果這不是約束條件,您可以獲得較長的執行時間。 查看更多。
請注意,如果 lambda 中的 memory 少於 1.7GB,則您只能獲得一小部分 CPU。 這就是為什么事情看起來出奇地慢。 通過將 memory 加倍,您可以將 CPU 加倍,從而將執行時間減半(對於 CPU 密集型任務)。 Double memory 的一半持續時間成本相同(假設它受 CPU 限制)。
如果它是單線程進程,請嘗試將 memory 增加到 1.7GB。 如果它是多線程的,則更多。 (我認為 pandas 在引擎蓋下使用 aiobotocore 進行下載,所以更多可能會有所幫助。)
這有助於解決速度問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.