核心内容
性能优化的第一原则:用向量化操作替代 Python 循环,并善用
eval()/query()加速表达式计算。
一、向量化操作
pandas / NumPy 的底层运算由 C 实现,向量化操作比 Python 循环快数十到数百倍。
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': np.random.rand(1_000_000),
'b': np.random.rand(1_000_000)})
# 推荐:向量化
df['c'] = df['a'] + df['b']
df['d'] = np.where(df['a'] > 0.5, df['b'], 0)
df['e'] = (df['a'] * 2).clip(0, 1)常用向量化手段
| 场景 | 向量化写法 |
|---|---|
| 条件赋值 | np.where(cond, x, y) |
| 聚合 | df.groupby('key')['val'].sum() |
| 窗口 | df['val'].rolling(7).mean() |
| 字符串 | df['name'].str.upper() |
| 日期 | pd.to_datetime(df['date']) |
| 移位 | df['val'].shift(1) |
二、避免循环
应避免的反模式
# 反模式 1:iterrows 逐行访问(最慢)
for idx, row in df.iterrows():
df.loc[idx, 'new'] = row['a'] + row['b']
# 反模式 2:itertuples(略快但仍慢)
for row in df.itertuples():
pass
# 反模式 3:逐 cell 赋值
for i in range(len(df)):
df.iloc[i, 2] = df.iloc[i, 0] * 2推荐的替代方案
# 向量化直接计算
df['new'] = df['a'] + df['b']
# 复杂逻辑 → apply 按行(仍比 iterrows 快)
df['new'] = df.apply(lambda r: custom_func(r['a'], r['b']), axis=1)
# 分组后变换
df['zscore'] = df.groupby('group')['val'].transform(
lambda x: (x - x.mean()) / x.std()
)
# 条件逻辑 → np.select
conditions = [df['a'] > 0.8, df['a'] > 0.5, df['a'] > 0.2]
choices = ['high', 'mid', 'low']
df['level'] = np.select(conditions, choices, default='very_low')何时不得不用循环
- 需要依赖前一行结果的迭代算法(可用 numba 加速)
- 无法向量化的自定义业务逻辑(可用
apply+axis=1)
三、eval() / query()
eval() 使用 numexpr 库对表达式进行并行加速,query() 基于 eval 实现快速过滤。
pd.eval() — 表达式求值
# 普通方式
df['result'] = (df['a'] + df['b']) / (df['c'] - 1)
# eval 加速(适合大规模 DataFrame)
df['result'] = pd.eval("(df['a'] + df['b']) / (df['c'] - 1)")
# 支持局部变量
mean_a = df['a'].mean()
df['result'] = pd.eval("df['a'] - @mean_a") # @ 引用 Python 变量df.eval() — 列间运算
# 直接引用列名
df.eval("result = (a + b) / (c - 1)", inplace=True)
# 条件表达式
df.eval("flag = a > 0.5 and b < 0.3", inplace=True)df.query() — 条件过滤
# 普通过滤
df_filtered = df[(df['a'] > 0.5) & (df['b'] < 0.3)]
# query 写法(更简洁、更快)
df_filtered = df.query("a > 0.5 and b < 0.3")
# 引用外部变量
threshold = 0.8
df_filtered = df.query("a > @threshold")
# 字符串列条件
df.query("name.str.startswith('张')")适用条件
| 条件 | 说明 |
|---|---|
| 数据量大 | > 10 万行时收益明显 |
| 表达式复杂 | 多列参与的算术 / 比较运算 |
| 已安装 numexpr | pip install numexpr |
| 不适用 | 需聚合、含 Python 对象方法(非 str 访问器) |
使用
engine='python'兜底pd.eval("df.a + df.b", engine='python') # 无 numexpr 时
相关笔记
- 21.4 数据类型优化 - 配合 dtype 优化进一步提升速度
- 21.2 加速工具 - numba / bottleneck 深度加速
- 21.3 内存分析与分块读取 - 大数据场景的分块处理