【模型数据处理】Python 中处理内存不足数据的实用指南
【精选优质专栏推荐】
- 《AI 技术前沿》 —— 紧跟 AI 最新趋势与应用
- 《网络安全新手快速入门(附漏洞挖掘案例)》 —— 零基础安全入门必看
- 《BurpSuite 入门教程(附实战图文)》 —— 渗透测试必备工具详解
- 《网安渗透工具使用教程(全)》 —— 一站式工具手册
- 《CTF 新手入门实战教程》 —— 从题目讲解到实战技巧
- 《前后端项目开发(新手必知必会)》 —— 实战驱动快速上手
每个专栏均配有案例与图文讲解,循序渐进,适合新手与进阶学习者,欢迎订阅。
文章目录

引言
如今,在处理大规模数据分析项目、管理高速生成的流数据,或构建大型机器学习模型时,遇到无法完全加载到内存(RAM)中的数据集已经十分常见。例如,尝试将一个 100 GB 的 CSV 文件加载到 Pandas DataFrame 中时,就会面临显著的内存压力。在这些情况下,内存限制可能中断整个数据处理流程,有时甚至带来高昂的代价。这个问题被称为“内存不足”(Out-of-Memory,简称 OOM),它直接影响系统的可扩展性、效率以及成本。
本文将概述几种在 Python 项目中应对 OOM 问题的实用技术和策略,并提供各种工具的“尝鲜体验”,帮助数据科学家和开发者在数据无法完全加载到内存时,仍能流畅地处理数据——包括分块处理数据、用磁盘替代 RAM,或者在多台机器上进行分布式计算。
应对 OOM 数据的策略尝鲜
本文将以一个 10 万条客户数据(100K customers dataset)为示例来演示处理 OOM 问题的策略。尽管该数据集并非真正意义上的海量数据,但其规模(10 万条记录)足以清晰展示所涉及的技术和方法。
数据分块(Data Chunking)
第一种策略可以在数据读取和加载的过程中“即时”应用,即将数据划分为多个块进行处理。在 Pandas 中,可以通过 read_csv() 函数的 chunksize 参数实现,指定每个数据块包含的记录数。
import pandas as pd
url = "https://raw.githubusercontent.com/gakudo-ai/open-datasets/refs/heads/main/customers-100000.csv"
reader = pd.read_csv(url, chunksize=30000)
for i, chunk in enumerate(reader):
print(f"Chunk {i}: {chunk.shape}")
分块处理是防止 CSV 文件形式且结构简单的数据集出现 OOM 问题的有效方法。然而,当数据格式较为复杂,例如实例之间存在依赖关系或嵌套的 JSON 结构时,这种方法就不太适用。
使用 Dask 进行并行 DataFrame 与惰性计算
如果希望几乎无缝地扩展类似 Pandas 的数据处理流程,Dask 是一个非常不错的选择:该库利用并行与惰性计算处理大规模数据集,同时其逻辑在很大程度上与独立的 Pandas 保持一致。
下面示例展示了如何使用 requests 先将 CSV 文件下载到本地,再用 Dask 读取,避免可能的服务器传输问题(例如编码错误):
import dask.dataframe as dd
import requests
url = "https://raw.githubusercontent.com/gakudo-ai/open-datasets/refs/heads/main/customers-100000.csv"
local_filename = "customers-100000.csv"
# 将 CSV 文件下载到本地后再读取到 Dask DataFrame
response = requests.get(url)
response.raise_for_status() # 状态码异常时抛出异常
with open(local_filename, 'wb') as f:
f.write(response.content)
df = dd.read_csv(local_filename)
df[df["Country"] == "Spain"].head()
在使用 Dask 时,务必通过 Dask 直接读取文件,而不要使用 pd.read_csv()。否则,所有数据将一次性加载到内存中,这正是我们想要避免的。
使用 Polars 高效管理大数据
Polars 是另一个可用于大数据处理的库,其核心用 Rust 编写,可在内存有限的情况下高效管理数据。相较于分块处理,Polars 更加自动化和灵活,非常适合单机场景,但不具备 Dask 的分布式计算能力。
下面示例展示如何加载大数据集并进行惰性查询(Lazy Query),注意使用 collect() 方法触发执行并获得最终结果:
import polars as pl
url = "https://raw.githubusercontent.com/gakudo-ai/open-datasets/refs/heads/main/customers-100000.csv"
df = pl.read_csv(url)
lazy_result = df.lazy().filter(pl.col("Country") == "France").select("First Name", "Email").collect()
print(lazy_result)
使用 Pandas 与 SQLite 执行 SQL 查询
如果需要反复从超大数据集文件中查询子集而不想重复加载数据,且熟悉 SQL 语法,这是一种优化内存使用的有效策略。该方法适合探索性过滤和选择性数据加载,但若需执行复杂的数据处理计算,Dask 会更高效。
下面示例展示如何结合 sqlite3 与 Pandas 分块处理,将数据增量加载到 SQL 数据库中,并查询西班牙客户,而无需一次性加载整个数据集:
import pandas as pd
import sqlite3
url = "https://raw.githubusercontent.com/gakudo-ai/open-datasets/refs/heads/main/customers-100000.csv"
# 创建内存中的 SQLite 数据库连接
conn = sqlite3.connect(":memory:")
# 将 CSV 分块读取并依次追加到 SQL 表
reader = pd.read_csv(url, chunksize=10000)
for i, chunk in enumerate(reader):
# 第一个块创建表,后续块追加
if_exists_strategy = 'replace' if i == 0 else 'append'
chunk.to_sql("customers", conn, if_exists=if_exists_strategy, index=False)
# 查询数据库而无需一次性加载整个文件
df = pd.read_sql_query("SELECT * FROM customers WHERE Country = 'Spain'", conn)
print(df.head())
conn.close()
需要注意的是,对于非常大的数据集,基于 SQLite 的方法在执行深度分析时可能比 Dask 或 Polars 稍慢。
总结
本文介绍了四种不同策略和技术,用于在内存受限情况下处理超大数据集时,避免出现著名的内存不足(OOM)问题。选择具体策略取决于对各方法的熟悉程度以及具体需求。
下表简要概览了各方法的特点:
| 方法 | 描述 |
|---|---|
| Pandas 分块 | 适合将大型 CSV 文件分块读取,内存控制灵活,设置简单,但需要手动处理聚合和合并逻辑。 |
| Dask DataFrame | 通过惰性计算和并行处理,将基于 DataFrame 的工作流程扩展到超内存数据。适合在管道中执行全数据集级别操作。 |
| Polars(惰性模式) | 内存高效、速度快,自动优化查询,适合单机大表数据处理,但不具备 Dask 的分布式能力。 |
| SQLite(结合 Pandas) | 适合在磁盘上查询大数据集文件而不加载到内存,适用于反复筛选或结构化访问,但执行速度可能较慢。 |
更多推荐


所有评论(0)