Python加载大型.xlsx文件及可视化内存问题咨询
大体积XLSX文件Jupyter环境低内存加载+可视化方案
加载阶段优化(解决pandas读入慢、内存报错问题)
- 前置裁剪+类型降级:读取前先用openpyxl只读模式读取表头,提前剔除完全用不到的列;针对字段类型提前做降级配置:ID类整数字段用
int32替代默认int64,浮点数值字段用float32替代默认float64,枚举类/类别型字段直接指定为category类型,整体内存占用可降低50%-70%。 - 分块读取替代一次性加载:调用pandas的
read_excel时开启chunksize参数(建议设为10000-50000,根据内存大小调整),逐块读入后再拼接,避免一次性把全量文件塞进内存。参考代码:
from openpyxl import load_workbook import pandas as pd # 只读模式拉取表头,不加载全量数据 wb = load_workbook("你的目标文件.xlsx", read_only=True, data_only=True) ws = wb.active headers = [cell.value for cell in next(ws.iter_rows(min_row=1, max_row=1))] # 筛选需要保留的列索引 keep_cols = [headers.index(col) for col in ["待保留列1", "待保留列2", "待保留列3"]] # 配置低占用字段类型 dtype_config = { "类别字段": "category", "ID字段": "int32", "数值字段": "float32" } chunk_cache = [] # 逐块读取 for chunk in pd.read_excel( "你的目标文件.xlsx", usecols=keep_cols, dtype=dtype_config, engine="openpyxl", chunksize=20000 ): chunk_cache.append(chunk) df = pd.concat(chunk_cache, ignore_index=True)
- 单次读取后转存列式存储:第一次成功读入数据后,直接把数据存为Parquet格式到本地,后续读取Parquet的速度是读取XLSX的10-20倍,内存占用更低,代码为
df.to_parquet("预处理完成数据.parquet"),后续直接用pd.read_parquet("预处理完成数据.parquet")调用即可。 - 超大型文件(单文件>1G)直接换Polars引擎:Polars读取Excel的性能是pandas的3-5倍,原生支持懒加载,内存占用仅为pandas的1/3-1/2,参考读入代码:
import polars as pl # 懒加载模式,不会立刻加载全量数据到内存 lazy_df = pl.scan_excel("你的目标文件.xlsx") # 提前做列裁剪、行过滤,计算完成后再加载到内存 pl_df = lazy_df.select(pl.col(["待保留列1", "待保留列2"])).filter(pl.col("数值字段") > 0).collect() # 转pandas对象即可直接对接后续流程 df = pl_df.to_pandas()
Dask场景下的可视化适配(解决绘图触发全量加载问题)
matplotlib、seaborn本身不识别Dask的延迟计算对象,直接传入Dask DataFrame会自动触发全量计算加载到内存,完全失去低内存优势,按绘图类型对应处理即可:
- 聚合类图表(分组柱状图、趋势折线图、占比饼图等):先用Dask的延迟计算能力完成分组、聚合、统计逻辑,得到的聚合结果通常只有几十到几百行,再调用
.compute()拉取到内存传给绘图库即可,全程不会加载全量原始数据。参考代码:
import dask.dataframe as dd import seaborn as sns import matplotlib.pyplot as plt ddf = dd.read_parquet("预处理完成数据.parquet") # Dask层完成聚合计算,结果体积极小 agg_res = ddf.groupby("类别字段")["数值字段"].mean().compute() # 用聚合结果绘图 sns.barplot(x=agg_res.index, y=agg_res.values) plt.show()
- 分布类图表(散点图、直方图、核密度图、箱线图等):不需要用全量数据绘制,对Dask DataFrame做分层采样即可,采样比例控制在5%-10%(根据总数据量调整,只要采样均匀,视觉上和全量绘制无差异),采样完成后再
.compute()拉取到内存绘图。参考代码:
# 按核心分类字段做分层采样,保证样本分布和全量一致 sample_df = ddf.groupby("类别字段").sample(frac=0.05, random_state=42).compute() # 用采样数据绘图 sns.scatterplot(data=sample_df, x="数值字段1", y="数值字段2", hue="类别字段") plt.show()
注意:Jupyter环境下不要直接输出全量DataFrame做预览,只用
df.head(N)查看前N行即可,全量输出会把所有数据渲染为HTML表格,额外占用数倍内存。
内容的提问来源于stack exchange,提问作者Pratap Chandra Das
相关产品推荐
相关产品推荐

