文章目录
- 一、什么是分块计算?
- 二、Python实现分块读取
- 三、一个简单示例
- 四、分块计算的工程模式
- [1 分块统计](#1 分块统计)
- [2 分块过滤](#2 分块过滤)
- [3 分块计算 + 实时写盘](#3 分块计算 + 实时写盘)
- 五、真实工程案例:雷达数据处理
- 六、分块计算的性能优化
-
- [1 只读取必要列](#1 只读取必要列)
- [2 使用 float32](#2 使用 float32)
- [3 及时释放内存](#3 及时释放内存)
- [4 使用 Parquet 代替 CSV](#4 使用 Parquet 代替 CSV)
- 七、什么时候必须使用分块计算?
- 八、分块计算的本质
- 九、总结
在数据分析和工程计算中,我们经常会遇到一个问题:
数据量太大,一次性读入内存会直接崩溃。
例如:
- 雷达扫描数据
- 风电测风塔高频数据
- 日志数据
- 传感器数据
很多时候,一个 CSV 文件就可能达到:
- 几 GB
- 上千万行
- 甚至上亿行
如果直接使用:
python
df = pd.read_csv("data.csv")
很可能会遇到:
MemoryError
或者程序运行到一半直接被系统杀死。
解决这个问题最有效的方法就是:
分块计算(Chunk Processing)
本文将深入浅出介绍 Python 分块计算的原理、实现方法以及工程实践。
一、什么是分块计算?
分块计算(Chunk Processing)是一种常见的大数据处理技术,其核心思想是:
不要一次性读取全部数据,而是分批读取、逐块处理。
假设有一个 1000 万行的 CSV 文件。
普通处理方式:
一次读取
┌─────────────────────────┐
│ 1000万行数据 │
└─────────────────────────┘
内存压力非常大。
而分块计算是:
分块读取
┌────────────┐
│ 10万行 │ → 处理 → 输出
└────────────┘
┌────────────┐
│ 10万行 │ → 处理 → 输出
└────────────┘
┌────────────┐
│ 10万行 │ → 处理 → 输出
└────────────┘
任何时候内存中只有一小块数据。
因此可以处理远大于内存容量的数据。
二、Python实现分块读取
Pandas 提供了一个非常方便的参数:
chunksize
示例:
python
import pandas as pd
reader = pd.read_csv("big_data.csv", chunksize=100000)
for chunk in reader:
print(len(chunk))
这里:
chunksize = 100000
表示:
每次只读取 10万行。
返回的 reader 实际上是一个 迭代器。
程序执行过程:
第1次读取 10万行
第2次读取 10万行
第3次读取 10万行
...
三、一个简单示例
假设我们有一个很大的 CSV 文件:
data.csv
内容:
timestamp,wind_speed
2024-01-01 00:00,5.3
2024-01-01 00:01,6.1
...
目标:计算平均风速。
如果直接读取:
python
df = pd.read_csv("data.csv")
print(df["wind_speed"].mean())
数据太大可能会崩溃。
分块计算方法:
python
import pandas as pd
reader = pd.read_csv("data.csv", chunksize=100000)
total_sum = 0
total_count = 0
for chunk in reader:
total_sum += chunk["wind_speed"].sum()
total_count += len(chunk)
mean_ws = total_sum / total_count
print("平均风速:", mean_ws)
核心思想:
sum += chunk.sum()
count += chunk.count()
最后再计算整体结果。
这样即使数据有 1亿行,也可以轻松处理。
四、分块计算的工程模式
在工程实践中,分块计算通常有三种模式。
1 分块统计
适用于:
- 平均值
- 最大值
- 最小值
- 计数
- 分组统计
示例:
python
total_sum += chunk.sum()
total_cnt += chunk.count()
最后计算:
mean = sum / count
2 分块过滤
适用于:
- 条件筛选
- 数据清洗
例如:
python
for chunk in pd.read_csv("data.csv", chunksize=100000):
chunk = chunk[chunk["wind_speed"] > 10]
chunk.to_csv("result.csv", mode="a", index=False)
这里使用:
mode="a"
表示:
追加写入文件。
因此不会占用大量内存。
3 分块计算 + 实时写盘
这是工程中最常见的模式。
流程:
读取一块数据
↓
数据处理
↓
写入结果文件
↓
释放内存
示例:
python
for chunk in pd.read_csv("data.csv", chunksize=100000):
result = process(chunk)
result.to_csv(
"output.csv",
mode="a",
header=False,
index=False
)
这样:
- 内存始终很小
- 处理速度也很快
五、真实工程案例:雷达数据处理
在风资源分析中,我们经常需要处理:
- 扫描雷达数据
- 高频测风塔数据
例如:
Timestamp
Azimuth
Elevation
Distance
WindSpeed
假设数据量:
100GB
如果直接读取:
df = pd.read_csv()
基本必然崩溃。
正确方式是:
python
for chunk in pd.read_csv(file, chunksize=200000):
# 距离过滤
chunk = chunk[
(chunk["Distance"] >= 250) &
(chunk["Distance"] <= 400)
]
# 计算坐标
chunk["x"] = ...
chunk["y"] = ...
chunk["z"] = ...
# 写入结果
chunk.to_csv("result.csv", mode="a")
优势:
- 内存稳定
- 可以处理 TB 级数据
- 程序稳定性高
六、分块计算的性能优化
在实际工程中,还可以进一步优化。
1 只读取必要列
CSV 文件往往有很多列。
使用:
python
pd.read_csv(
file,
usecols=["Timestamp", "Distance", "WindSpeed"],
chunksize=100000
)
可以大幅降低内存。
2 使用 float32
默认:
float64
占用:
8 bytes
可以改为:
float32
占用:
4 bytes
示例:
python
chunk["wind_speed"] = chunk["wind_speed"].astype("float32")
3 及时释放内存
处理完一个块后:
python
del chunk
import gc
gc.collect()
可以避免内存逐渐增长。
4 使用 Parquet 代替 CSV
CSV:
- 体积大
- 读取慢
Parquet:
- 更快
- 更省空间
- 支持列存储
示例:
python
chunk.to_parquet("data.parquet")
七、什么时候必须使用分块计算?
当出现以下情况时,强烈建议使用分块计算:
数据规模:
> 1GB
> 1000万行
或者:
- 服务器内存较小
- CSV 文件过大
- 程序出现 MemoryError
分块计算几乎是唯一稳定方案。
八、分块计算的本质
分块计算的本质其实就是:
流式计算(Streaming Processing)
核心思想:
数据流入 → 处理 → 输出
而不是:
全部加载 → 再处理
这也是:
- Spark
- Flink
- Hadoop
等大数据系统的核心思想。
九、总结
Python 分块计算是处理大规模数据最实用的技术之一。
核心原则只有三条:
1 不一次性读取全部数据
chunksize
2 分块处理
for chunk in reader
3 实时写出结果
mode="a"
通过分块计算,我们可以:
- 处理 TB 级数据
- 避免内存溢出
- 提升程序稳定性
在工程实践中,这是一个非常重要的数据处理技巧。