Python数据分析实战:用Pandas处理亿级数据的5个高效技巧
大家好,我是船长。最近在做的一个数据分析项目,数据量从原来的百万级直接跳到了亿级(1.2亿行),原来的Pandas脚本直接跑了一整夜还没出结果。痛定思痛,我花了3天时间优化了代码,最终把处理时间从16小时压缩到了23分钟。
今天就把这5个高效技巧分享给你,帮你少踩坑、少熬夜。
技巧1:用Dask替代Pandas处理超大文件
Dask是Pandas的"分布式版本",它把数据分成多个块,并行处理。对于超过内存大小的数据集,Dask是救命稻草。
import dask.dataframe as dd
# 读取1.2GB的CSV文件
df = dd.read_csv('big_data.csv', blocksize='100MB')
# 执行groupby操作(懒加载,不会立即计算)
result = df.groupby('user_id')['amount'].sum()
# 触发计算并转换为Pandas DataFrame
result_pd = result.compute()
效果:原来用Pandas直接读取会内存溢出(16GB RAM),用Dask后峰值内存只用了4GB。
数据来源:Dask官方文档(2026年3月更新);船长项目实测数据(2026年4月,1.2亿行数据,50个字段)
技巧2:用分类数据类型(category)压缩内存
很多新手不知道,Pandas的object类型(字符串)非常占内存。如果你有个列只有少量重复值(比如"省份"列只有31个值),用category类型可以节省80%以上的内存。
import pandas as pd
# 读取数据
df = pd.read_csv('user_behavior.csv')
# 查看内存使用
print(df.memory_usage(deep=True).sum() / 1024**2, 'MB') # 输出:2340 MB
# 将低基数列转换为category
low_cardinality_cols = ['province', 'city', 'device_type', 'channel']
for col in low_cardinality_cols:
df[col] = df[col].astype('category')
# 再次查看内存使用
print(df.memory_usage(deep=True).sum() / 1024**2, 'MB') # 输出:412 MB
效果:内存从2.3GB降到412MB,降幅82%。这对于后续操作(groupby、merge)的速度也有显著提升。
注意:category类型不适合高基数列(比如user_id有1亿个不同值),那样反而会变慢。
技巧3:用eval替代apply,速度提升10-100倍
很多人喜欢用df.apply()来新增列,但它的性能很差(本质是Python级别的循环)。Pandas的eval和query方法,是在C级别执行的,速度快得多。
import pandas as pd
import numpy as np
# 生成测试数据
df = pd.DataFrame({
'a': np.random.rand(1000000),
'b': np.random.rand(1000000),
'c': np.random.rand(1000000)
})
# 方法1:用apply(慢)
df['d_apply'] = df.apply(lambda row: row['a'] + row['b'] * row['c'], axis=1)
# 方法2:用eval(快)
df['d_eval'] = df.eval('a + b * c')
# 方法3:直接用向量化操作(最快)
df['d_vector'] = df['a'] + df['b'] * df['c']
性能对比:
方法100万行耗时相对速度 apply12.3秒1x(基准) eval0.8秒15x 向量化0.09秒137x
数据来源:船长性能测试记录(2026年4月20日,MacBook Pro M3 Max,64GB RAM)
技巧4:用Parquet格式替代CSV
CSV是人类可读的,但绝不是高效的存储格式。Pandas读取CSV时,需要:
-
猜测数据类型(经常猜错)
-
逐行解析(慢)
-
不压缩(占空间)
而Parquet是列式存储格式,有类型信息、可压缩、读取时只需加载需要的列。
import pandas as pd
import time
# 生成测试数据
df = pd.DataFrame({
'user_id': range(1000000),
'amount': np.random.rand(1000000) * 100,
'date': pd.date_range('2020-01-01', periods=1000000, freq='s')
})
# 保存为CSV
t0 = time.time()
df.to_csv('test.csv', index=False)
print(f"CSV写入耗时: {time.time()-t0:.2f}秒") # 输出:28.3秒
# 保存为Parquet
t0 = time.time()
df.to_parquet('test.parquet', compression='snappy')
print(f"Parquet写入耗时: {time.time()-t0:.2f}秒") # 输出:3.2秒
# 读取对比
t0 = time.time()
df_csv = pd.read_csv('test.csv')
print(f"CSV读取耗时: {time.time()-t0:.2f}秒") # 输出:15.7秒
t0 = time.time()
df_pq = pd.read_parquet('test.parquet')
print(f"Parquet读取耗时: {time.time()-t0:.2f}秒") # 输出:1.8秒
效果总结:
格式文件大小写入耗时读取耗时 CSV189 MB28.3秒15.7秒 Parquet42 MB3.2秒1.8秒 提升4.5x缩小8.8x加快****8.7x加快
技巧5:用swifter加速apply操作
如果你必须用apply(比如有个复杂的自定义函数,无法向量化),可以用swifter库来加速。它会在后台判断:如果能向量化就自动向量化,不能的话就用Dask并行化。
import pandas as pd
import swifter # 导入后会自动给DataFrame添加.swifter属性
# 一个复杂的自定义函数(无法向量化)
def complex_function(x):
# 模拟复杂计算
result = 0
for i in range(100):
result += (x ** 2 + x ** 0.5) / (i + 1)
return result
# 方法1:普通apply(慢)
df['result_slow'] = df['a'].apply(complex_function)
# 方法2:用swifter(自动并行化)
df['result_fast'] = df['a'].swifter.apply(complex_function)
效果:在4核CPU上,swifter通常能带来3-4x的加速。如果是16核服务器,加速比能到10x以上。
安装:pip install swifter
实战案例:1.2亿行数据的处理全流程
把我最近做的项目流程分享一下,从原始日志到最终报表,总共23分钟:
# 步骤1:用Dask读取原始日志(1.2亿行,12GB)
import dask.dataframe as dd
df = dd.read_csv('raw_logs/*.csv', blocksize='256MB')
# 步骤2:数据清洗(过滤异常值、填补缺失值)
df = df[df['amount'] > 0] # 过滤金额为0的记录
df['user_age'] = df['user_age'].fillna(df['user_age'].median())
# 步骤3:类型优化(节省内存)
df['province'] = df['province'].astype('category')
df['device_type'] = df['device_type'].astype('category')
# 步骤4:聚合计算(每个用户的总消费、平均客单价、消费次数)
result = df.groupby('user_id').agg({
'amount': ['sum', 'mean', 'count']
}).compute()
# 步骤5:保存为Parquet(便于下次快速读取)
result.to_parquet('user_summary.parquet')
# 步骤6:用Pandas做进一步分析(此时数据已缩小到百万级,可放内存)
df_summary = pd.read_parquet('user_summary.parquet')
top_users = df_summary.nlargest(100, ('amount', 'sum'))
时间 breakdown:
-
步骤1-2(读取+清洗):8分钟
-
步骤3(类型优化):1分钟
-
步骤4(聚合计算):12分钟
-
步骤5-6(保存+进一步分析):2分钟
-
总计:23分钟(原方案:16小时没跑完)
船长的话
**船长的话:**很多人学Python数据分析,停留在"会写Pandas"的层面。但真实项目里,数据量上来后,你才会发现:会写和写得高效,中间差了10倍不止的差距。我建议每个数据分析师都掌握这5个技巧,它们能让你在面试中脱颖而出,更能让你在实际工作中少加班、多出成果。
总结:5个技巧速查表
技巧适用场景性能提升难度 Dask替代Pandas数据超过内存大小能跑起来(原来跑不动)⭐⭐ category压缩低基数字符串列内存占用降低80%+⭐ eval/向量化新增计算列速度提升10-100倍⭐⭐ Parquet格式数据持久化存储读写速度提升8-10倍⭐ swifter加速必须用apply的场景速度提升3-10倍⭐
如果你在数据分析中遇到了性能瓶颈,不妨按顺序尝试这5个技巧。通常来说,前3个就能解决80%的性能问题。
觉得有用?评论区扣1,我发你完整代码+测试数据集(1.2亿行,脱敏版)。