如何用PyArrow提取Parquet数据并避免嵌套循环?读取格式差异解惑
问题描述
需要对大量大体积Parquet文件做数据分析,分析逻辑简单,但用Pandas时需要嵌套循环切片提取数据。以下是Pandas最小可复现示例(MWE):
import pandas as pd import numpy as np col1 = [1,5,8,6,4,5,3,8,5,8,9,6,4,5,6,7,2,89,6,65,5,8,5,8,65,6,4] col2 = ['a','a','a','a','b','b','b','b','c','c','c','c','a','a','a','a','a','a','a','a','b','b','b','c','c','c','c'] col3 = [1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2] df = pd.DataFrame({'col1':col1, 'col2':col2, 'col3':col3}) for i in np.unique(df.col3): slice_1 = df[df.col3==i] for j in np.unique(slice_1.col2): slice_2 = slice_1[slice_1.col2==j] print(slice_2.col1.values[-1])
希望用PyArrow替代,但目前只能用嵌套循环实现类似切片过滤,想知道无需嵌套循环实现上述print功能的方法;另外,用pyarrow.parquet.read_table(data)读取实际Parquet数据时,输出格式为[['a','a','a','a',],['a','a','a','a','a','a','a']],和用pyarrow.Table.from_pandas(df)转换上述MWE数据得到的输出结构不同,想知道原因。
解决方案
1. 无嵌套循环实现分组取最后一个值
PyArrow支持直接对Table进行分组聚合操作,完全不需要嵌套循环。核心思路是按col3和col2分组,然后对col1取最后一个值,代码示例如下:
import pyarrow as pa # 实际场景直接用read_table读取Parquet文件即可,此处为兼容示例先转Table table = pa.Table.from_pandas(df) # 按col3、col2分组,聚合col1的最后一个值 result = table.group_by(['col3', 'col2']).aggregate([('col1', 'last')]) # 遍历结果输出(也可转成Pandas DataFrame查看结构化结果) for row in result.to_pylist(): print(row['col1_last'])
该方法基于PyArrow的列式存储优化,内存占用和处理速度远优于Pandas的嵌套循环切片,尤其适合大文件场景。
2. 读取Parquet与from_pandas输出格式差异的原因
差异本质是实际Parquet文件的Schema与MWE中DataFrame的Schema完全不同:
pa.Table.from_pandas(df)转换得到的Table中,col2是扁平的字符串数组(每个元素为单个字符串);- 你读取的实际Parquet文件中,对应列是嵌套列表类型(ListArray),每个元素本身就是一个字符串列表,因此输出呈现嵌套数组格式。
可通过查看Schema确认:
parquet_table = pa.parquet.read_table("your_data.parquet") print(parquet_table.schema)
若输出中对应列的类型为list<string>,则说明该列是嵌套列表结构,这就是两种输出格式不同的根源。
内容的提问来源于stack exchange,提问作者Sal
相关产品推荐
相关产品推荐

