当前位置:首页>python>一起学Python第100天:百日里程碑, Pandas性能优化

一起学Python第100天:百日里程碑, Pandas性能优化

  • 2026-10-11 05:53:00
一起学Python第100天:百日里程碑, Pandas性能优化
🎉 热烈庆祝!今天是我们共同学习的第100天!

我们从数据结构(Series/DataFrame)起步,跨越了I/O读写、清洗、分析、绘图的重重关卡。今天,作为这一阶段的收官之作,我们将攻克数据分析的“最后一块高地”——性能优化!

当数据量从“几千行”膨胀到“几百万行”,或者内存从“够用”变成“爆满”时,优秀的性能优化技巧能让你的代码从“龟速爬行”变成“猎豹冲刺”。

DataFrame的“瘦身”计划:数据类型优化

在 Pandas 中,数据类型(dtype)直接决定了内存占用和计算速度。默认情况下,Pandas 往往会分配比实际需要更大的空间(例如用 64位 整数存储很小的数字)。

🔹 核心原理

  • int64 vs int32:将整数类型降级,内存可减半。
  • object vs category:将重复率高的字符串转换为类别类型,内存可压缩 90% 以上!

🛠️ 实战演示

import pandas as pdimport gc# 1. 构造一个“臃肿”的大数据框(模拟 100万 行数据)data = {    'A': [1, 2, 3, 4, 5] * 200000,  # 大量小整数    'B': [10.5, 20.5, 30.5, 40.5, 50.5] * 200000, # 大量浮点数    'C': ['Category1', 'Category2', 'Category3'] * 333334  # 大量重复字符串}df = pd.DataFrame(data)print("🔹 原始数据占用内存:")print(df.memory_usage(deep=True) / 1024**2, "MB")# deep=True 关键:包含字符串等对象占用的真实内存

优化方案

# 2. 数据类型转换(瘦身开始!)# 整数列:int64 -> int32df['A'] = df['A'].astype('int32')# 浮点列:float64 -> float32df['B'] = df['B'].astype('float32')# 字符串列:object -> categorydf['C'] = df['C'].astype('category')print("\n🔹 优化后数据占用内存:")print(df.memory_usage(deep=True) / 1024**2, "MB")
💡 效果:对于包含大量重复字符串的列,category 类型通常能节省 50%-90% 的内存!

内存管理:及时“断舍离”

# 1. 删除不再需要的列del df['C']  # 假设列 C 处理完了,不再需要# 2. 强制垃圾回收(清理碎片)gc.collect()print("\n 删除列并回收垃圾后的内存:")print(df.memory_usage(deep=True) / 1024**2, "MB")

驾驭大数据:分块与并行

当数据量大到连 Pandas 都读不进来(MemoryError)时,我们需要改变策略。

🔹 策略一:分块读取(Chunking)

就像吃大饼,一口一口吃。利用 chunksize 参数,Pandas 会返回一个迭代器。
# 假设存在一个超大的 CSV 文件# pd.read_csv 加上 chunksize 参数后,不会一次性读入内存,而是返回一个迭代器chunk_size = 100000  # 每次读取 10万 行chunk_results = []print("🔄 开始分块读取处理...")for chunk in pd.read_csv('large_data.csv', chunksize=chunk_size):    # 在内存中处理每一块    # 例如:只保留大于 100 的行    processed_chunk = chunk[chunk['value'] > 100]    # 将处理后的块存入列表(或其他文件)    chunk_results.append(processed_chunk)# 最后合并结果final_df = pd.concat(chunk_results)

🔹 策略二:Dask(并行计算利器)

Dask 是一个灵活的并行计算库,API 与 Pandas 高度相似,但支持多核和集群计算。
import dask.dataframe as dd# Dask 的读取方式与 Pandas 几乎一样,但它默认是“延迟计算”的ddf = dd.read_csv('large_data.csv')# 进行计算(例如求均值)# 注意:Dask 需要调用 .compute() 才会真正执行并返回结果mean_value = ddf['value'].mean().compute()print(f"计算结果: {mean_value}")

💻 综合实战:全流程优化流水线

将内存优化、垃圾回收和分块处理结合在一起。
import pandas as pdimport numpy as npimport gcprint("🏁 开始性能优化综合实战...")# 1. 创建测试数据df = pd.DataFrame({    'ID': np.arange(1000000),    'Score': np.random.randint(50, 100, 1000000),    'Group': np.random.choice(['A', 'B', 'C'], 1000000)})# 2. 内存优化前original_mem = df.memory_usage(deep=True).sum() / 1024**2print(f"🔹 优化前内存: {original_mem:.2f} MB")# 3. 优化数据类型df['Score'] = df['Score'].astype('int8')  # 50-100 的范围,int8 绰绰有余df['Group'] = df['Group'].astype('category')# 4. 内存优化后optimized_mem = df.memory_usage(deep=True).sum() / 1024**2print(f"🔹 优化后内存: {optimized_mem:.2f} MB")print(f"📉 节省内存: {((original_mem - optimized_mem) / original_mem * 100):.1f}%")# 5. 清理中间变量del dfgc.collect()print("🧹 垃圾回收完成,内存已释放!")
🖥️ 预期输出:控制台将展示优化前后的内存对比,对于特定数值范围(如 50-100),使用 int8 能带来极致的压缩效果。

性能优化避坑

痛点

解决方案

内存计算不准

务必使用 df.memory_usage(deep=True),否则无法统计 object 类型的真实占用

类型转换报错

降级类型前检查数据范围(如 df.max()),防止溢出(如负数溢出)

分块处理逻辑混乱

确保每一块的处理逻辑是独立的,最后再 concat 或 append 到文件

Dask 不执行

忘记加 .compute() 会导致程序什么都没干就结束了(Dask 是延迟执行的)

【一起学Python】每天进步一点点,365天后遇见更优秀的自己!

👉 关注公众号,不错过每天的进阶内容!

🎯 百日金句:“性能优化是代码的雕琢,也是思维的升华;在数据的浩瀚中,高效与优雅并行。” ✨

最新文章

随机文章