如何用Python结合Dask快速读取大型XLSB文件?
快速读取大型XLSB文件的可行方案
一、修正Dask的使用方式(真正实现并行)
你的现有代码没有发挥Dask的并行能力——所有文件的读取逻辑被塞进一个delayed函数里,Dask只会单线程执行这个函数,速度自然和直接用pyxlsb没区别。正确的做法是给每个文件(或每个sheet)单独创建delayed任务,让Dask并行处理,最后合并为Dask DataFrame。
示例代码:
import dask.dataframe as dd from dask.delayed import delayed import pyxlsb import pandas as pd def read_single_xlsb(file_path): # 读取单个XLSB文件的所有sheet并合并 data_frames = [] with pyxlsb.open_workbook(file_path) as wb: for sheet_name in wb.sheet_names(): with wb.get_sheet(sheet_name) as sheet: # 将sheet数据转为DataFrame df = pd.DataFrame(sheet.rows(values_only=True)) # 第一行设为列名(有表头时用) df.columns = df.iloc[0] df = df[1:] data_frames.append(df) return pd.concat(data_frames, ignore_index=True) # 替换为你的文件路径列表 file_list = ["file1.xlsb", "file2.xlsb", ...] # 为每个文件创建独立的delayed任务 delayed_dfs = [delayed(read_single_xlsb)(f) for f in file_list] # 转换为Dask DataFrame ddf = dd.from_delayed(delayed_dfs) # 执行计算(或做后续数据操作) result = ddf.compute()
二、用多进程并行读取(轻量高效)
如果觉得Dask配置复杂,可以直接用Python标准库的concurrent.futures实现多进程读取,绕过Dask的额外开销,适合单文件多sheet或多文件场景。
示例代码:
import pyxlsb import pandas as pd from concurrent.futures import ProcessPoolExecutor def read_sheet(file_path, sheet_name): with pyxlsb.open_workbook(file_path) as wb: with wb.get_sheet(sheet_name) as sheet: df = pd.DataFrame(sheet.rows(values_only=True)) df.columns = df.iloc[0] return df[1:] def read_xlsb_parallel(file_path): with pyxlsb.open_workbook(file_path) as wb: sheet_names = wb.sheet_names() # 用进程池并行读取每个sheet with ProcessPoolExecutor() as executor: futures = [executor.submit(read_sheet, file_path, name) for name in sheet_names] dfs = [future.result() for future in futures] return pd.concat(dfs, ignore_index=True) # 读取单个大型XLSB文件 big_df = read_xlsb_parallel("large_file.xlsb")
三、减少读取的数据量(最直接的优化)
如果不需要全量数据,只读取必要的列或行,能大幅提升速度:
- 跳过表头后的无用行(比如从指定行开始读取)
- 只提取目标列(先匹配列索引,再筛选对应单元格)
示例:仅读取指定列
import pyxlsb import pandas as pd def read_selected_columns(file_path, sheet_name, target_cols): # 先获取表头,定位目标列的索引 with pyxlsb.open_workbook(file_path) as wb: with wb.get_sheet(sheet_name) as sheet: header = next(sheet.rows(values_only=True)) col_indices = [i for i, col in enumerate(header) if col in target_cols] # 只读取目标列的数据 data = [] with pyxlsb.open_workbook(file_path) as wb: with wb.get_sheet(sheet_name) as sheet: for row in sheet.rows(values_only=True): filtered_row = [row[i] for i in col_indices] data.append(filtered_row) df = pd.DataFrame(data[1:], columns=target_cols) return df # 读取"Sheet1"中的"ID"和"Value"列 df = read_selected_columns("large_file.xlsb", "Sheet1", ["ID", "Value"])
四、预转换为高效格式(长期优化)
如果需要反复读取该大型XLSB文件,建议一次性转换为Parquet或CSV格式——这类格式的读取速度比XLSB快一个数量级:
# 先用并行方法读取XLSB big_df = read_xlsb_parallel("large_file.xlsb") # 保存为Parquet(压缩率高、读取快) big_df.to_parquet("large_file.parquet") # 后续读取只需一行 import pandas as pd df = pd.read_parquet("large_file.parquet")
内容的提问来源于stack exchange,提问作者Michael An
相关产品推荐
相关产品推荐

