单Row Group的超大Parquet文件随机抽样方法咨询
单Row Group的超大Parquet文件随机抽样方法咨询
嗨,我来帮你搞定这个单row group超大Parquet文件的随机抽样问题~从你贴的元数据来看,这个3000多万行的文件确实只有1个row group,没法用read_row_groups来做行组级的抽样优化,但咱们有几个高效的方案,不用把整个文件都塞进内存:
逐批次读取+分批次抽样(内存友好首选)
这个思路是把大文件拆成小批次加载,每个批次里抽一部分行,最后合并结果,这样每次内存里只存一小段数据,不会爆内存:import pyarrow.parquet as pq import pandas as pd # 设定抽样比例,比如抽1%的数据,也可以用n参数指定固定行数 sample_fraction = 0.01 sampled_data = [] # 按批次迭代读取,batch_size可以根据你的内存情况调整,比如10万行一批 for batch in pq.ParquetFile('Flight_Delay.parquet').iter_batches(batch_size=100000): df_batch = batch.to_pandas() # 对当前批次做随机抽样,random_state保证结果可复现 sampled_batch = df_batch.sample(frac=sample_fraction, random_state=42) sampled_data.append(sampled_batch) # 把所有批次的抽样结果合并成最终数据集 final_sample = pd.concat(sampled_data, ignore_index=True)这个方法的优势是内存占用可控,不管文件多大,只要batch_size调得合理,都能跑起来。
用PyArrow Dataset的内置抽样功能
PyArrow的Dataset API自带抽样参数,写法更简洁,适合快速实现近似抽样:import pyarrow.dataset as ds # 创建Parquet数据集对象 dataset = ds.dataset('Flight_Delay.parquet', format='parquet') # 直接指定抽样比例读取,seed参数保证抽样可复现 sampled_table = dataset.to_table(sample_fraction=0.01, seed=42) # 转成Pandas DataFrame(如果需要用Pandas处理的话) sampled_df = sampled_table.to_pandas()注意:这里的
sample_fraction是近似抽样,底层是按统计概率来选行,如果需要完全精确的随机样本,还是推荐第一个批次抽样的方法。小样本量场景:生成随机行索引过滤
如果你只需要抽很少的行(比如几万行),可以先拿到总行数,生成随机行号,再通过过滤来获取样本:import pyarrow.parquet as pq import numpy as np import pyarrow.dataset as ds import pyarrow.compute as pc # 获取文件总行数 total_rows = pq.ParquetFile('Flight_Delay.parquet').metadata.num_rows # 设定要抽取的行数 sample_size = 10000 # 生成不重复的随机行索引并排序(排序能提升读取效率) random_indices = np.random.choice(total_rows, size=sample_size, replace=False) random_indices.sort() # 用Dataset加行号过滤来获取样本 dataset = ds.dataset('Flight_Delay.parquet', format='parquet') # 给数据集临时添加行号列,然后过滤行号在随机索引中的行 sampled_table = dataset.scanner( columns=None, filter=pc.field("__row_index__").isin(random_indices) ).to_table() sampled_df = sampled_table.to_pandas()这个方法适合抽样量极小的场景,因为如果样本量太大,过滤的效率会下降。
另外补充一句:如果你的机器内存足够大(比如能装下3000多万行的全量数据),直接读整个文件再sample当然是最简单的,比如:
import pandas as pd df = pd.read_parquet('Flight_Delay.parquet') final_sample = df.sample(frac=0.01, random_state=42)
但显然这种方法对内存要求很高,所以还是前两种方法更实用。
备注:内容来源于stack exchange,提问作者CHADHA ESSID




